]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Aug 2012 01:43:13 +0000 (18:43 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Aug 2012 01:43:13 +0000 (18:43 -0700)
Pull networking update from David S. Miller:
 "I think Eric Dumazet and I have dealt with all of the known routing
  cache removal fallout.  Some other minor fixes all around.

  1) Fix RCU of cached routes, particular of output routes which require
     liberation via call_rcu() instead of call_rcu_bh().  From Eric
     Dumazet.

  2) Make sure we purge net device references in cached routes properly.

  3) TG3 driver bug fixes from Michael Chan.

  4) Fix reported 'expires' value in ipv6 routes, from Li Wei.

  5) TUN driver ioctl leaks kernel bytes to userspace, from Mathias
     Krause."

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (22 commits)
  ipv4: Properly purge netdev references on uncached routes.
  ipv4: Cache routes in nexthop exception entries.
  ipv4: percpu nh_rth_output cache
  ipv4: Restore old dst_free() behavior.
  bridge: make port attributes const
  ipv4: remove rt_cache_rebuild_count
  net: ipv4: fix RCU races on dst refcounts
  net: TCP early demux cleanup
  tun: Fix formatting.
  net/tun: fix ioctl() based info leaks
  tg3: Update version to 3.124
  tg3: Fix race condition in tg3_get_stats64()
  tg3: Add New 5719 Read DMA workaround
  tg3: Fix Read DMA workaround for 5719 A0.
  tg3: Request APE_LOCK_PHY before PHY access
  ipv6: fix incorrect route 'expires' value passed to userspace
  mISDN: Bugfix only few bytes are transfered on a connection
  seeq: use PTR_RET at init_module of driver
  bnx2x: remove cast around the kmalloc in bnx2x_prev_mark_path
  ipv4: clean up put_child
  ...

1149 files changed:
Documentation/ABI/stable/sysfs-bus-firewire
Documentation/ABI/testing/sysfs-bus-rbd
Documentation/ABI/testing/sysfs-devices-edac [new file with mode: 0644]
Documentation/ABI/testing/sysfs-platform-asus-wmi
Documentation/DMA-attributes.txt
Documentation/DocBook/media/v4l/biblio.xml
Documentation/DocBook/media/v4l/common.xml
Documentation/DocBook/media/v4l/compat.xml
Documentation/DocBook/media/v4l/dev-subdev.xml
Documentation/DocBook/media/v4l/io.xml
Documentation/DocBook/media/v4l/selection-api.xml
Documentation/DocBook/media/v4l/selections-common.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/v4l2.xml
Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
Documentation/DocBook/media/v4l/vidioc-g-selection.xml
Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
Documentation/DocBook/media/v4l/vidioc-qbuf.xml
Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
Documentation/device-mapper/striped.txt
Documentation/device-mapper/thin-provisioning.txt
Documentation/devicetree/bindings/arm/calxeda/l2ecc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt [new file with mode: 0644]
Documentation/devicetree/bindings/ata/cavium-compact-flash.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/cavium-i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/gpio-i2c.txt [moved from Documentation/devicetree/bindings/gpio/gpio_i2c.txt with 100% similarity]
Documentation/devicetree/bindings/i2c/i2c-mxs.txt
Documentation/devicetree/bindings/i2c/i2c-ocores.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
Documentation/devicetree/bindings/mfd/ab8500.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/max77686.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/tps65910.txt
Documentation/devicetree/bindings/mfd/twl6040.txt
Documentation/devicetree/bindings/mips/cavium/bootbus.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mips/cavium/ciu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mips/cavium/ciu2.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mips/cavium/dma-engine.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mips/cavium/uctl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/cavium-mdio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/cavium-mix.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/cavium-pip.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/mxs-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/serial/cavium-uart.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt [new file with mode: 0644]
Documentation/dontdiff
Documentation/dvb/get_dvb_firmware
Documentation/edac.txt
Documentation/fault-injection/fault-injection.txt
Documentation/fault-injection/notifier-error-inject.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/input/edt-ft5x06.txt [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/power/power_supply_class.txt
Documentation/printk-formats.txt
Documentation/pwm.txt [new file with mode: 0644]
Documentation/sysctl/fs.txt
Documentation/video4linux/v4l2-framework.txt
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/Kconfig
arch/alpha/include/asm/unistd.h
arch/alpha/kernel/smc37c669.c
arch/arm/Kconfig
arch/arm/boot/dts/highbank.dts
arch/arm/boot/dts/imx28.dtsi
arch/arm/boot/dts/r8a7740.dtsi [new file with mode: 0644]
arch/arm/boot/dts/sh7377.dtsi [new file with mode: 0644]
arch/arm/boot/dts/tegra20.dtsi
arch/arm/boot/dts/tegra30.dtsi
arch/arm/common/dmabounce.c
arch/arm/configs/armadillo800eva_defconfig
arch/arm/configs/kzm9d_defconfig [new file with mode: 0644]
arch/arm/configs/kzm9g_defconfig
arch/arm/configs/tegra_defconfig
arch/arm/include/asm/dma-mapping.h
arch/arm/include/asm/unistd.h
arch/arm/lib/io-acorn.S
arch/arm/mach-exynos/clock-exynos4.c
arch/arm/mach-exynos/clock-exynos4.h
arch/arm/mach-exynos/clock-exynos4210.c
arch/arm/mach-exynos/clock-exynos4212.c
arch/arm/mach-exynos/mach-nuri.c
arch/arm/mach-exynos/mach-origen.c
arch/arm/mach-netx/fb.c
arch/arm/mach-pxa/eseries.h [deleted file]
arch/arm/mach-pxa/hx4700.c
arch/arm/mach-s3c64xx/include/mach/pm-core.h
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/Makefile
arch/arm/mach-shmobile/board-ag5evm.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-armadillo800eva.c
arch/arm/mach-shmobile/board-bonito.c
arch/arm/mach-shmobile/board-g4evm.c
arch/arm/mach-shmobile/board-kota2.c
arch/arm/mach-shmobile/board-kzm9d.c
arch/arm/mach-shmobile/board-kzm9g.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/board-marzen.c
arch/arm/mach-shmobile/clock-r8a7740.c
arch/arm/mach-shmobile/clock-r8a7779.c
arch/arm/mach-shmobile/clock-sh7367.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/clock-sh7377.c
arch/arm/mach-shmobile/clock-sh73a0.c
arch/arm/mach-shmobile/include/mach/common.h
arch/arm/mach-shmobile/include/mach/dma-register.h [new file with mode: 0644]
arch/arm/mach-shmobile/include/mach/gpio.h
arch/arm/mach-shmobile/include/mach/pm-rmobile.h [new file with mode: 0644]
arch/arm/mach-shmobile/include/mach/r8a7740.h
arch/arm/mach-shmobile/include/mach/sh7372.h
arch/arm/mach-shmobile/include/mach/sh73a0.h
arch/arm/mach-shmobile/intc-r8a7740.c
arch/arm/mach-shmobile/pfc-r8a7740.c
arch/arm/mach-shmobile/pm-r8a7740.c [new file with mode: 0644]
arch/arm/mach-shmobile/pm-rmobile.c [new file with mode: 0644]
arch/arm/mach-shmobile/pm-sh7372.c
arch/arm/mach-shmobile/setup-r8a7740.c
arch/arm/mach-shmobile/setup-sh7372.c
arch/arm/mach-shmobile/setup-sh7377.c
arch/arm/mach-shmobile/setup-sh73a0.c
arch/arm/mach-tegra/board-dt-tegra20.c
arch/arm/mach-tegra/board-dt-tegra30.c
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/devices-common.h
arch/arm/mach-ux500/include/mach/setup.h
arch/arm/mach-vt8500/Makefile
arch/arm/mach-vt8500/pwm.c [deleted file]
arch/arm/mm/dma-mapping.c
arch/arm/mm/mm.h
arch/arm/plat-mxc/Kconfig
arch/arm/plat-mxc/Makefile
arch/arm/plat-mxc/include/mach/i2c.h
arch/arm/plat-pxa/Makefile
arch/arm/plat-pxa/pwm.c [deleted file]
arch/arm/plat-samsung/Makefile
arch/arm/vfp/vfphw.S
arch/avr32/Kconfig
arch/avr32/boards/atstk1000/atstk1002.c
arch/avr32/include/asm/unistd.h
arch/avr32/mm/fault.c
arch/blackfin/Kconfig
arch/blackfin/include/asm/unistd.h
arch/blackfin/kernel/Makefile
arch/blackfin/kernel/pwm.c [deleted file]
arch/cris/Kconfig
arch/cris/include/asm/unistd.h
arch/frv/Kconfig
arch/frv/include/asm/cpumask.h [deleted file]
arch/frv/include/asm/unistd.h
arch/frv/kernel/kernel_thread.S
arch/h8300/Kconfig
arch/h8300/include/asm/unistd.h
arch/hexagon/include/asm/Kbuild
arch/ia64/Kconfig
arch/ia64/include/asm/atomic.h
arch/ia64/include/asm/machvec.h
arch/ia64/include/asm/machvec_dig.h
arch/ia64/include/asm/machvec_dig_vtd.h
arch/ia64/include/asm/machvec_hpsim.h
arch/ia64/include/asm/machvec_hpzx1.h
arch/ia64/include/asm/machvec_hpzx1_swiotlb.h
arch/ia64/include/asm/machvec_sn2.h
arch/ia64/include/asm/machvec_uv.h
arch/ia64/include/asm/machvec_xen.h
arch/ia64/include/asm/processor.h
arch/ia64/kvm/Kconfig
arch/ia64/pci/fixup.c
arch/m32r/Kconfig
arch/m32r/include/asm/unistd.h
arch/m68k/Kconfig
arch/m68k/include/asm/unistd.h
arch/microblaze/Kconfig
arch/microblaze/include/asm/unistd.h
arch/mips/Kbuild.platforms
arch/mips/Kconfig
arch/mips/alchemy/board-mtx1.c
arch/mips/alchemy/common/platform.c
arch/mips/alchemy/devboards/Makefile
arch/mips/alchemy/devboards/bcsr.c
arch/mips/alchemy/devboards/pb1100.c
arch/mips/alchemy/devboards/pb1500.c
arch/mips/alchemy/devboards/platform.c
arch/mips/alchemy/devboards/prom.c [deleted file]
arch/mips/bcm63xx/Kconfig
arch/mips/bcm63xx/Makefile
arch/mips/bcm63xx/boards/board_bcm963xx.c
arch/mips/bcm63xx/clk.c
arch/mips/bcm63xx/cpu.c
arch/mips/bcm63xx/dev-dsp.c
arch/mips/bcm63xx/dev-flash.c [new file with mode: 0644]
arch/mips/bcm63xx/dev-rng.c [new file with mode: 0644]
arch/mips/bcm63xx/dev-spi.c [new file with mode: 0644]
arch/mips/bcm63xx/dev-wdt.c
arch/mips/bcm63xx/irq.c
arch/mips/bcm63xx/prom.c
arch/mips/bcm63xx/setup.c
arch/mips/boot/compressed/Makefile
arch/mips/boot/compressed/uart-16550.c
arch/mips/cavium-octeon/.gitignore [new file with mode: 0644]
arch/mips/cavium-octeon/Makefile
arch/mips/cavium-octeon/executive/cvmx-fpa.c [deleted file]
arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c [deleted file]
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/cavium-octeon/octeon-memcpy.S
arch/mips/cavium-octeon/octeon-platform.c
arch/mips/cavium-octeon/octeon_3xxx.dts [new file with mode: 0644]
arch/mips/cavium-octeon/octeon_68xx.dts [new file with mode: 0644]
arch/mips/cavium-octeon/serial.c
arch/mips/cavium-octeon/setup.c
arch/mips/configs/ls1b_defconfig [new file with mode: 0644]
arch/mips/configs/nlm_xlr_defconfig
arch/mips/dec/prom/memory.c
arch/mips/include/asm/cpu.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h [new file with mode: 0644]
arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h [new file with mode: 0644]
arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
arch/mips/include/asm/mach-bcm63xx/ioremap.h
arch/mips/include/asm/mach-cavium-octeon/irq.h
arch/mips/include/asm/mach-jz4740/jz4740_nand.h
arch/mips/include/asm/mach-loongson/loongson.h
arch/mips/include/asm/mach-loongson1/irq.h [new file with mode: 0644]
arch/mips/include/asm/mach-loongson1/loongson1.h [new file with mode: 0644]
arch/mips/include/asm/mach-loongson1/platform.h [new file with mode: 0644]
arch/mips/include/asm/mach-loongson1/prom.h [new file with mode: 0644]
arch/mips/include/asm/mach-loongson1/regs-clk.h [new file with mode: 0644]
arch/mips/include/asm/mach-loongson1/regs-wdt.h [new file with mode: 0644]
arch/mips/include/asm/mach-loongson1/war.h [new file with mode: 0644]
arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h
arch/mips/include/asm/mach-tx49xx/mangle-port.h
arch/mips/include/asm/mipsmtregs.h
arch/mips/include/asm/module.h
arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h
arch/mips/include/asm/netlogic/xlp-hal/iomap.h
arch/mips/include/asm/netlogic/xlp-hal/pcibus.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlp-hal/pic.h
arch/mips/include/asm/netlogic/xlp-hal/usb.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlp-hal/xlp.h
arch/mips/include/asm/netlogic/xlr/bridge.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlr/flash.h [new file with mode: 0644]
arch/mips/include/asm/netlogic/xlr/gpio.h
arch/mips/include/asm/octeon/cvmx-helper-fpa.h [deleted file]
arch/mips/include/asm/octeon/cvmx-helper.h
arch/mips/include/asm/octeon/octeon.h
arch/mips/include/asm/prom.h
arch/mips/include/asm/smtc.h
arch/mips/include/asm/uaccess.h
arch/mips/include/asm/uasm.h
arch/mips/include/asm/unistd.h
arch/mips/jz4740/board-qi_lb60.c
arch/mips/jz4740/platform.c
arch/mips/jz4740/reset.c
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/prom.c
arch/mips/kernel/smp.c
arch/mips/kernel/smtc.c
arch/mips/kernel/traps.c
arch/mips/lib/Makefile
arch/mips/lib/memcpy-inatomic.S [deleted file]
arch/mips/lib/memcpy.S
arch/mips/loongson1/Kconfig [new file with mode: 0644]
arch/mips/loongson1/Makefile [new file with mode: 0644]
arch/mips/loongson1/Platform [new file with mode: 0644]
arch/mips/loongson1/common/Makefile [new file with mode: 0644]
arch/mips/loongson1/common/clock.c [new file with mode: 0644]
arch/mips/loongson1/common/irq.c [new file with mode: 0644]
arch/mips/loongson1/common/platform.c [new file with mode: 0644]
arch/mips/loongson1/common/prom.c [new file with mode: 0644]
arch/mips/loongson1/common/reset.c [new file with mode: 0644]
arch/mips/loongson1/common/setup.c [new file with mode: 0644]
arch/mips/loongson1/ls1b/Makefile [new file with mode: 0644]
arch/mips/loongson1/ls1b/board.c [new file with mode: 0644]
arch/mips/mm/uasm.c
arch/mips/netlogic/common/earlycons.c
arch/mips/netlogic/common/smpboot.S
arch/mips/netlogic/xlp/Makefile
arch/mips/netlogic/xlp/nlm_hal.c
arch/mips/netlogic/xlp/of.c [new file with mode: 0644]
arch/mips/netlogic/xlp/platform.c
arch/mips/netlogic/xlp/setup.c
arch/mips/netlogic/xlp/usb-init.c [new file with mode: 0644]
arch/mips/netlogic/xlr/Makefile
arch/mips/netlogic/xlr/platform-flash.c [new file with mode: 0644]
arch/mips/netlogic/xlr/platform.c
arch/mips/netlogic/xlr/setup.c
arch/mips/oprofile/common.c
arch/mips/oprofile/op_model_mipsxx.c
arch/mips/pci/Makefile
arch/mips/pci/fixup-cobalt.c
arch/mips/pci/fixup-malta.c
arch/mips/pci/fixup-rc32434.c
arch/mips/pci/ops-bcm63xx.c
arch/mips/pci/pci-bcm63xx.c
arch/mips/pci/pci-bcm63xx.h
arch/mips/pci/pci-xlp.c [new file with mode: 0644]
arch/mips/pci/pci-xlr.c
arch/mips/pnx833x/stb22x/board.c
arch/mips/txx9/generic/pci.c
arch/mips/txx9/generic/setup.c
arch/mips/txx9/generic/setup_tx4939.c
arch/mips/txx9/rbtx4939/setup.c
arch/mn10300/Kconfig
arch/mn10300/include/asm/ipc.h [deleted file]
arch/mn10300/include/asm/unistd.h
arch/openrisc/include/asm/Kbuild
arch/powerpc/Kconfig
arch/powerpc/boot/dts/p2020rdb-pc_32b.dts
arch/powerpc/boot/dts/p2020rdb-pc_36b.dts
arch/powerpc/boot/dts/p3041ds.dts
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/kernel/dma-iommu.c
arch/powerpc/kernel/dma-swiotlb.c
arch/powerpc/kernel/dma.c
arch/powerpc/kernel/vio.c
arch/powerpc/kvm/book3s_rmhandlers.S
arch/powerpc/platforms/85xx/p1022_ds.c
arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h
arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
arch/s390/Kconfig
arch/s390/defconfig
arch/s390/include/asm/mmu_context.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/setup.h
arch/s390/include/asm/unistd.h
arch/s390/kernel/debug.c
arch/s390/kernel/dis.c
arch/s390/kernel/early.c
arch/s390/kernel/ipl.c
arch/s390/kernel/setup.c
arch/s390/kernel/traps.c
arch/s390/kernel/vdso.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/mm/fault.c
arch/s390/mm/mmap.c
arch/s390/mm/pgtable.c
arch/s390/oprofile/backtrace.c
arch/sh/Kconfig
arch/sh/include/asm/unistd.h
arch/sparc/Kconfig
arch/sparc/include/asm/unistd.h
arch/sparc/kernel/sys_sparc_64.c
arch/tile/include/asm/Kbuild
arch/x86/Kconfig
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/unistd.h
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpu/perf_event_intel_uncore.h
arch/x86/kernel/e820.c
arch/xtensa/include/asm/cpumask.h [deleted file]
arch/xtensa/include/asm/rmap.h [deleted file]
arch/xtensa/kernel/syscall.c
arch/xtensa/mm/fault.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/video_detect.c
drivers/ata/pata_arasan_cf.c
drivers/base/dma-mapping.c
drivers/block/rbd.c
drivers/block/rbd_types.h
drivers/block/virtio_blk.c
drivers/char/hw_random/Kconfig
drivers/char/hw_random/Makefile
drivers/char/hw_random/bcm63xx-rng.c [new file with mode: 0644]
drivers/char/hw_random/virtio-rng.c
drivers/char/mspec.c
drivers/clk/Kconfig
drivers/clk/clk.c
drivers/cpufreq/exynos5250-cpufreq.c
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h
drivers/edac/amd64_edac_dbg.c
drivers/edac/amd64_edac_inj.c
drivers/edac/amd76x_edac.c
drivers/edac/cell_edac.c
drivers/edac/cpc925_edac.c
drivers/edac/e752x_edac.c
drivers/edac/e7xxx_edac.c
drivers/edac/edac_core.h
drivers/edac/edac_device.c
drivers/edac/edac_device_sysfs.c
drivers/edac/edac_mc.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/edac_module.c
drivers/edac/edac_module.h
drivers/edac/edac_pci.c
drivers/edac/edac_pci_sysfs.c
drivers/edac/highbank_l2_edac.c [new file with mode: 0644]
drivers/edac/highbank_mc_edac.c [new file with mode: 0644]
drivers/edac/i3000_edac.c
drivers/edac/i3200_edac.c
drivers/edac/i5000_edac.c
drivers/edac/i5100_edac.c
drivers/edac/i5400_edac.c
drivers/edac/i7300_edac.c
drivers/edac/i7core_edac.c
drivers/edac/i82443bxgx_edac.c
drivers/edac/i82860_edac.c
drivers/edac/i82875p_edac.c
drivers/edac/i82975x_edac.c
drivers/edac/mpc85xx_edac.c
drivers/edac/mv64x60_edac.c
drivers/edac/pasemi_edac.c
drivers/edac/ppc4xx_edac.c
drivers/edac/r82600_edac.c
drivers/edac/sb_edac.c
drivers/edac/tile_edac.c
drivers/edac/x38_edac.c
drivers/extcon/Kconfig
drivers/extcon/extcon-max8997.c
drivers/firewire/core-device.c
drivers/firewire/core-iso.c
drivers/firewire/core-transaction.c
drivers/firewire/ohci.c
drivers/firmware/memmap.c
drivers/firmware/pcdp.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-tps6586x.c [new file with mode: 0644]
drivers/gpu/drm/exynos/exynos_drm_connector.c
drivers/gpu/drm/exynos/exynos_drm_core.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_crtc.h
drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_encoder.c
drivers/gpu/drm/exynos/exynos_drm_encoder.h
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_gem.c
drivers/gpu/drm/exynos/exynos_drm_gem.h
drivers/gpu/drm/exynos/exynos_drm_plane.c
drivers/gpu/drm/exynos/exynos_drm_plane.h
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/hwmon/acpi_power_meter.c
drivers/hwmon/applesmc.c
drivers/hwmon/coretemp.c
drivers/hwmon/jc42.c
drivers/hwmon/via-cputemp.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-bfin-twi.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-nomadik.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-octeon.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-pnx.c
drivers/i2c/busses/i2c-puv3.c
drivers/i2c/busses/i2c-pxa.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/i2c/busses/i2c-stu300.c
drivers/i2c/busses/i2c-tegra.c
drivers/i2c/i2c-core.c
drivers/input/misc/88pm80x_onkey.c [new file with mode: 0644]
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/ab8500-ponkey.c
drivers/input/mouse/synaptics.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/edt-ft5x06.c [new file with mode: 0644]
drivers/md/Kconfig
drivers/md/dm-crypt.c
drivers/md/dm-delay.c
drivers/md/dm-exception-store.c
drivers/md/dm-flakey.c
drivers/md/dm-ioctl.c
drivers/md/dm-linear.c
drivers/md/dm-log.c
drivers/md/dm-mpath.c
drivers/md/dm-raid.c
drivers/md/dm-raid1.c
drivers/md/dm-snap.c
drivers/md/dm-stripe.c
drivers/md/dm-table.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin-metadata.h
drivers/md/dm-thin.c
drivers/md/dm-verity.c
drivers/md/dm.c
drivers/md/dm.h
drivers/md/persistent-data/Makefile
drivers/md/persistent-data/dm-block-manager.c
drivers/md/persistent-data/dm-block-manager.h
drivers/md/persistent-data/dm-space-map-checker.c [deleted file]
drivers/md/persistent-data/dm-space-map-checker.h [deleted file]
drivers/md/persistent-data/dm-space-map-common.c
drivers/md/persistent-data/dm-space-map-common.h
drivers/md/persistent-data/dm-space-map-disk.c
drivers/md/persistent-data/dm-transaction-manager.c
drivers/md/persistent-data/dm-transaction-manager.h
drivers/media/Kconfig
drivers/media/common/tuners/Kconfig
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/common/tuners/xc5000.c
drivers/media/dvb/ddbridge/ddbridge-core.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/az6007.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/rtl28xxu.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/a8293.c
drivers/media/dvb/frontends/drxk.h
drivers/media/dvb/frontends/drxk_hard.c
drivers/media/dvb/frontends/drxk_hard.h
drivers/media/dvb/frontends/rtl2832.c [new file with mode: 0644]
drivers/media/dvb/frontends/rtl2832.h [new file with mode: 0644]
drivers/media/dvb/frontends/rtl2832_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/s5h1420.c
drivers/media/dvb/frontends/stb0899_drv.c
drivers/media/dvb/frontends/stv0367.c
drivers/media/dvb/frontends/stv090x.c
drivers/media/dvb/frontends/tda10071.c
drivers/media/dvb/frontends/tda10071_priv.h
drivers/media/dvb/ngene/ngene-cards.c
drivers/media/radio/Kconfig
drivers/media/radio/lm7000.h [new file with mode: 0644]
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-wl1273.c
drivers/media/radio/si470x/radio-si470x-common.c
drivers/media/radio/wl128x/fmdrv_rx.c
drivers/media/radio/wl128x/fmdrv_v4l2.c
drivers/media/rc/Kconfig
drivers/media/rc/ene_ir.c
drivers/media/rc/fintek-cir.c
drivers/media/rc/gpio-ir-recv.c
drivers/media/rc/nuvoton-cir.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7393.c [new file with mode: 0644]
drivers/media/video/adv7393_regs.h [new file with mode: 0644]
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cs8420.h [deleted file]
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-ioctl.h
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx231xx/cx231xx-avcore.c
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-reg.h
drivers/media/video/ibmmpeg2.h [deleted file]
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-ioctl.h
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/m5mols/Kconfig
drivers/media/video/mem2mem_testdev.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9m032.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9p031.c
drivers/media/video/mt9t001.c
drivers/media/video/mt9v022.c
drivers/media/video/omap3isp/ispccdc.c
drivers/media/video/omap3isp/isppreview.c
drivers/media/video/omap3isp/ispresizer.c
drivers/media/video/pvrusb2/Kconfig
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pwc/pwc.h
drivers/media/video/s5p-fimc/fimc-capture.c
drivers/media/video/s5p-fimc/fimc-core.c
drivers/media/video/s5p-fimc/fimc-lite-reg.c
drivers/media/video/s5p-fimc/fimc-lite.c
drivers/media/video/s5p-fimc/fimc-mdevice.c
drivers/media/video/s5p-jpeg/jpeg-core.c
drivers/media/video/s5p-tv/mixer_video.c
drivers/media/video/s5p-tv/sii9234_drv.c
drivers/media/video/saa7121.h [deleted file]
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7146.h [deleted file]
drivers/media/video/saa7146reg.h [deleted file]
drivers/media/video/saa7164/saa7164-api.c
drivers/media/video/smiapp/Kconfig
drivers/media/video/smiapp/smiapp-core.c
drivers/media/video/sn9c102/sn9c102.h
drivers/media/video/tuner-core.c
drivers/media/video/tvaudio.c
drivers/media/video/tvp5150.c
drivers/media/video/uvc/Kconfig
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvc_video.c
drivers/media/video/v4l2-compat-ioctl32.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/v4l2-subdev.c
drivers/media/video/videobuf-core.c
drivers/media/video/videobuf-dma-contig.c
drivers/media/video/videobuf2-core.c
drivers/media/video/vivi.c
drivers/media/video/zr364xx.c
drivers/message/i2o/i2o_config.c
drivers/message/i2o/i2o_proc.c
drivers/mfd/88pm800.c [new file with mode: 0644]
drivers/mfd/88pm805.c [new file with mode: 0644]
drivers/mfd/88pm80x.c [new file with mode: 0644]
drivers/mfd/88pm860x-core.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab3100-core.c
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-debugfs.c
drivers/mfd/ab8500-gpadc.c
drivers/mfd/ab8500-sysctrl.c
drivers/mfd/adp5520.c
drivers/mfd/anatop-mfd.c
drivers/mfd/arizona-core.c [new file with mode: 0644]
drivers/mfd/arizona-i2c.c [new file with mode: 0644]
drivers/mfd/arizona-irq.c [new file with mode: 0644]
drivers/mfd/arizona-spi.c [new file with mode: 0644]
drivers/mfd/arizona.h [new file with mode: 0644]
drivers/mfd/da9052-core.c
drivers/mfd/db8500-prcmu.c
drivers/mfd/dbx500-prcmu-regs.h
drivers/mfd/max77686-irq.c [new file with mode: 0644]
drivers/mfd/max77686.c [new file with mode: 0644]
drivers/mfd/max77693.c
drivers/mfd/max8925-core.c
drivers/mfd/max8997-irq.c
drivers/mfd/max8997.c
drivers/mfd/mc13xxx-core.c
drivers/mfd/mc13xxx-i2c.c
drivers/mfd/mc13xxx-spi.c
drivers/mfd/mfd-core.c
drivers/mfd/pcf50633-core.c
drivers/mfd/s5m-core.c [deleted file]
drivers/mfd/s5m-irq.c [deleted file]
drivers/mfd/sec-core.c [new file with mode: 0644]
drivers/mfd/sec-irq.c [new file with mode: 0644]
drivers/mfd/tc3589x.c
drivers/mfd/timberdale.c
drivers/mfd/tps65090.c
drivers/mfd/tps6586x.c
drivers/mfd/tps65910.c
drivers/mfd/twl-core.c
drivers/mfd/twl6040-core.c
drivers/mfd/wm5102-tables.c [new file with mode: 0644]
drivers/mfd/wm5110-tables.c [new file with mode: 0644]
drivers/mfd/wm8350-core.c
drivers/mfd/wm8350-i2c.c
drivers/mfd/wm8350-irq.c
drivers/mfd/wm8350-regmap.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8994-irq.c
drivers/misc/Kconfig
drivers/misc/ab8500-pwm.c
drivers/misc/lkdtm.c
drivers/misc/ti-st/st_core.c
drivers/mtd/nand/jz4740_nand.c
drivers/net/can/c_can/c_can_platform.c
drivers/net/ethernet/octeon/octeon_mgmt.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/phy/mdio-octeon.c
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/apple-gmux.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/asus-wmi.h
drivers/platform/x86/classmate-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/eeepc-wmi.c
drivers/platform/x86/samsung-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/power/Kconfig
drivers/power/bq27x00_battery.c
drivers/power/charger-manager.c
drivers/power/ds2781_battery.c
drivers/power/gpio-charger.c
drivers/power/lp8727_charger.c
drivers/power/max17042_battery.c
drivers/power/olpc_battery.c
drivers/power/pda_power.c
drivers/power/power_supply_core.c
drivers/power/power_supply_sysfs.c
drivers/power/sbs-battery.c
drivers/power/smb347-charger.c
drivers/power/test_power.c
drivers/power/twl4030_charger.c
drivers/pps/pps.c
drivers/pwm/Kconfig [new file with mode: 0644]
drivers/pwm/Makefile [new file with mode: 0644]
drivers/pwm/core.c [new file with mode: 0644]
drivers/pwm/pwm-bfin.c [new file with mode: 0644]
drivers/pwm/pwm-imx.c [moved from arch/arm/plat-mxc/pwm.c with 50% similarity]
drivers/pwm/pwm-lpc32xx.c [new file with mode: 0644]
drivers/pwm/pwm-mxs.c [new file with mode: 0644]
drivers/pwm/pwm-pxa.c [new file with mode: 0644]
drivers/pwm/pwm-samsung.c [moved from arch/arm/plat-samsung/pwm.c with 56% similarity]
drivers/pwm/pwm-tegra.c [new file with mode: 0644]
drivers/pwm/pwm-tiecap.c [new file with mode: 0644]
drivers/pwm/pwm-tiehrpwm.c [new file with mode: 0644]
drivers/pwm/pwm-vt8500.c [new file with mode: 0644]
drivers/regulator/Kconfig
drivers/regulator/ab8500.c
drivers/regulator/db8500-prcmu.c
drivers/regulator/s5m8767.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-88pm80x.c [new file with mode: 0644]
drivers/rtc/rtc-ab8500.c
drivers/rtc/rtc-coh901331.c
drivers/rtc/rtc-da9052.c
drivers/rtc/rtc-max8925.c
drivers/rtc/rtc-mc13xxx.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-pl031.c
drivers/rtc/rtc-r9701.c
drivers/rtc/rtc-s3c.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/spi-falcon.c [new file with mode: 0644]
drivers/staging/media/lirc/lirc_sir.c
drivers/staging/media/solo6x10/TODO
drivers/staging/media/solo6x10/i2c.c
drivers/staging/octeon/ethernet-mdio.c
drivers/staging/octeon/ethernet.c
drivers/staging/octeon/octeon-ethernet.h
drivers/thermal/thermal_sys.c
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/m66592-udc.h
drivers/usb/gadget/r8a66597-udc.c
drivers/usb/gadget/r8a66597-udc.h
drivers/usb/host/ehci-omap.c
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/r8a66597.h
drivers/usb/musb/musb_core.h
drivers/video/backlight/Kconfig
drivers/video/backlight/atmel-pwm-bl.c
drivers/video/backlight/corgi_lcd.c
drivers/video/backlight/l4f00242t03.c
drivers/video/backlight/lm3533_bl.c
drivers/video/backlight/lms283gf05.c
drivers/video/backlight/lp855x_bl.c
drivers/video/backlight/ot200_bl.c
drivers/video/backlight/pwm_bl.c
drivers/video/backlight/tosa_bl.c
drivers/video/backlight/tosa_lcd.c
fs/affs/bitmap.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/relocation.c
fs/btrfs/super.c
fs/cachefiles/rdwr.c
fs/ceph/dir.c
fs/ceph/mds_client.c
fs/ceph/snap.c
fs/ceph/super.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/exec.c
fs/ext2/balloc.c
fs/ext2/ialloc.c
fs/ext3/balloc.c
fs/ext3/bitmap.c
fs/ext4/bitmap.c
fs/fat/dir.c
fs/fat/fat.h
fs/fat/inode.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/fcntl.c
fs/fs-writeback.c
fs/hfsplus/super.c
fs/lockd/grace.c
fs/lockd/host.c
fs/lockd/netns.h
fs/lockd/svc.c
fs/lockd/svc4proc.c
fs/lockd/svclock.c
fs/lockd/svcproc.c
fs/lockd/svcsubs.c
fs/locks.c
fs/minix/itree_v2.c
fs/nfs/Kconfig
fs/nfs/Makefile
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/delegation.h
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/file.c
fs/nfs/getroot.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs2xdr.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c [new file with mode: 0644]
fs/nfs/nfs4file.c [new file with mode: 0644]
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4getroot.c [new file with mode: 0644]
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4super.c [new file with mode: 0644]
fs/nfs/nfs4sysctl.c [new file with mode: 0644]
fs/nfs/nfs4xdr.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/proc.c
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/sysctl.c
fs/nfs/unlink.c
fs/nfs/write.c
fs/nfsd/export.c
fs/nfsd/netns.h
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4idmap.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsd.h
fs/nfsd/nfssvc.c
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nilfs2/alloc.h
fs/nilfs2/bmap.h
fs/nilfs2/btnode.h
fs/nilfs2/cpfile.c
fs/nilfs2/dat.c
fs/nilfs2/export.h
fs/nilfs2/ifile.c
fs/nilfs2/inode.c
fs/nilfs2/ioctl.c
fs/nilfs2/mdt.h
fs/nilfs2/nilfs.h
fs/nilfs2/sufile.c
fs/nilfs2/super.c
fs/nilfs2/the_nilfs.c
fs/nilfs2/the_nilfs.h
fs/ntfs/super.c
fs/ocfs2/localalloc.c
fs/proc/base.c
fs/qnx4/bitmap.c
fs/super.c
fs/xattr.c
fs/xfs/xfs_alloc_btree.h
fs/xfs/xfs_aops.c
fs/xfs/xfs_aops.h
fs/xfs/xfs_attr.c
fs/xfs/xfs_attr_leaf.c
fs/xfs/xfs_attr_leaf.h
fs/xfs/xfs_bmap.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_buf_item.h
fs/xfs/xfs_da_btree.c
fs/xfs/xfs_da_btree.h
fs/xfs/xfs_dinode.h
fs/xfs/xfs_dir2.c
fs/xfs/xfs_dir2_block.c
fs/xfs/xfs_dir2_data.c
fs/xfs/xfs_dir2_leaf.c
fs/xfs/xfs_dir2_node.c
fs/xfs/xfs_dir2_priv.h
fs/xfs/xfs_dir2_sf.c
fs/xfs/xfs_file.c
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_ialloc.h
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_iomap.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_itable.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_qm.c
fs/xfs/xfs_super.c
fs/xfs/xfs_sync.c
fs/xfs/xfs_trace.h
fs/xfs/xfs_trans.h
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_trans_priv.h
fs/xfs/xfs_types.h
fs/xfs/xfs_utils.c
fs/xfs/xfs_vnodeops.c
include/asm-generic/dma-coherent.h
include/asm-generic/dma-mapping-common.h
include/asm-generic/fcntl.h
include/drm/exynos_drm.h
include/linux/Kbuild
include/linux/acpi.h
include/linux/aio.h
include/linux/backing-dev.h
include/linux/ceph/ceph_features.h [new file with mode: 0644]
include/linux/ceph/ceph_fs.h
include/linux/ceph/decode.h
include/linux/ceph/libceph.h
include/linux/ceph/messenger.h
include/linux/ceph/mon_client.h
include/linux/ceph/msgpool.h
include/linux/clk.h
include/linux/compat.h
include/linux/crush/crush.h
include/linux/device-mapper.h
include/linux/dm-ioctl.h
include/linux/dma-attrs.h
include/linux/dma-mapping.h
include/linux/edac.h
include/linux/firewire.h
include/linux/flex_proportions.h [new file with mode: 0644]
include/linux/fs.h
include/linux/i2c-ocores.h
include/linux/i2c.h
include/linux/i2c/twl.h
include/linux/input/edt-ft5x06.h [new file with mode: 0644]
include/linux/kern_levels.h [new file with mode: 0644]
include/linux/key-type.h
include/linux/libfdt.h [new file with mode: 0644]
include/linux/libfdt_env.h [new file with mode: 0644]
include/linux/lockd/lockd.h
include/linux/mempolicy.h
include/linux/mfd/88pm80x.h [new file with mode: 0644]
include/linux/mfd/88pm860x.h
include/linux/mfd/abx500/ab8500.h
include/linux/mfd/arizona/core.h [new file with mode: 0644]
include/linux/mfd/arizona/pdata.h [new file with mode: 0644]
include/linux/mfd/arizona/registers.h [new file with mode: 0644]
include/linux/mfd/core.h
include/linux/mfd/db8500-prcmu.h
include/linux/mfd/dbx500-prcmu.h
include/linux/mfd/max77686-private.h [new file with mode: 0644]
include/linux/mfd/max77686.h [new file with mode: 0644]
include/linux/mfd/max77693-private.h
include/linux/mfd/max8997-private.h
include/linux/mfd/max8997.h
include/linux/mfd/s5m87xx/s5m-core.h [deleted file]
include/linux/mfd/s5m87xx/s5m-pmic.h [deleted file]
include/linux/mfd/samsung/core.h [new file with mode: 0644]
include/linux/mfd/samsung/irq.h [new file with mode: 0644]
include/linux/mfd/samsung/rtc.h [moved from include/linux/mfd/s5m87xx/s5m-rtc.h with 59% similarity]
include/linux/mfd/samsung/s2mps11.h [new file with mode: 0644]
include/linux/mfd/samsung/s5m8763.h [new file with mode: 0644]
include/linux/mfd/samsung/s5m8767.h [new file with mode: 0644]
include/linux/mfd/tps65910.h
include/linux/mfd/twl6040.h
include/linux/mfd/wm8350/core.h
include/linux/mfd/wm8994/pdata.h
include/linux/mm_types.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/nfs_page.h
include/linux/nfs_xdr.h
include/linux/nilfs2_fs.h
include/linux/of.h
include/linux/platform_data/i2c-nomadik.h [moved from arch/arm/plat-nomadik/include/plat/i2c.h with 91% similarity]
include/linux/platform_data/lp855x.h [moved from include/linux/lp855x.h with 96% similarity]
include/linux/platform_data/lp8727.h [moved from include/linux/lp8727.h with 100% similarity]
include/linux/platform_data/mv_usb.h
include/linux/power/charger-manager.h
include/linux/power_supply.h
include/linux/printk.h
include/linux/pwm.h
include/linux/pwm_backlight.h
include/linux/scatterlist.h
include/linux/sched.h
include/linux/shm.h
include/linux/slab.h
include/linux/slab_def.h
include/linux/slub_def.h
include/linux/string.h
include/linux/sunrpc/auth.h
include/linux/sunrpc/cache.h
include/linux/sunrpc/gss_api.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/xdr.h
include/linux/thermal.h
include/linux/uvcvideo.h
include/linux/v4l2-common.h [new file with mode: 0644]
include/linux/v4l2-subdev.h
include/linux/videodev2.h
include/linux/virtio_blk.h
include/linux/virtio_ids.h
include/linux/vmalloc.h
include/media/adv7393.h [new file with mode: 0644]
include/media/gpio-ir-recv.h
include/media/mt9t001.h
include/media/v4l2-chip-ident.h
include/media/v4l2-dev.h
include/media/v4l2-ioctl.h
include/media/videobuf-core.h
include/media/videobuf2-core.h
include/media/videobuf2-dma-contig.h
include/ras/ras_event.h [new file with mode: 0644]
ipc/compat.c
ipc/shm.c
ipc/syscall.c
ipc/util.c
ipc/util.h
kernel/events/uprobes.c
kernel/fork.c
kernel/kexec.c
kernel/kmod.c
kernel/panic.c
kernel/power/suspend.c
kernel/printk.c
kernel/resource.c
kernel/sched/core.c
kernel/sys.c
kernel/sysctl.c
kernel/taskstats.c
kernel/watchdog.c
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/atomic64_test.c
lib/cpu-notifier-error-inject.c
lib/crc32.c
lib/fdt.c [new file with mode: 0644]
lib/fdt_ro.c [new file with mode: 0644]
lib/fdt_rw.c [new file with mode: 0644]
lib/fdt_strerror.c [new file with mode: 0644]
lib/fdt_sw.c [new file with mode: 0644]
lib/fdt_wip.c [new file with mode: 0644]
lib/flex_proportions.c [new file with mode: 0644]
lib/memory-notifier-error-inject.c [new file with mode: 0644]
lib/memweight.c [new file with mode: 0644]
lib/notifier-error-inject.c [new file with mode: 0644]
lib/notifier-error-inject.h [new file with mode: 0644]
lib/pSeries-reconfig-notifier-error-inject.c [new file with mode: 0644]
lib/pm-notifier-error-inject.c [new file with mode: 0644]
lib/scatterlist.c
lib/spinlock_debug.c
lib/vsprintf.c
mm/Makefile
mm/backing-dev.c
mm/memory-failure.c
mm/mempolicy.c
mm/mmap.c
mm/page-writeback.c
mm/slab.c
mm/slab.h [new file with mode: 0644]
mm/slab_common.c [new file with mode: 0644]
mm/slob.c
mm/slub.c
mm/vmalloc.c
net/ceph/ceph_common.c
net/ceph/crush/mapper.c
net/ceph/messenger.c
net/ceph/mon_client.c
net/ceph/msgpool.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/sunrpc/auth.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_gss/gss_mech_switch.c
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/xdr.c
scripts/checkpatch.pl
scripts/coccinelle/iterators/use_after_iter.cocci [new file with mode: 0644]
scripts/coccinelle/misc/irqf_oneshot.cocci [new file with mode: 0644]
scripts/config
scripts/kconfig/.gitignore
scripts/kconfig/Makefile
scripts/kconfig/confdata.c
scripts/kconfig/lxdialog/check-lxdialog.sh
scripts/kconfig/lxdialog/textbox.c
scripts/kconfig/mconf.c
scripts/kconfig/nconf.c
scripts/kconfig/nconf.gui.c
scripts/kconfig/streamline_config.pl
scripts/link-vmlinux.sh
scripts/package/builddeb
scripts/sortextable.c
scripts/tags.sh
security/selinux/hooks.c
security/smack/smackfs.c
sound/core/misc.c
sound/i2c/other/tea575x-tuner.c
sound/soc/codecs/twl6040.c
tools/lib/traceevent/.gitignore [new file with mode: 0644]
tools/lib/traceevent/Makefile
tools/perf/Makefile
tools/perf/builtin-test.c
tools/perf/builtin-top.c
tools/perf/ui/browsers/hists.c
tools/perf/util/annotate.c
tools/perf/util/dso-test-data.c [new file with mode: 0644]
tools/perf/util/evlist.c
tools/perf/util/header.c
tools/perf/util/hist.c
tools/perf/util/map.c
tools/perf/util/map.h
tools/perf/util/parse-events.c
tools/perf/util/session.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/target.c
tools/testing/fault-injection/failcmd.sh [new file with mode: 0644]
tools/testing/ktest/ktest.pl
tools/testing/ktest/sample.conf
tools/testing/selftests/Makefile
tools/testing/selftests/cpu-hotplug/Makefile [new file with mode: 0644]
tools/testing/selftests/cpu-hotplug/on-off-test.sh [new file with mode: 0644]
tools/testing/selftests/memory-hotplug/Makefile [new file with mode: 0644]
tools/testing/selftests/memory-hotplug/on-off-test.sh [new file with mode: 0644]
tools/vm/slabinfo.c

index 3d484e5dc846ed9b7625c83d948322f825c323df..41e5a0cd1e3ed334234c4f3e9e3db1e2fa021dfc 100644 (file)
@@ -39,6 +39,17 @@ Users:               udev rules to set ownership and access permissions or ACLs of
                /dev/fw[0-9]+ character device files
 
 
+What:          /sys/bus/firewire/devices/fw[0-9]+/is_local
+Date:          July 2012
+KernelVersion: 3.6
+Contact:       linux1394-devel@lists.sourceforge.net
+Description:
+               IEEE 1394 node device attribute.
+               Read-only and immutable.
+Values:                1: The sysfs entry represents a local node (a controller card).
+               0: The sysfs entry represents a remote node.
+
+
 What:          /sys/bus/firewire/devices/fw[0-9]+[.][0-9]+/
 Date:          May 2007
 KernelVersion: 2.6.22
index bcd88eb7ebcd240abcdbe0ef34f4a517f0f404bd..3c17b62899f688c5955a3f065e966c9fc72231f7 100644 (file)
@@ -35,8 +35,14 @@ name
 
 pool
 
-       The pool where this rbd image resides. The pool-name pair is unique
-       per rados system.
+       The name of the storage pool where this rbd image resides.
+       An rbd image name is unique within its pool.
+
+pool_id
+
+       The unique identifier for the rbd image's pool.  This is
+       a permanent attribute of the pool.  A pool's id will never
+       change.
 
 size
 
diff --git a/Documentation/ABI/testing/sysfs-devices-edac b/Documentation/ABI/testing/sysfs-devices-edac
new file mode 100644 (file)
index 0000000..30ee78a
--- /dev/null
@@ -0,0 +1,140 @@
+What:          /sys/devices/system/edac/mc/mc*/reset_counters
+Date:          January 2006
+Contact:       linux-edac@vger.kernel.org
+Description:   This write-only control file will zero all the statistical
+               counters for UE and CE errors on the given memory controller.
+               Zeroing the counters will also reset the timer indicating how
+               long since the last counter were reset. This is useful for
+               computing errors/time.  Since the counters are always reset
+               at driver initialization time, no module/kernel parameter
+               is available.
+
+What:          /sys/devices/system/edac/mc/mc*/seconds_since_reset
+Date:          January 2006
+Contact:       linux-edac@vger.kernel.org
+Description:   This attribute file displays how many seconds have elapsed
+               since the last counter reset. This can be used with the error
+               counters to measure error rates.
+
+What:          /sys/devices/system/edac/mc/mc*/mc_name
+Date:          January 2006
+Contact:       linux-edac@vger.kernel.org
+Description:   This attribute file displays the type of memory controller
+               that is being utilized.
+
+What:          /sys/devices/system/edac/mc/mc*/size_mb
+Date:          January 2006
+Contact:       linux-edac@vger.kernel.org
+Description:   This attribute file displays, in count of megabytes, of memory
+               that this memory controller manages.
+
+What:          /sys/devices/system/edac/mc/mc*/ue_count
+Date:          January 2006
+Contact:       linux-edac@vger.kernel.org
+Description:   This attribute file displays the total count of uncorrectable
+               errors that have occurred on this memory controller. If
+               panic_on_ue is set, this counter will not have a chance to
+               increment, since EDAC will panic the system
+
+What:          /sys/devices/system/edac/mc/mc*/ue_noinfo_count
+Date:          January 2006
+Contact:       linux-edac@vger.kernel.org
+Description:   This attribute file displays the number of UEs that have
+               occurred on this memory controller with no information as to
+               which DIMM slot is having errors.
+
+What:          /sys/devices/system/edac/mc/mc*/ce_count
+Date:          January 2006
+Contact:       linux-edac@vger.kernel.org
+Description:   This attribute file displays the total count of correctable
+               errors that have occurred on this memory controller. This
+               count is very important to examine. CEs provide early
+               indications that a DIMM is beginning to fail. This count
+               field should be monitored for non-zero values and report
+               such information to the system administrator.
+
+What:          /sys/devices/system/edac/mc/mc*/ce_noinfo_count
+Date:          January 2006
+Contact:       linux-edac@vger.kernel.org
+Description:   This attribute file displays the number of CEs that
+               have occurred on this memory controller wherewith no
+               information as to which DIMM slot is having errors. Memory is
+               handicapped, but operational, yet no information is available
+               to indicate which slot the failing memory is in. This count
+               field should be also be monitored for non-zero values.
+
+What:          /sys/devices/system/edac/mc/mc*/sdram_scrub_rate
+Date:          February 2007
+Contact:       linux-edac@vger.kernel.org
+Description:   Read/Write attribute file that controls memory scrubbing.
+               The scrubbing rate used by the memory controller is set by
+               writing a minimum bandwidth in bytes/sec to the attribute file.
+               The rate will be translated to an internal value that gives at
+               least the specified rate.
+               Reading the file will return the actual scrubbing rate employed.
+               If configuration fails or memory scrubbing is not implemented,
+               the value of the attribute file will be -1.
+
+What:          /sys/devices/system/edac/mc/mc*/max_location
+Date:          April 2012
+Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+               linux-edac@vger.kernel.org
+Description:   This attribute file displays the information about the last
+               available memory slot in this memory controller. It is used by
+               userspace tools in order to display the memory filling layout.
+
+What:          /sys/devices/system/edac/mc/mc*/(dimm|rank)*/size
+Date:          April 2012
+Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+               linux-edac@vger.kernel.org
+Description:   This attribute file will display the size of dimm or rank.
+               For dimm*/size, this is the size, in MB of the DIMM memory
+               stick. For rank*/size, this is the size, in MB for one rank
+               of the DIMM memory stick. On single rank memories (1R), this
+               is also the total size of the dimm. On dual rank (2R) memories,
+               this is half the size of the total DIMM memories.
+
+What:          /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_dev_type
+Date:          April 2012
+Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+               linux-edac@vger.kernel.org
+Description:   This attribute file will display what type of DRAM device is
+               being utilized on this DIMM (x1, x2, x4, x8, ...).
+
+What:          /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_edac_mode
+Date:          April 2012
+Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+               linux-edac@vger.kernel.org
+Description:   This attribute file will display what type of Error detection
+               and correction is being utilized. For example: S4ECD4ED would
+               mean a Chipkill with x4 DRAM.
+
+What:          /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_label
+Date:          April 2012
+Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+               linux-edac@vger.kernel.org
+Description:   This control file allows this DIMM to have a label assigned
+               to it. With this label in the module, when errors occur
+               the output can provide the DIMM label in the system log.
+               This becomes vital for panic events to isolate the
+               cause of the UE event.
+               DIMM Labels must be assigned after booting, with information
+               that correctly identifies the physical slot with its
+               silk screen label. This information is currently very
+               motherboard specific and determination of this information
+               must occur in userland at this time.
+
+What:          /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_location
+Date:          April 2012
+Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+               linux-edac@vger.kernel.org
+Description:   This attribute file will display the location (csrow/channel,
+               branch/channel/slot or channel/slot) of the dimm or rank.
+
+What:          /sys/devices/system/edac/mc/mc*/(dimm|rank)*/dimm_mem_type
+Date:          April 2012
+Contact:       Mauro Carvalho Chehab <mchehab@redhat.com>
+               linux-edac@vger.kernel.org
+Description:   This attribute file will display what type of memory is
+               currently on this csrow. Normally, either buffered or
+               unbuffered memory (for example, Unbuffered-DDR3).
index 2e7df91620de46ce9e473298f7a8d7fa8216f0db..019e1e29370e73b96aff40903bc49551206caa77 100644 (file)
@@ -29,3 +29,10 @@ KernelVersion:       2.6.39
 Contact:       "Corentin Chary" <corentincj@iksaif.net>
 Description:
                Control the card touchpad. 1 means on, 0 means off.
+
+What:          /sys/devices/platform/<platform>/lid_resume
+Date:          May 2012
+KernelVersion: 3.5
+Contact:       "AceLan Kao" <acelan.kao@canonical.com>
+Description:
+               Resume on lid open. 1 means on, 0 means off.
index 5c72eed89563083250217336c79ab1d7f350a7c5..f50309081ac78e0900c3ef5e5646abf998079657 100644 (file)
@@ -49,3 +49,45 @@ DMA_ATTR_NON_CONSISTENT lets the platform to choose to return either
 consistent or non-consistent memory as it sees fit.  By using this API,
 you are guaranteeing to the platform that you have all the correct and
 necessary sync points for this memory in the driver.
+
+DMA_ATTR_NO_KERNEL_MAPPING
+--------------------------
+
+DMA_ATTR_NO_KERNEL_MAPPING lets the platform to avoid creating a kernel
+virtual mapping for the allocated buffer. On some architectures creating
+such mapping is non-trivial task and consumes very limited resources
+(like kernel virtual address space or dma consistent address space).
+Buffers allocated with this attribute can be only passed to user space
+by calling dma_mmap_attrs(). By using this API, you are guaranteeing
+that you won't dereference the pointer returned by dma_alloc_attr(). You
+can threat it as a cookie that must be passed to dma_mmap_attrs() and
+dma_free_attrs(). Make sure that both of these also get this attribute
+set on each call.
+
+Since it is optional for platforms to implement
+DMA_ATTR_NO_KERNEL_MAPPING, those that do not will simply ignore the
+attribute and exhibit default behavior.
+
+DMA_ATTR_SKIP_CPU_SYNC
+----------------------
+
+By default dma_map_{single,page,sg} functions family transfer a given
+buffer from CPU domain to device domain. Some advanced use cases might
+require sharing a buffer between more than one device. This requires
+having a mapping created separately for each device and is usually
+performed by calling dma_map_{single,page,sg} function more than once
+for the given buffer with device pointer to each device taking part in
+the buffer sharing. The first call transfers a buffer from 'CPU' domain
+to 'device' domain, what synchronizes CPU caches for the given region
+(usually it means that the cache has been flushed or invalidated
+depending on the dma direction). However, next calls to
+dma_map_{single,page,sg}() for other devices will perform exactly the
+same sychronization operation on the CPU cache. CPU cache sychronization
+might be a time consuming operation, especially if the buffers are
+large, so it is highly recommended to avoid it if possible.
+DMA_ATTR_SKIP_CPU_SYNC allows platform code to skip synchronization of
+the CPU cache for the given buffer assuming that it has been already
+transferred to 'device' domain. This attribute can be also used for
+dma_unmap_{single,page,sg} functions family to force buffer to stay in
+device domain after releasing a mapping for it. Use this attribute with
+care!
index 7c49facecd25a8ee7cbe293cb4af906d0728d116..1078e45f189f0630c6c6ea50f74b3764dc1cea43 100644 (file)
@@ -194,7 +194,7 @@ in the frequency range from 87,5 to 108,0 MHz</title>
        <corpauthor>National Radio Systems Committee
 (<ulink url="http://www.nrscstandards.org">http://www.nrscstandards.org</ulink>)</corpauthor>
       </authorgroup>
-      <title>NTSC-4: United States RBDS Standard</title>
+      <title>NRSC-4: United States RBDS Standard</title>
     </biblioentry>
 
     <biblioentry id="iso12232">
index 4101aeb565406b6ed08219feff76bdd735f1fd33..b91d25313b631eb25fec06bf42877131af31c61e 100644 (file)
@@ -464,14 +464,14 @@ The <structfield>type</structfield> field of the respective
 <structfield>tuner</structfield> field contains the index number of
 the tuner.</para>
 
-      <para>Radio devices have exactly one tuner with index zero, no
+      <para>Radio input devices have exactly one tuner with index zero, no
 video inputs.</para>
 
       <para>To query and change tuner properties applications use the
 &VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; ioctl, respectively. The
 &v4l2-tuner; returned by <constant>VIDIOC_G_TUNER</constant> also
 contains signal status information applicable when the tuner of the
-current video input, or a radio tuner is queried. Note that
+current video or radio input is queried. Note that
 <constant>VIDIOC_S_TUNER</constant> does not switch the current tuner,
 when there is more than one at all. The tuner is solely determined by
 the current video input. Drivers must support both ioctls and set the
@@ -491,8 +491,17 @@ the modulator. The <structfield>type</structfield> field of the
 respective &v4l2-output; returned by the &VIDIOC-ENUMOUTPUT; ioctl is
 set to <constant>V4L2_OUTPUT_TYPE_MODULATOR</constant> and its
 <structfield>modulator</structfield> field contains the index number
-of the modulator. This specification does not define radio output
-devices.</para>
+of the modulator.</para>
+
+      <para>Radio output devices have exactly one modulator with index
+zero, no video outputs.</para>
+
+      <para>A video or radio device cannot support both a tuner and a
+modulator. Two separate device nodes will have to be used for such
+hardware, one that supports the tuner functionality and one that supports
+the modulator functionality. The reason is a limitation with the
+&VIDIOC-S-FREQUENCY; ioctl where you cannot specify whether the frequency
+is for a tuner or a modulator.</para>
 
       <para>To query and change modulator properties applications use
 the &VIDIOC-G-MODULATOR; and &VIDIOC-S-MODULATOR; ioctl. Note that
index ea42ef824948cd6392189328faa65725c22013f8..97b895151bb02d76fabdb63e97e9d807947ea872 100644 (file)
@@ -2377,10 +2377,11 @@ that used it. It was originally scheduled for removal in 2.6.35.
          <para>V4L2_CTRL_FLAG_VOLATILE was added to signal volatile controls to userspace.</para>
         </listitem>
         <listitem>
-         <para>Add selection API for extended control over cropping and
-composing. Does not affect the compatibility of current drivers and
-applications.  See <link linkend="selection-api"> selection API </link> for
-details.</para>
+         <para>Add selection API for extended control over cropping
+         and composing. Does not affect the compatibility of current
+         drivers and applications. See <link
+         linkend="selection-api"> selection API </link> for
+         details.</para>
         </listitem>
       </orderedlist>
     </section>
@@ -2458,6 +2459,18 @@ details.</para>
       </orderedlist>
     </section>
 
+    <section>
+      <title>V4L2 in Linux 3.5</title>
+      <orderedlist>
+       <listitem>
+         <para>Replaced <structfield>input</structfield> in
+         <structname>v4l2_buffer</structname> by
+         <structfield>reserved2</structfield> and removed
+         <constant>V4L2_BUF_FLAG_INPUT</constant>.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
     <section id="other">
       <title>Relation of V4L2 to other Linux multimedia APIs</title>
 
index 4afcbbec5eda6c7146a497646ec36345ce4ef2bf..a3d9dd093268747de3751dcc41001e1fba638b11 100644 (file)
       </para>
     </section>
 
-    <section>
+    <section id="v4l2-subdev-selections">
       <title>Selections: cropping, scaling and composition</title>
 
       <para>Many sub-devices support cropping frames on their input or output
       size. Both the coordinates and sizes are expressed in pixels.</para>
 
       <para>As for pad formats, drivers store try and active
-      rectangles for the selection targets of ACTUAL type <xref
-      linkend="v4l2-subdev-selection-targets">.</xref></para>
+      rectangles for the selection targets <xref
+      linkend="v4l2-selections-common" />.</para>
 
       <para>On sink pads, cropping is applied relative to the
       current pad format. The pad format represents the image size as
       <para>Scaling support is optional. When supported by a subdev,
       the crop rectangle on the subdev's sink pad is scaled to the
       size configured using the &VIDIOC-SUBDEV-S-SELECTION; IOCTL
-      using <constant>V4L2_SUBDEV_SEL_COMPOSE_ACTUAL</constant>
+      using <constant>V4L2_SEL_TGT_COMPOSE</constant>
       selection target on the same pad. If the subdev supports scaling
       but not composing, the top and left values are not used and must
       always be set to zero.</para>
       <para>The drivers should always use the closest possible
       rectangle the user requests on all selection targets, unless
       specifically told otherwise.
-      <constant>V4L2_SUBDEV_SEL_FLAG_SIZE_GE</constant> and
-      <constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant> flags may be
+      <constant>V4L2_SEL_FLAG_GE</constant> and
+      <constant>V4L2_SEL_FLAG_LE</constant> flags may be
       used to round the image size either up or down. <xref
-      linkend="v4l2-subdev-selection-flags"></xref></para>
+      linkend="v4l2-selection-flags" /></para>
     </section>
 
     <section>
       <title>Types of selection targets</title>
 
       <section>
-       <title>ACTUAL targets</title>
+       <title>Actual targets</title>
 
-       <para>ACTUAL targets reflect the actual hardware configuration
-       at any point of time. There is a BOUNDS target
-       corresponding to every ACTUAL.</para>
+       <para>Actual targets (without a postfix) reflect the actual
+       hardware configuration at any point of time. There is a BOUNDS
+       target corresponding to every actual target.</para>
       </section>
 
       <section>
        <title>BOUNDS targets</title>
 
-       <para>BOUNDS targets is the smallest rectangle that contains
-       all valid ACTUAL rectangles. It may not be possible to set the
-       ACTUAL rectangle as large as the BOUNDS rectangle, however.
-       This may be because e.g. a sensor's pixel array is not
-       rectangular but cross-shaped or round. The maximum size may
-       also be smaller than the BOUNDS rectangle.</para>
+       <para>BOUNDS targets is the smallest rectangle that contains all
+       valid actual rectangles. It may not be possible to set the actual
+       rectangle as large as the BOUNDS rectangle, however. This may be
+       because e.g. a sensor's pixel array is not rectangular but
+       cross-shaped or round. The maximum size may also be smaller than the
+       BOUNDS rectangle.</para>
       </section>
 
     </section>
       performed by the user: the changes made will be propagated to
       any subsequent stages. If this behaviour is not desired, the
       user must set
-      <constant>V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG</constant> flag. This
+      <constant>V4L2_SEL_FLAG_KEEP_CONFIG</constant> flag. This
       flag causes no propagation of the changes are allowed in any
       circumstances. This may also cause the accessed rectangle to be
       adjusted by the driver, depending on the properties of the
index fd6aca2922b64994f283f2d3f0820f7f10541824..1885cc0755cb48a438aadfe686857f46ee541172 100644 (file)
@@ -683,14 +683,12 @@ memory, set by the application. See <xref linkend="userp" /> for details.
          </row>
          <row>
            <entry>__u32</entry>
-           <entry><structfield>input</structfield></entry>
+           <entry><structfield>reserved2</structfield></entry>
            <entry></entry>
-           <entry>Some video capture drivers support rapid and
-synchronous video input changes, a function useful for example in
-video surveillance applications. For this purpose applications set the
-<constant>V4L2_BUF_FLAG_INPUT</constant> flag, and this field to the
-number of a video input as in &v4l2-input; field
-<structfield>index</structfield>.</entry>
+           <entry>A place holder for future extensions and custom
+(driver defined) buffer types
+<constant>V4L2_BUF_TYPE_PRIVATE</constant> and higher. Applications
+should set this to 0.</entry>
          </row>
          <row>
            <entry>__u32</entry>
@@ -921,13 +919,6 @@ previous key frame.</entry>
            <entry>The <structfield>timecode</structfield> field is valid.
 Drivers set or clear this flag when the <constant>VIDIOC_DQBUF</constant>
 ioctl is called.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_INPUT</constant></entry>
-           <entry>0x0200</entry>
-           <entry>The <structfield>input</structfield> field is valid.
-Applications set or clear this flag before calling the
-<constant>VIDIOC_QBUF</constant> ioctl.</entry>
          </row>
          <row>
            <entry><constant>V4L2_BUF_FLAG_PREPARED</constant></entry>
index b299e4779354afac2ba9a2891ad1699fcfd313b0..e7ed5077834deaa027fe1a202a555631338dba15 100644 (file)
@@ -53,11 +53,11 @@ cropping and composing rectangles have the same size.</para>
        </mediaobject>
       </figure>
 
-For complete list of the available selection targets see table <xref
-linkend="v4l2-sel-target"/>
-
     </section>
 
+    See <xref linkend="v4l2-selection-targets" /> for more
+    information.
+
   <section>
 
   <title>Configuration</title>
@@ -74,7 +74,7 @@ cropping/composing rectangles may have to be aligned, and both the source and
 the sink may have arbitrary upper and lower size limits. Therefore, as usual,
 drivers are expected to adjust the requested parameters and return the actual
 values selected. An application can control the rounding behaviour using <link
-linkend="v4l2-sel-flags"> constraint flags </link>.</para>
+linkend="v4l2-selection-flags"> constraint flags </link>.</para>
 
    <section>
 
@@ -91,7 +91,7 @@ top/left corner at position <constant> (0,0) </constant>.  The rectangle's
 coordinates are expressed in pixels.</para>
 
 <para>The top left corner, width and height of the source rectangle, that is
-the area actually sampled, is given by the <constant> V4L2_SEL_TGT_CROP_ACTIVE
+the area actually sampled, is given by the <constant> V4L2_SEL_TGT_CROP
 </constant> target. It uses the same coordinate system as <constant>
 V4L2_SEL_TGT_CROP_BOUNDS </constant>. The active cropping area must lie
 completely inside the capture boundaries. The driver may further adjust the
@@ -111,13 +111,13 @@ height are equal to the image size set by <constant> VIDIOC_S_FMT </constant>.
 </para>
 
 <para>The part of a buffer into which the image is inserted by the hardware is
-controlled by the <constant> V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target.
+controlled by the <constant> V4L2_SEL_TGT_COMPOSE </constant> target.
 The rectangle's coordinates are also expressed in the same coordinate system as
 the bounds rectangle. The composing rectangle must lie completely inside bounds
 rectangle. The driver must adjust the composing rectangle to fit to the
 bounding limits. Moreover, the driver can perform other adjustments according
 to hardware limitations. The application can control rounding behaviour using
-<link linkend="v4l2-sel-flags"> constraint flags </link>.</para>
+<link linkend="v4l2-selection-flags"> constraint flags </link>.</para>
 
 <para>For capture devices the default composing rectangle is queried using
 <constant> V4L2_SEL_TGT_COMPOSE_DEFAULT </constant>. It is usually equal to the
@@ -125,7 +125,7 @@ bounding rectangle.</para>
 
 <para>The part of a buffer that is modified by the hardware is given by
 <constant> V4L2_SEL_TGT_COMPOSE_PADDED </constant>. It contains all pixels
-defined using <constant> V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> plus all
+defined using <constant> V4L2_SEL_TGT_COMPOSE </constant> plus all
 padding data modified by hardware during insertion process. All pixels outside
 this rectangle <emphasis>must not</emphasis> be changed by the hardware. The
 content of pixels that lie inside the padded area but outside active area is
@@ -153,7 +153,7 @@ specified using <constant> VIDIOC_S_FMT </constant> ioctl.</para>
 
 <para>The top left corner, width and height of the source rectangle, that is
 the area from which image date are processed by the hardware, is given by the
-<constant> V4L2_SEL_TGT_CROP_ACTIVE </constant>. Its coordinates are expressed
+<constant> V4L2_SEL_TGT_CROP </constant>. Its coordinates are expressed
 in in the same coordinate system as the bounds rectangle. The active cropping
 area must lie completely inside the crop boundaries and the driver may further
 adjust the requested size and/or position according to hardware
@@ -165,7 +165,7 @@ bounding rectangle.</para>
 
 <para>The part of a video signal or graphics display where the image is
 inserted by the hardware is controlled by <constant>
-V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target.  The rectangle's coordinates
+V4L2_SEL_TGT_COMPOSE </constant> target.  The rectangle's coordinates
 are expressed in pixels. The composing rectangle must lie completely inside the
 bounds rectangle.  The driver must adjust the area to fit to the bounding
 limits.  Moreover, the driver can perform other adjustments according to
@@ -184,7 +184,7 @@ such a padded area is driver-dependent feature not covered by this document.
 Driver developers are encouraged to keep padded rectangle equal to active one.
 The padded target is accessed by the <constant> V4L2_SEL_TGT_COMPOSE_PADDED
 </constant> identifier.  It must contain all pixels from the <constant>
-V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target.</para>
+V4L2_SEL_TGT_COMPOSE </constant> target.</para>
 
    </section>
 
@@ -193,8 +193,8 @@ V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target.</para>
      <title>Scaling control</title>
 
 <para>An application can detect if scaling is performed by comparing the width
-and the height of rectangles obtained using <constant> V4L2_SEL_TGT_CROP_ACTIVE
-</constant> and <constant> V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> targets. If
+and the height of rectangles obtained using <constant> V4L2_SEL_TGT_CROP
+</constant> and <constant> V4L2_SEL_TGT_COMPOSE </constant> targets. If
 these are not equal then the scaling is applied. The application can compute
 the scaling ratios using these values.</para>
 
@@ -252,7 +252,7 @@ area)</para>
        ret = ioctl(fd, &VIDIOC-G-SELECTION;, &amp;sel);
        if (ret)
                exit(-1);
-       sel.target = V4L2_SEL_TGT_CROP_ACTIVE;
+       sel.target = V4L2_SEL_TGT_CROP;
        ret = ioctl(fd, &VIDIOC-S-SELECTION;, &amp;sel);
        if (ret)
                exit(-1);
@@ -281,7 +281,7 @@ area)</para>
        r.left = sel.r.width / 4;
        r.top = sel.r.height / 4;
        sel.r = r;
-       sel.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
+       sel.target = V4L2_SEL_TGT_COMPOSE;
        sel.flags = V4L2_SEL_FLAG_LE;
        ret = ioctl(fd, &VIDIOC-S-SELECTION;, &amp;sel);
        if (ret)
@@ -298,11 +298,11 @@ V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> for other devices</para>
 
        &v4l2-selection; compose = {
                .type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
-               .target = V4L2_SEL_TGT_COMPOSE_ACTIVE,
+               .target = V4L2_SEL_TGT_COMPOSE,
        };
        &v4l2-selection; crop = {
                .type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
-               .target = V4L2_SEL_TGT_CROP_ACTIVE,
+               .target = V4L2_SEL_TGT_CROP,
        };
        double hscale, vscale;
 
diff --git a/Documentation/DocBook/media/v4l/selections-common.xml b/Documentation/DocBook/media/v4l/selections-common.xml
new file mode 100644 (file)
index 0000000..7502f78
--- /dev/null
@@ -0,0 +1,164 @@
+<section id="v4l2-selections-common">
+
+  <title>Common selection definitions</title>
+
+  <para>While the <link linkend="selection-api">V4L2 selection
+  API</link> and <link linkend="v4l2-subdev-selections">V4L2 subdev
+  selection APIs</link> are very similar, there's one fundamental
+  difference between the two. On sub-device API, the selection
+  rectangle refers to the media bus format, and is bound to a
+  sub-device's pad. On the V4L2 interface the selection rectangles
+  refer to the in-memory pixel format.</para>
+
+  <para>This section defines the common definitions of the
+  selection interfaces on the two APIs.</para>
+
+  <section id="v4l2-selection-targets">
+
+    <title>Selection targets</title>
+
+    <para>The precise meaning of the selection targets may be
+    dependent on which of the two interfaces they are used.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-selection-targets-table">
+    <title>Selection target definitions</title>
+      <tgroup cols="5">
+       <colspec colname="c1" />
+       <colspec colname="c2" />
+       <colspec colname="c3" />
+       <colspec colname="c4" />
+       <colspec colname="c5" />
+       &cs-def;
+       <thead>
+         <row rowsep="1">
+           <entry align="left">Target name</entry>
+           <entry align="left">id</entry>
+           <entry align="left">Definition</entry>
+           <entry align="left">Valid for V4L2</entry>
+           <entry align="left">Valid for V4L2 subdev</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_SEL_TGT_CROP</constant></entry>
+           <entry>0x0000</entry>
+           <entry>Crop rectangle. Defines the cropped area.</entry>
+           <entry>Yes</entry>
+           <entry>Yes</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SEL_TGT_CROP_DEFAULT</constant></entry>
+           <entry>0x0001</entry>
+           <entry>Suggested cropping rectangle that covers the "whole picture".</entry>
+           <entry>Yes</entry>
+           <entry>No</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SEL_TGT_CROP_BOUNDS</constant></entry>
+           <entry>0x0002</entry>
+           <entry>Bounds of the crop rectangle. All valid crop
+           rectangles fit inside the crop bounds rectangle.
+           </entry>
+           <entry>Yes</entry>
+           <entry>Yes</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SEL_TGT_COMPOSE</constant></entry>
+           <entry>0x0100</entry>
+           <entry>Compose rectangle. Used to configure scaling
+           and composition.</entry>
+           <entry>Yes</entry>
+           <entry>Yes</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SEL_TGT_COMPOSE_DEFAULT</constant></entry>
+           <entry>0x0101</entry>
+           <entry>Suggested composition rectangle that covers the "whole picture".</entry>
+           <entry>Yes</entry>
+           <entry>No</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SEL_TGT_COMPOSE_BOUNDS</constant></entry>
+           <entry>0x0102</entry>
+           <entry>Bounds of the compose rectangle. All valid compose
+           rectangles fit inside the compose bounds rectangle.</entry>
+           <entry>Yes</entry>
+           <entry>Yes</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant></entry>
+           <entry>0x0103</entry>
+           <entry>The active area and all padding pixels that are inserted or
+           modified by hardware.</entry>
+           <entry>Yes</entry>
+           <entry>No</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+  </section>
+
+  <section id="v4l2-selection-flags">
+
+    <title>Selection flags</title>
+
+    <table pgwide="1" frame="none" id="v4l2-selection-flags-table">
+    <title>Selection flag definitions</title>
+      <tgroup cols="5">
+       <colspec colname="c1" />
+       <colspec colname="c2" />
+       <colspec colname="c3" />
+       <colspec colname="c4" />
+       <colspec colname="c5" />
+       &cs-def;
+       <thead>
+       <row rowsep="1">
+           <entry align="left">Flag name</entry>
+           <entry align="left">id</entry>
+           <entry align="left">Definition</entry>
+           <entry align="left">Valid for V4L2</entry>
+           <entry align="left">Valid for V4L2 subdev</entry>
+       </row>
+       </thead>
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_SEL_FLAG_GE</constant></entry>
+           <entry>(1 &lt;&lt; 0)</entry>
+           <entry>Suggest the driver it should choose greater or
+           equal rectangle (in size) than was requested. Albeit the
+           driver may choose a lesser size, it will only do so due to
+           hardware limitations. Without this flag (and
+           <constant>V4L2_SEL_FLAG_LE</constant>) the
+           behaviour is to choose the closest possible
+           rectangle.</entry>
+           <entry>Yes</entry>
+           <entry>Yes</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SEL_FLAG_LE</constant></entry>
+           <entry>(1 &lt;&lt; 1)</entry>
+           <entry>Suggest the driver it
+           should choose lesser or equal rectangle (in size) than was
+           requested. Albeit the driver may choose a greater size, it
+           will only do so due to hardware limitations.</entry>
+           <entry>Yes</entry>
+           <entry>Yes</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SEL_FLAG_KEEP_CONFIG</constant></entry>
+           <entry>(1 &lt;&lt; 2)</entry>
+           <entry>The configuration must not be propagated to any
+           further processing steps. If this flag is not given, the
+           configuration is propagated inside the subdevice to all
+           further processing steps.</entry>
+           <entry>No</entry>
+           <entry>Yes</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+  </section>
+
+</section>
index 008c2d73a484622d8343752391fd5312c3ff2793..36bafc48e03baa86890d1cf2c062c825be55a35c 100644 (file)
@@ -589,6 +589,11 @@ and discussions on the V4L mailing list.</revremark>
     &sub-write;
   </appendix>
 
+  <appendix>
+    <title>Common definitions for V4L2 and V4L2 subdev interfaces</title>
+      &sub-selections-common;
+  </appendix>
+
   <appendix id="videodev">
     <title>Video For Linux Two Header File</title>
     &sub-videodev2-h;
index a2474ecb574acd06c533f7a22bd4c5fbccacc4c6..5e73b1c8d09543183d3c388916a29f8d91dfdd0f 100644 (file)
@@ -97,7 +97,13 @@ information.</para>
          <row>
            <entry>__u32</entry>
            <entry><structfield>count</structfield></entry>
-           <entry>The number of buffers requested or granted.</entry>
+           <entry>The number of buffers requested or granted. If count == 0, then
+           <constant>VIDIOC_CREATE_BUFS</constant> will set <structfield>index</structfield>
+           to the current number of created buffers, and it will check the validity of
+           <structfield>memory</structfield> and <structfield>format.type</structfield>.
+           If those are invalid -1 is returned and errno is set to &EINVAL;,
+           otherwise <constant>VIDIOC_CREATE_BUFS</constant> returns 0. It will
+           never set errno to &EBUSY; in this particular case.</entry>
          </row>
          <row>
            <entry>__u32</entry>
index 69c178a4d20546d5c54f767df0c32158f7e222df..40e58a42eb26d55123ccf1153d702eb1b9a70953 100644 (file)
@@ -135,6 +135,12 @@ bounds or the value in the <structfield>type</structfield> field is
 wrong.</para>
        </listitem>
       </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>A hardware seek is in progress.</para>
+       </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
index bb04eff75f45440fa338d316911b7d8b7a79e75c..f76d8a6d9b92df2133babc08456ac3bfc4d9c171 100644 (file)
@@ -65,9 +65,9 @@ Do not use multiplanar buffers.  Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
 </constant>.  Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of
 <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>.  The next step is
 setting the value of &v4l2-selection; <structfield>target</structfield> field
-to <constant> V4L2_SEL_TGT_CROP_ACTIVE </constant> (<constant>
-V4L2_SEL_TGT_COMPOSE_ACTIVE </constant>).  Please refer to table <xref
-linkend="v4l2-sel-target" /> or <xref linkend="selection-api" /> for additional
+to <constant> V4L2_SEL_TGT_CROP </constant> (<constant>
+V4L2_SEL_TGT_COMPOSE </constant>).  Please refer to table <xref
+linkend="v4l2-selections-common" /> or <xref linkend="selection-api" /> for additional
 targets.  The <structfield>flags</structfield> and <structfield>reserved
 </structfield> fields of &v4l2-selection; are ignored and they must be filled
 with zeros.  The driver fills the rest of the structure or
@@ -86,9 +86,9 @@ use multiplanar buffers.  Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
 </constant>.  Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of
 <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>.  The next step is
 setting the value of &v4l2-selection; <structfield>target</structfield> to
-<constant>V4L2_SEL_TGT_CROP_ACTIVE</constant> (<constant>
-V4L2_SEL_TGT_COMPOSE_ACTIVE </constant>). Please refer to table <xref
-linkend="v4l2-sel-target" /> or <xref linkend="selection-api" /> for additional
+<constant>V4L2_SEL_TGT_CROP</constant> (<constant>
+V4L2_SEL_TGT_COMPOSE </constant>). Please refer to table <xref
+linkend="v4l2-selections-common" /> or <xref linkend="selection-api" /> for additional
 targets.  The &v4l2-rect; <structfield>r</structfield> rectangle need to be
 set to the desired active area. Field &v4l2-selection; <structfield> reserved
 </structfield> is ignored and must be filled with zeros.  The driver may adjust
@@ -154,74 +154,8 @@ exist no rectangle </emphasis> that satisfies the constraints.</para>
 
   </refsect1>
 
-  <refsect1>
-    <table frame="none" pgwide="1" id="v4l2-sel-target">
-      <title>Selection targets.</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-            <entry><constant>V4L2_SEL_TGT_CROP_ACTIVE</constant></entry>
-            <entry>0x0000</entry>
-            <entry>The area that is currently cropped by hardware.</entry>
-         </row>
-         <row>
-            <entry><constant>V4L2_SEL_TGT_CROP_DEFAULT</constant></entry>
-            <entry>0x0001</entry>
-            <entry>Suggested cropping rectangle that covers the "whole picture".</entry>
-         </row>
-         <row>
-            <entry><constant>V4L2_SEL_TGT_CROP_BOUNDS</constant></entry>
-            <entry>0x0002</entry>
-            <entry>Limits for the cropping rectangle.</entry>
-         </row>
-         <row>
-            <entry><constant>V4L2_SEL_TGT_COMPOSE_ACTIVE</constant></entry>
-            <entry>0x0100</entry>
-            <entry>The area to which data is composed by hardware.</entry>
-         </row>
-         <row>
-            <entry><constant>V4L2_SEL_TGT_COMPOSE_DEFAULT</constant></entry>
-            <entry>0x0101</entry>
-            <entry>Suggested composing rectangle that covers the "whole picture".</entry>
-         </row>
-         <row>
-            <entry><constant>V4L2_SEL_TGT_COMPOSE_BOUNDS</constant></entry>
-            <entry>0x0102</entry>
-            <entry>Limits for the composing rectangle.</entry>
-         </row>
-         <row>
-            <entry><constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant></entry>
-            <entry>0x0103</entry>
-            <entry>The active area and all padding pixels that are inserted or modified by hardware.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    <table frame="none" pgwide="1" id="v4l2-sel-flags">
-      <title>Selection constraint flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-            <entry><constant>V4L2_SEL_FLAG_GE</constant></entry>
-            <entry>0x00000001</entry>
-            <entry>Indicates that the adjusted rectangle must contain the original
-           &v4l2-selection; <structfield>r</structfield> rectangle.</entry>
-         </row>
-         <row>
-            <entry><constant>V4L2_SEL_FLAG_LE</constant></entry>
-            <entry>0x00000002</entry>
-            <entry>Indicates that the adjusted rectangle must be inside the original
-           &v4l2-rect; <structfield>r</structfield> rectangle.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
+  <para>Selection targets and flags are documented in <xref
+  linkend="v4l2-selections-common"/>.</para>
 
     <section>
       <figure id="sel-const-adjust">
@@ -252,14 +186,14 @@ exist no rectangle </emphasis> that satisfies the constraints.</para>
          <row>
            <entry>__u32</entry>
            <entry><structfield>target</structfield></entry>
-            <entry>Used to select between <link linkend="v4l2-sel-target"> cropping
+            <entry>Used to select between <link linkend="v4l2-selections-common"> cropping
            and composing rectangles</link>.</entry>
          </row>
          <row>
            <entry>__u32</entry>
            <entry><structfield>flags</structfield></entry>
             <entry>Flags controlling the selection rectangle adjustments, refer to
-           <link linkend="v4l2-sel-flags">selection flags</link>.</entry>
+           <link linkend="v4l2-selection-flags">selection flags</link>.</entry>
          </row>
          <row>
            <entry>&v4l2-rect;</entry>
index 62a1aa200a36ccfd5dd59fe132de8ddfb57e2724..95d5371c17090af4ff0c9ba1e51aa3a0dbdc0d98 100644 (file)
@@ -275,6 +275,18 @@ can or must be switched. (B/G PAL tuners for example are typically not
       see the description of ioctl &VIDIOC-ENUMINPUT; for details. Only
       <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</entry>
          </row>
+         <row>
+           <entry><constant>V4L2_TUNER_CAP_HWSEEK_BOUNDED</constant></entry>
+           <entry>0x0004</entry>
+           <entry>If set, then this tuner supports the hardware seek functionality
+           where the seek stops when it reaches the end of the frequency range.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_CAP_HWSEEK_WRAP</constant></entry>
+           <entry>0x0008</entry>
+           <entry>If set, then this tuner supports the hardware seek functionality
+           where the seek wraps around when it reaches the end of the frequency range.</entry>
+         </row>
          <row>
        <entry><constant>V4L2_TUNER_CAP_STEREO</constant></entry>
        <entry>0x0010</entry>
index 9caa49af580fe2a2ae5607a30f1a5d2141ff072a..77ff5be0809d13ef530ff07718e243aab98358fc 100644 (file)
@@ -71,12 +71,9 @@ initialize the <structfield>bytesused</structfield>,
 <structfield>field</structfield> and
 <structfield>timestamp</structfield> fields, see <xref
 linkend="buffer" /> for details.
-Applications must also set <structfield>flags</structfield> to 0. If a driver
-supports capturing from specific video inputs and you want to specify a video
-input, then <structfield>flags</structfield> should be set to
-<constant>V4L2_BUF_FLAG_INPUT</constant> and the field
-<structfield>input</structfield> must be initialized to the desired input.
-The <structfield>reserved</structfield> field must be set to 0. When using
+Applications must also set <structfield>flags</structfield> to 0.
+The <structfield>reserved2</structfield> and
+<structfield>reserved</structfield> fields must be set to 0. When using
 the <link linkend="planar-apis">multi-planar API</link>, the
 <structfield>m.planes</structfield> field must contain a userspace pointer
 to a filled-in array of &v4l2-plane; and the <structfield>length</structfield>
index 407dfceb71f0c29fcc8cfd7d2a29cabc2e305ba1..f4db44d0d95a8c0b065bf99dccae34b63c70a6af 100644 (file)
@@ -58,6 +58,9 @@ To do this applications initialize the <structfield>tuner</structfield>,
 call the <constant>VIDIOC_S_HW_FREQ_SEEK</constant> ioctl with a pointer
 to this structure.</para>
 
+    <para>If an error is returned, then the original frequency will
+    be restored.</para>
+
     <para>This ioctl is supported if the <constant>V4L2_CAP_HW_FREQ_SEEK</constant> capability is set.</para>
 
     <table pgwide="1" frame="none" id="v4l2-hw-freq-seek">
@@ -87,7 +90,10 @@ field and the &v4l2-tuner; <structfield>index</structfield> field.</entry>
          <row>
            <entry>__u32</entry>
            <entry><structfield>wrap_around</structfield></entry>
-           <entry>If non-zero, wrap around when at the end of the frequency range, else stop seeking.</entry>
+           <entry>If non-zero, wrap around when at the end of the frequency range, else stop seeking.
+           The &v4l2-tuner; <structfield>capability</structfield> field will tell you what the
+           hardware supports.
+           </entry>
          </row>
          <row>
            <entry>__u32</entry>
@@ -118,9 +124,15 @@ wrong.</para>
        </listitem>
       </varlistentry>
       <varlistentry>
-       <term><errorcode>EAGAIN</errorcode></term>
+       <term><errorcode>ENODATA</errorcode></term>
+       <listitem>
+         <para>The hardware seek found no channels.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
        <listitem>
-         <para>The ioctl timed-out. Try again.</para>
+         <para>Another hardware seek is already in progress.</para>
        </listitem>
       </varlistentry>
     </variablelist>
index 208e9f0da3f30440e67d0c744b5ab92bdd51f582..f33cc814a01d14d07483a04051f4513ace88876c 100644 (file)
     <section>
       <title>Types of selection targets</title>
 
-      <para>There are two types of selection targets: actual and bounds.
-      The ACTUAL targets are the targets which configure the hardware.
-      The BOUNDS target will return a rectangle that contain all
-      possible ACTUAL rectangles.</para>
+      <para>There are two types of selection targets: actual and bounds. The
+      actual targets are the targets which configure the hardware. The BOUNDS
+      target will return a rectangle that contain all possible actual
+      rectangles.</para>
     </section>
 
     <section>
       <constant>EINVAL</constant>.</para>
     </section>
 
-    <table pgwide="1" frame="none" id="v4l2-subdev-selection-targets">
-      <title>V4L2 subdev selection targets</title>
-      <tgroup cols="3">
-        &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL</constant></entry>
-           <entry>0x0000</entry>
-           <entry>Actual crop. Defines the cropping
-           performed by the processing step.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS</constant></entry>
-           <entry>0x0002</entry>
-           <entry>Bounds of the crop rectangle.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL</constant></entry>
-           <entry>0x0100</entry>
-           <entry>Actual compose rectangle. Used to configure scaling
-           on sink pads and composition on source pads.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS</constant></entry>
-           <entry>0x0102</entry>
-           <entry>Bounds of the compose rectangle.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-selection-flags">
-      <title>V4L2 subdev selection flags</title>
-      <tgroup cols="3">
-        &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_GE</constant></entry>
-           <entry>(1 &lt;&lt; 0)</entry> <entry>Suggest the driver it
-           should choose greater or equal rectangle (in size) than
-           was requested. Albeit the driver may choose a lesser size,
-           it will only do so due to hardware limitations. Without
-           this flag (and
-           <constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant>) the
-           behaviour is to choose the closest possible
-           rectangle.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant></entry>
-           <entry>(1 &lt;&lt; 1)</entry> <entry>Suggest the driver it
-           should choose lesser or equal rectangle (in size) than was
-           requested. Albeit the driver may choose a greater size, it
-           will only do so due to hardware limitations.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG</constant></entry>
-           <entry>(1 &lt;&lt; 2)</entry>
-           <entry>The configuration should not be propagated to any
-           further processing steps. If this flag is not given, the
-           configuration is propagated inside the subdevice to all
-           further processing steps.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
+    <para>Selection targets and flags are documented in <xref
+    linkend="v4l2-selections-common"/>.</para>
 
     <table pgwide="1" frame="none" id="v4l2-subdev-selection">
       <title>struct <structname>v4l2_subdev_selection</structname></title>
            <entry>__u32</entry>
            <entry><structfield>target</structfield></entry>
            <entry>Target selection rectangle. See
-           <xref linkend="v4l2-subdev-selection-targets">.</xref>.</entry>
+           <xref linkend="v4l2-selections-common" />.</entry>
          </row>
          <row>
            <entry>__u32</entry>
            <entry><structfield>flags</structfield></entry>
            <entry>Flags. See
-           <xref linkend="v4l2-subdev-selection-flags">.</xref></entry>
+           <xref linkend="v4l2-selection-flags" />.</entry>
          </row>
          <row>
            <entry>&v4l2-rect;</entry>
index f34d3236b9da838e0a3e81516e135b914f5577ee..45f3b91ea4c3259ba19388b40935d60f276ff6ec 100644 (file)
@@ -9,15 +9,14 @@ devices in parallel.
 
 Parameters: <num devs> <chunk size> [<dev path> <offset>]+
     <num devs>: Number of underlying devices.
-    <chunk size>: Size of each chunk of data. Must be a power-of-2 and at
-                  least as large as the system's PAGE_SIZE.
+    <chunk size>: Size of each chunk of data. Must be at least as
+                  large as the system's PAGE_SIZE.
     <dev path>: Full pathname to the underlying block-device, or a
                 "major:minor" device-number.
     <offset>: Starting sector within the device.
 
 One or more underlying devices can be specified. The striped device size must
-be a multiple of the chunk size and a multiple of the number of underlying
-devices.
+be a multiple of the chunk size multiplied by the number of underlying devices.
 
 
 Example scripts
index f5cfc62b7ad3fa2bfbb50fb3f33339e1d402a575..30b8b83bd333401a2cc1138d664d6086b4d47aef 100644 (file)
@@ -231,6 +231,9 @@ i) Constructor
       no_discard_passdown: Don't pass discards down to the underlying
                           data device, but just remove the mapping.
 
+      read_only: Don't allow any changes to be made to the pool
+                metadata.
+
     Data block size must be between 64KB (128 sectors) and 1GB
     (2097152 sectors) inclusive.
 
@@ -239,7 +242,7 @@ ii) Status
 
     <transaction id> <used metadata blocks>/<total metadata blocks>
     <used data blocks>/<total data blocks> <held metadata root>
-
+    [no_]discard_passdown ro|rw
 
     transaction id:
        A 64-bit number used by userspace to help synchronise with metadata
@@ -257,6 +260,21 @@ ii) Status
        held root.  This feature is not yet implemented so '-' is
        always returned.
 
+    discard_passdown|no_discard_passdown
+       Whether or not discards are actually being passed down to the
+       underlying device.  When this is enabled when loading the table,
+       it can get disabled if the underlying device doesn't support it.
+
+    ro|rw
+       If the pool encounters certain types of device failures it will
+       drop into a read-only metadata mode in which no changes to
+       the pool metadata (like allocating new blocks) are permitted.
+
+       In serious cases where even a read-only mode is deemed unsafe
+       no further I/O will be permitted and the status will just
+       contain the string 'Fail'.  The userspace recovery tools
+       should then be used.
+
 iii) Messages
 
     create_thin <dev id>
@@ -329,3 +347,7 @@ regain some space then send the 'trim' message to the pool.
 ii) Status
 
      <nr mapped sectors> <highest mapped sector>
+
+       If the pool has encountered device errors and failed, the status
+       will just contain the string 'Fail'.  The userspace recovery
+       tools should then be used.
diff --git a/Documentation/devicetree/bindings/arm/calxeda/l2ecc.txt b/Documentation/devicetree/bindings/arm/calxeda/l2ecc.txt
new file mode 100644 (file)
index 0000000..94e642a
--- /dev/null
@@ -0,0 +1,15 @@
+Calxeda Highbank L2 cache ECC
+
+Properties:
+- compatible : Should be "calxeda,hb-sregs-l2-ecc"
+- reg : Address and size for ECC error interrupt clear registers.
+- interrupts : Should be single bit error interrupt, then double bit error
+       interrupt.
+
+Example:
+
+       sregs@fff3c200 {
+               compatible = "calxeda,hb-sregs-l2-ecc";
+               reg = <0xfff3c200 0x100>;
+               interrupts = <0 71 4  0 72 4>;
+       };
diff --git a/Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt b/Documentation/devicetree/bindings/arm/calxeda/mem-ctrlr.txt
new file mode 100644 (file)
index 0000000..f770ac0
--- /dev/null
@@ -0,0 +1,14 @@
+Calxeda DDR memory controller
+
+Properties:
+- compatible : Should be "calxeda,hb-ddr-ctrl"
+- reg : Address and size for DDR controller registers.
+- interrupts : Interrupt for DDR controller.
+
+Example:
+
+       memory-controller@fff00000 {
+               compatible = "calxeda,hb-ddr-ctrl";
+               reg = <0xfff00000 0x1000>;
+               interrupts = <0 91 4>;
+       };
diff --git a/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt b/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt
new file mode 100644 (file)
index 0000000..93986a5
--- /dev/null
@@ -0,0 +1,30 @@
+* Compact Flash
+
+The Cavium Compact Flash device is connected to the Octeon Boot Bus,
+and is thus a child of the Boot Bus device.  It can read and write
+industry standard compact flash devices.
+
+Properties:
+- compatible: "cavium,ebt3000-compact-flash";
+
+  Compatibility with many Cavium evaluation boards.
+
+- reg: The base address of the the CF chip select banks.  Depending on
+  the device configuration, there may be one or two banks.
+
+- cavium,bus-width: The width of the connection to the CF devices.  Valid
+  values are 8 and 16.
+
+- cavium,true-ide: Optional, if present the CF connection is in True IDE mode.
+
+- cavium,dma-engine-handle: Optional, a phandle for the DMA Engine connected
+  to this device.
+
+Example:
+       compact-flash@5,0 {
+               compatible = "cavium,ebt3000-compact-flash";
+               reg = <5 0 0x10000>, <6 0 0x10000>;
+               cavium,bus-width = <16>;
+               cavium,true-ide;
+               cavium,dma-engine-handle = <&dma0>;
+       };
diff --git a/Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt b/Documentation/devicetree/bindings/gpio/cavium-octeon-gpio.txt
new file mode 100644 (file)
index 0000000..9d6dcd3
--- /dev/null
@@ -0,0 +1,49 @@
+* General Purpose Input Output (GPIO) bus.
+
+Properties:
+- compatible: "cavium,octeon-3860-gpio"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The base address of the GPIO unit's register bank.
+
+- gpio-controller: This is a GPIO controller.
+
+- #gpio-cells: Must be <2>.  The first cell is the GPIO pin.
+
+- interrupt-controller: The GPIO controller is also an interrupt
+  controller, many of its pins may be configured as an interrupt
+  source.
+
+- #interrupt-cells: Must be <2>.  The first cell is the GPIO pin
+   connected to the interrupt source.  The second cell is the interrupt
+   triggering protocol and may have one of four values:
+   1 - edge triggered on the rising edge.
+   2 - edge triggered on the falling edge
+   4 - level triggered active high.
+   8 - level triggered active low.
+
+- interrupts: Interrupt routing for each pin.
+
+Example:
+
+       gpio-controller@1070000000800 {
+               #gpio-cells = <2>;
+               compatible = "cavium,octeon-3860-gpio";
+               reg = <0x10700 0x00000800 0x0 0x100>;
+               gpio-controller;
+               /* Interrupts are specified by two parts:
+                * 1) GPIO pin number (0..15)
+                * 2) Triggering (1 - edge rising
+                *                2 - edge falling
+                *                4 - level active high
+                *                8 - level active low)
+                */
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               /* The GPIO pin connect to 16 consecutive CUI bits */
+               interrupts = <0 16>, <0 17>, <0 18>, <0 19>,
+                            <0 20>, <0 21>, <0 22>, <0 23>,
+                            <0 24>, <0 25>, <0 26>, <0 27>,
+                            <0 28>, <0 29>, <0 30>, <0 31>;
+       };
diff --git a/Documentation/devicetree/bindings/i2c/cavium-i2c.txt b/Documentation/devicetree/bindings/i2c/cavium-i2c.txt
new file mode 100644 (file)
index 0000000..dced82e
--- /dev/null
@@ -0,0 +1,34 @@
+* Two Wire Serial Interface (TWSI) / I2C
+
+- compatible: "cavium,octeon-3860-twsi"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The base address of the TWSI/I2C bus controller register bank.
+
+- #address-cells: Must be <1>.
+
+- #size-cells: Must be <0>.  I2C addresses have no size component.
+
+- interrupts: A single interrupt specifier.
+
+- clock-frequency: The I2C bus clock rate in Hz.
+
+Example:
+       twsi0: i2c@1180000001000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "cavium,octeon-3860-twsi";
+               reg = <0x11800 0x00001000 0x0 0x200>;
+               interrupts = <0 45>;
+               clock-frequency = <100000>;
+
+               rtc@68 {
+                       compatible = "dallas,ds1337";
+                       reg = <0x68>;
+               };
+               tmp@4c {
+                       compatible = "ti,tmp421";
+                       reg = <0x4c>;
+               };
+       };
index 1bfc02de1b0cc9900827be41386429638c0548d7..30ac3a0557f7d8c99a3660cbaf6ef2d718f3f3a9 100644 (file)
@@ -4,6 +4,8 @@ Required properties:
 - compatible: Should be "fsl,<chip>-i2c"
 - reg: Should contain registers location and length
 - interrupts: Should contain ERROR and DMA interrupts
+- clock-frequency: Desired I2C bus clock frequency in Hz.
+                   Only 100000Hz and 400000Hz modes are supported.
 
 Examples:
 
@@ -13,4 +15,5 @@ i2c0: i2c@80058000 {
        compatible = "fsl,imx28-i2c";
        reg = <0x80058000 2000>;
        interrupts = <111 68>;
+       clock-frequency = <100000>;
 };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt
new file mode 100644 (file)
index 0000000..c15781f
--- /dev/null
@@ -0,0 +1,33 @@
+Device tree configuration for i2c-ocores
+
+Required properties:
+- compatible      : "opencores,i2c-ocores"
+- reg             : bus address start and address range size of device
+- interrupts      : interrupt number
+- clock-frequency : frequency of bus clock in Hz
+- #address-cells  : should be <1>
+- #size-cells     : should be <0>
+
+Optional properties:
+- reg-shift       : device register offsets are shifted by this value
+- reg-io-width    : io register width in bytes (1, 2 or 4)
+- regstep         : deprecated, use reg-shift above
+
+Example:
+
+       i2c0: ocores@a0000000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "opencores,i2c-ocores";
+               reg = <0xa0000000 0x8>;
+               interrupts = <10>;
+               clock-frequency = <20000000>;
+
+               reg-shift = <0>;        /* 8 bit registers */
+               reg-io-width = <1>;     /* 8 bit read/write */
+
+               dummy@60 {
+                       compatible = "dummy";
+                       reg = <0x60>;
+               };
+       };
index b891ee218354014e6bb9eca531b01750f6bb54c7..0f7945019f6fb0351140bb376465cb09ae302b5a 100644 (file)
@@ -1,4 +1,4 @@
-* I2C
+* Marvell MMP I2C controller
 
 Required properties :
 
@@ -32,3 +32,20 @@ Examples:
                interrupts = <58>;
        };
 
+* Marvell MV64XXX I2C controller
+
+Required properties :
+
+ - reg             : Offset and length of the register set for the device
+ - compatible      : Should be "marvell,mv64xxx-i2c"
+ - interrupts      : The interrupt number
+ - clock-frequency : Desired I2C bus clock frequency in Hz.
+
+Examples:
+
+       i2c@11000 {
+               compatible = "marvell,mv64xxx-i2c";
+               reg = <0x11000 0x20>;
+               interrupts = <29>;
+               clock-frequency = <100000>;
+       };
diff --git a/Documentation/devicetree/bindings/mfd/ab8500.txt b/Documentation/devicetree/bindings/mfd/ab8500.txt
new file mode 100644 (file)
index 0000000..69e757a
--- /dev/null
@@ -0,0 +1,123 @@
+* AB8500 Multi-Functional Device (MFD)
+
+Required parent device properties:
+- compatible             : contains "stericsson,ab8500";
+- interrupts             : contains the IRQ line for the AB8500
+- interrupt-controller   : describes the AB8500 as an Interrupt Controller (has its own domain)
+- #interrupt-cells       : should be 2, for 2-cell format
+                            - The first cell is the AB8500 local IRQ number
+                            - The second cell is used to specify optional parameters
+                              - bits[3:0] trigger type and level flags:
+                                  1 = low-to-high edge triggered
+                                  2 = high-to-low edge triggered
+                                  4 = active high level-sensitive
+                                  8 = active low level-sensitive
+
+Optional parent device properties:
+- reg                    : contains the PRCMU mailbox address for the AB8500 i2c port
+
+The AB8500 consists of a large and varied group of sub-devices:
+
+Device                     IRQ Names              Supply Names   Description
+------                     ---------              ------------   -----------
+ab8500-bm                :                      :              : Battery Manager
+ab8500-btemp             :                      :              : Battery Temperature
+ab8500-charger           :                      :              : Battery Charger
+ab8500-fg                :                      :              : Fuel Gauge
+ab8500-gpadc             : HW_CONV_END          : vddadc       : Analogue to Digital Converter
+                           SW_CONV_END          :              :
+ab8500-gpio              :                      :              : GPIO Controller
+ab8500-ponkey            : ONKEY_DBF            :              : Power-on Key
+                           ONKEY_DBR            :              :
+ab8500-pwm               :                      :              : Pulse Width Modulator
+ab8500-regulator         :                      :              : Regulators
+ab8500-rtc               : 60S                  :              : Real Time Clock
+                         : ALARM                :              :
+ab8500-sysctrl           :                      :              : System Control
+ab8500-usb               : ID_WAKEUP_R          : vddulpivio18 : Universal Serial Bus
+                         : ID_WAKEUP_F          : v-ape        :
+                         : VBUS_DET_F           : musb_1v8     :
+                         : VBUS_DET_R           :              :
+                         : USB_LINK_STATUS      :              :
+                         : USB_ADP_PROBE_PLUG   :              :
+                         : USB_ADP_PROBE_UNPLUG :              :
+
+Required child device properties:
+- compatible             : "stericsson,ab8500-[bm|btemp|charger|fg|gpadc|gpio|ponkey|
+                                               pwm|regulator|rtc|sysctrl|usb]";
+
+Optional child device properties:
+- interrupts             : contains the device IRQ(s) using the 2-cell format (see above)
+- interrupt-names        : contains names of IRQ resource in the order in which they were
+                           supplied in the interrupts property
+- <supply_name>-supply   : contains a phandle to the regulator supply node in Device Tree
+
+ab8500@5 {
+         compatible = "stericsson,ab8500";
+         reg = <5>; /* mailbox 5 is i2c */
+         interrupts = <0 40 0x4>;
+         interrupt-controller;
+         #interrupt-cells = <2>;
+
+         ab8500-rtc {
+                 compatible = "stericsson,ab8500-rtc";
+                 interrupts = <17 0x4
+                               18 0x4>;
+                 interrupt-names = "60S", "ALARM";
+         };
+
+        ab8500-gpadc {
+                compatible = "stericsson,ab8500-gpadc";
+                interrupts = <32 0x4
+                              39 0x4>;
+                interrupt-names = "HW_CONV_END", "SW_CONV_END";
+                vddadc-supply = <&ab8500_ldo_tvout_reg>;
+        };
+
+        ab8500-usb {
+                compatible = "stericsson,ab8500-usb";
+                interrupts = < 90 0x4
+                               96 0x4
+                               14 0x4
+                               15 0x4
+                               79 0x4
+                               74 0x4
+                               75 0x4>;
+                interrupt-names = "ID_WAKEUP_R",
+                                  "ID_WAKEUP_F",
+                                  "VBUS_DET_F",
+                                  "VBUS_DET_R",
+                                  "USB_LINK_STATUS",
+                                  "USB_ADP_PROBE_PLUG",
+                                  "USB_ADP_PROBE_UNPLUG";
+                vddulpivio18-supply = <&ab8500_ldo_initcore_reg>;
+                v-ape-supply = <&db8500_vape_reg>;
+                musb_1v8-supply = <&db8500_vsmps2_reg>;
+        };
+
+        ab8500-ponkey {
+                compatible = "stericsson,ab8500-ponkey";
+                interrupts = <6 0x4
+                              7 0x4>;
+                interrupt-names = "ONKEY_DBF", "ONKEY_DBR";
+        };
+
+        ab8500-sysctrl {
+                compatible = "stericsson,ab8500-sysctrl";
+        };
+
+        ab8500-pwm {
+                compatible = "stericsson,ab8500-pwm";
+        };
+
+        ab8500-regulators {
+                compatible = "stericsson,ab8500-regulator";
+
+                ab8500_ldo_aux1_reg: ab8500_ldo_aux1 {
+                        /*
+                         * See: Documentation/devicetree/bindings/regulator/regulator.txt
+                         * for more information on regulators
+                         */
+                };
+        };
+};
diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt
new file mode 100644 (file)
index 0000000..c6a3469
--- /dev/null
@@ -0,0 +1,59 @@
+Maxim MAX77686 multi-function device
+
+MAX77686 is a Mulitifunction device with PMIC, RTC and Charger on chip. It is
+interfaced to host controller using i2c interface. PMIC and Charger submodules
+are addressed using same i2c slave address whereas RTC submodule uses
+different i2c slave address,presently for which we are statically creating i2c
+client while probing.This document describes the binding for mfd device and
+PMIC submodule.
+
+Required properties:
+- compatible : Must be "maxim,max77686";
+- reg : Specifies the i2c slave address of PMIC block.
+- interrupts : This i2c device has an IRQ line connected to the main SoC.
+- interrupt-parent : The parent interrupt controller.
+
+Optional node:
+- voltage-regulators : The regulators of max77686 have to be instantiated
+  under subnode named "voltage-regulators" using the following format.
+
+       regulator_name {
+               regulator-compatible = LDOn/BUCKn
+               standard regulator constraints....
+       };
+       refer Documentation/devicetree/bindings/regulator/regulator.txt
+
+  The regulator-compatible property of regulator should initialized with string
+to get matched with their hardware counterparts as follow:
+
+       -LDOn   :       for LDOs, where n can lie in range 1 to 26.
+                       example: LDO1, LDO2, LDO26.
+       -BUCKn  :       for BUCKs, where n can lie in range 1 to 9.
+                       example: BUCK1, BUCK5, BUCK9.
+
+Example:
+
+       max77686@09 {
+               compatible = "maxim,max77686";
+               interrupt-parent = <&wakeup_eint>;
+               interrupts = <26 0>;
+               reg = <0x09>;
+
+               voltage-regulators {
+                       ldo11_reg {
+                               regulator-compatible = "LDO11";
+                               regulator-name = "vdd_ldo11";
+                               regulator-min-microvolt = <1900000>;
+                               regulator-max-microvolt = <1900000>;
+                               regulator-always-on;
+                       };
+
+                       buck1_reg {
+                               regulator-compatible = "BUCK1";
+                               regulator-name = "vdd_mif";
+                               regulator-min-microvolt = <950000>;
+                               regulator-max-microvolt = <1300000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+       }
index d2802d4717bcfe70c146c95a1bc430807feae514..db03599ae4dcf268f0410d0b1373c3369f67351d 100644 (file)
@@ -81,7 +81,7 @@ Example:
 
                ti,vmbch-threshold = 0;
                ti,vmbch2-threshold = 0;
-
+               ti,en-ck32k-xtal;
                ti,en-gpio-sleep = <0 0 1 0 0 0 0 0 0>;
 
                vcc1-supply = <&reg_parent>;
index bc67c6f424aacc05ae894ecc7f684d7443d9ac95..c855240f3a0e0afec8fa3e6870f82dddde00ebcc 100644 (file)
@@ -6,7 +6,7 @@ They are connected ot the host processor via i2c for commands, McPDM for audio
 data and commands.
 
 Required properties:
-- compatible : Must be "ti,twl6040";
+- compatible : "ti,twl6040" for twl6040, "ti,twl6041" for twl6041
 - reg: must be 0x4b for i2c address
 - interrupts: twl6040 has one interrupt line connecteded to the main SoC
 - interrupt-parent: The parent interrupt controller
diff --git a/Documentation/devicetree/bindings/mips/cavium/bootbus.txt b/Documentation/devicetree/bindings/mips/cavium/bootbus.txt
new file mode 100644 (file)
index 0000000..6581478
--- /dev/null
@@ -0,0 +1,126 @@
+* Boot Bus
+
+The Octeon Boot Bus is a configurable parallel bus with 8 chip
+selects.  Each chip select is independently configurable.
+
+Properties:
+- compatible: "cavium,octeon-3860-bootbus"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The base address of the Boot Bus' register bank.
+
+- #address-cells: Must be <2>.  The first cell is the chip select
+   within the bootbus.  The second cell is the offset from the chip select.
+
+- #size-cells: Must be <1>.
+
+- ranges: There must be one one triplet of (child-bus-address,
+  parent-bus-address, length) for each active chip select.  If the
+  length element for any triplet is zero, the chip select is disabled,
+  making it inactive.
+
+The configuration parameters for each chip select are stored in child
+nodes.
+
+Configuration Properties:
+- compatible:  "cavium,octeon-3860-bootbus-config"
+
+- cavium,cs-index: A single cell indicating the chip select that
+  corresponds to this configuration.
+
+- cavium,t-adr: A cell specifying the ADR timing (in nS).
+
+- cavium,t-ce: A cell specifying the CE timing (in nS).
+
+- cavium,t-oe: A cell specifying the OE timing (in nS).
+
+- cavium,t-we: A cell specifying the WE timing (in nS).
+
+- cavium,t-rd-hld: A cell specifying the RD_HLD timing (in nS).
+
+- cavium,t-wr-hld: A cell specifying the WR_HLD timing (in nS).
+
+- cavium,t-pause: A cell specifying the PAUSE timing (in nS).
+
+- cavium,t-wait: A cell specifying the WAIT timing (in nS).
+
+- cavium,t-page: A cell specifying the PAGE timing (in nS).
+
+- cavium,t-rd-dly: A cell specifying the RD_DLY timing (in nS).
+
+- cavium,pages: A cell specifying the PAGES parameter (0 = 8 bytes, 1
+  = 2 bytes, 2 = 4 bytes, 3 = 8 bytes).
+
+- cavium,wait-mode: Optional.  If present, wait mode (WAITM) is selected.
+
+- cavium,page-mode: Optional.  If present, page mode (PAGEM) is selected.
+
+- cavium,bus-width: A cell specifying the WIDTH parameter (in bits) of
+  the bus for this chip select.
+
+- cavium,ale-mode: Optional.  If present, ALE mode is selected.
+
+- cavium,sam-mode: Optional.  If present, SAM mode is selected.
+
+- cavium,or-mode: Optional.  If present, OR mode is selected.
+
+Example:
+       bootbus: bootbus@1180000000000 {
+               compatible = "cavium,octeon-3860-bootbus";
+               reg = <0x11800 0x00000000 0x0 0x200>;
+               /* The chip select number and offset */
+               #address-cells = <2>;
+               /* The size of the chip select region */
+               #size-cells = <1>;
+               ranges = <0 0  0x0 0x1f400000  0xc00000>,
+                        <1 0  0x10000 0x30000000  0>,
+                        <2 0  0x10000 0x40000000  0>,
+                        <3 0  0x10000 0x50000000  0>,
+                        <4 0  0x0 0x1d020000  0x10000>,
+                        <5 0  0x0 0x1d040000  0x10000>,
+                        <6 0  0x0 0x1d050000  0x10000>,
+                        <7 0  0x10000 0x90000000  0>;
+
+                       cavium,cs-config@0 {
+                       compatible = "cavium,octeon-3860-bootbus-config";
+                       cavium,cs-index = <0>;
+                       cavium,t-adr  = <20>;
+                       cavium,t-ce   = <60>;
+                       cavium,t-oe   = <60>;
+                       cavium,t-we   = <45>;
+                       cavium,t-rd-hld = <35>;
+                       cavium,t-wr-hld = <45>;
+                       cavium,t-pause  = <0>;
+                       cavium,t-wait   = <0>;
+                       cavium,t-page   = <35>;
+                       cavium,t-rd-dly = <0>;
+
+                       cavium,pages     = <0>;
+                       cavium,bus-width = <8>;
+               };
+               .
+               .
+               .
+               cavium,cs-config@6 {
+                       compatible = "cavium,octeon-3860-bootbus-config";
+                       cavium,cs-index = <6>;
+                       cavium,t-adr  = <5>;
+                       cavium,t-ce   = <300>;
+                       cavium,t-oe   = <270>;
+                       cavium,t-we   = <150>;
+                       cavium,t-rd-hld = <100>;
+                       cavium,t-wr-hld = <70>;
+                       cavium,t-pause  = <0>;
+                       cavium,t-wait   = <0>;
+                       cavium,t-page   = <320>;
+                       cavium,t-rd-dly = <0>;
+
+                       cavium,pages     = <0>;
+                       cavium,wait-mode;
+                       cavium,bus-width = <16>;
+               };
+               .
+               .
+               .
+       };
diff --git a/Documentation/devicetree/bindings/mips/cavium/ciu.txt b/Documentation/devicetree/bindings/mips/cavium/ciu.txt
new file mode 100644 (file)
index 0000000..2c2d074
--- /dev/null
@@ -0,0 +1,26 @@
+* Central Interrupt Unit
+
+Properties:
+- compatible: "cavium,octeon-3860-ciu"
+
+  Compatibility with all cn3XXX, cn5XXX and cn63XX SOCs.
+
+- interrupt-controller:  This is an interrupt controller.
+
+- reg: The base address of the CIU's register bank.
+
+- #interrupt-cells: Must be <2>.  The first cell is the bank within
+   the CIU and may have a value of 0 or 1.  The second cell is the bit
+   within the bank and may have a value between 0 and 63.
+
+Example:
+       interrupt-controller@1070000000000 {
+               compatible = "cavium,octeon-3860-ciu";
+               interrupt-controller;
+               /* Interrupts are specified by two parts:
+                * 1) Controller register (0 or 1)
+                * 2) Bit within the register (0..63)
+                */
+               #interrupt-cells = <2>;
+               reg = <0x10700 0x00000000 0x0 0x7000>;
+       };
diff --git a/Documentation/devicetree/bindings/mips/cavium/ciu2.txt b/Documentation/devicetree/bindings/mips/cavium/ciu2.txt
new file mode 100644 (file)
index 0000000..0ec7ba8
--- /dev/null
@@ -0,0 +1,27 @@
+* Central Interrupt Unit
+
+Properties:
+- compatible: "cavium,octeon-6880-ciu2"
+
+  Compatibility with 68XX SOCs.
+
+- interrupt-controller:  This is an interrupt controller.
+
+- reg: The base address of the CIU's register bank.
+
+- #interrupt-cells: Must be <2>.  The first cell is the bank within
+  the CIU and may have a value between 0 and 63.  The second cell is
+  the bit within the bank and may also have a value between 0 and 63.
+
+Example:
+       interrupt-controller@1070100000000 {
+               compatible = "cavium,octeon-6880-ciu2";
+               interrupt-controller;
+               /* Interrupts are specified by two parts:
+                * 1) Controller register (0..63)
+                * 2) Bit within the register (0..63)
+                */
+               #address-cells = <0>;
+               #interrupt-cells = <2>;
+               reg = <0x10701 0x00000000 0x0 0x4000000>;
+       };
diff --git a/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt b/Documentation/devicetree/bindings/mips/cavium/dma-engine.txt
new file mode 100644 (file)
index 0000000..cb4291e
--- /dev/null
@@ -0,0 +1,21 @@
+* DMA Engine.
+
+The Octeon DMA Engine transfers between the Boot Bus and main memory.
+The DMA Engine will be refered to by phandle by any device that is
+connected to it.
+
+Properties:
+- compatible: "cavium,octeon-5750-bootbus-dma"
+
+  Compatibility with all cn52XX, cn56XX and cn6XXX SOCs.
+
+- reg: The base address of the DMA Engine's register bank.
+
+- interrupts: A single interrupt specifier.
+
+Example:
+       dma0: dma-engine@1180000000100 {
+               compatible = "cavium,octeon-5750-bootbus-dma";
+               reg = <0x11800 0x00000100 0x0 0x8>;
+               interrupts = <0 63>;
+       };
diff --git a/Documentation/devicetree/bindings/mips/cavium/uctl.txt b/Documentation/devicetree/bindings/mips/cavium/uctl.txt
new file mode 100644 (file)
index 0000000..aa66b9b
--- /dev/null
@@ -0,0 +1,46 @@
+* UCTL USB controller glue
+
+Properties:
+- compatible: "cavium,octeon-6335-uctl"
+
+  Compatibility with all cn6XXX SOCs.
+
+- reg: The base address of the UCTL register bank.
+
+- #address-cells: Must be <2>.
+
+- #size-cells: Must be <2>.
+
+- ranges: Empty to signify direct mapping of the children.
+
+- refclk-frequency: A single cell containing the reference clock
+  frequency in Hz.
+
+- refclk-type: A string describing the reference clock connection
+  either "crystal" or "external".
+
+Example:
+       uctl@118006f000000 {
+               compatible = "cavium,octeon-6335-uctl";
+               reg = <0x11800 0x6f000000 0x0 0x100>;
+               ranges; /* Direct mapping */
+               #address-cells = <2>;
+               #size-cells = <2>;
+               /* 12MHz, 24MHz and 48MHz allowed */
+               refclk-frequency = <24000000>;
+               /* Either "crystal" or "external" */
+               refclk-type = "crystal";
+
+               ehci@16f0000000000 {
+                       compatible = "cavium,octeon-6335-ehci","usb-ehci";
+                       reg = <0x16f00 0x00000000 0x0 0x100>;
+                       interrupts = <0 56>;
+                       big-endian-regs;
+               };
+               ohci@16f0000000400 {
+                       compatible = "cavium,octeon-6335-ohci","usb-ohci";
+                       reg = <0x16f00 0x00000400 0x0 0x100>;
+                       interrupts = <0 56>;
+                       big-endian-regs;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/net/cavium-mdio.txt b/Documentation/devicetree/bindings/net/cavium-mdio.txt
new file mode 100644 (file)
index 0000000..04cb749
--- /dev/null
@@ -0,0 +1,27 @@
+* System Management Interface (SMI) / MDIO
+
+Properties:
+- compatible: "cavium,octeon-3860-mdio"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The base address of the MDIO bus controller register bank.
+
+- #address-cells: Must be <1>.
+
+- #size-cells: Must be <0>.  MDIO addresses have no size component.
+
+Typically an MDIO bus might have several children.
+
+Example:
+       mdio@1180000001800 {
+               compatible = "cavium,octeon-3860-mdio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x11800 0x00001800 0x0 0x40>;
+
+               ethernet-phy@0 {
+                       ...
+                       reg = <0>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/net/cavium-mix.txt b/Documentation/devicetree/bindings/net/cavium-mix.txt
new file mode 100644 (file)
index 0000000..5da628d
--- /dev/null
@@ -0,0 +1,39 @@
+* MIX Ethernet controller.
+
+Properties:
+- compatible: "cavium,octeon-5750-mix"
+
+  Compatibility with all cn5XXX and cn6XXX SOCs populated with MIX
+  devices.
+
+- reg: The base addresses of four separate register banks.  The first
+  bank contains the MIX registers.  The second bank the corresponding
+  AGL registers.  The third bank are the AGL registers shared by all
+  MIX devices present.  The fourth bank is the AGL_PRT_CTL shared by
+  all MIX devices present.
+
+- cell-index: A single cell specifying which portion of the shared
+  register banks corresponds to this MIX device.
+
+- interrupts: Two interrupt specifiers.  The first is the MIX
+  interrupt routing and the second the routing for the AGL interrupts.
+
+- mac-address: Optional, the MAC address to assign to the device.
+
+- local-mac-address: Optional, the MAC address to assign to the device
+  if mac-address is not specified.
+
+- phy-handle: Optional, a phandle for the PHY device connected to this device.
+
+Example:
+       ethernet@1070000100800 {
+               compatible = "cavium,octeon-5750-mix";
+               reg = <0x10700 0x00100800 0x0 0x100>, /* MIX */
+                     <0x11800 0xE0000800 0x0 0x300>, /* AGL */
+                     <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED  */
+                     <0x11800 0xE0002008 0x0 0x8>;   /* AGL_PRT_CTL */
+               cell-index = <1>;
+               interrupts = <1 18>, < 1 46>;
+               local-mac-address = [ 00 0f b7 10 63 54 ];
+               phy-handle = <&phy1>;
+       };
diff --git a/Documentation/devicetree/bindings/net/cavium-pip.txt b/Documentation/devicetree/bindings/net/cavium-pip.txt
new file mode 100644 (file)
index 0000000..d4c53ba
--- /dev/null
@@ -0,0 +1,98 @@
+* PIP Ethernet nexus.
+
+The PIP Ethernet nexus can control several data packet input/output
+devices.  The devices have a two level grouping scheme.  There may be
+several interfaces, and each interface may have several ports.  These
+ports might be an individual Ethernet PHY.
+
+
+Properties for the PIP nexus:
+- compatible: "cavium,octeon-3860-pip"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The base address of the PIP's register bank.
+
+- #address-cells: Must be <1>.
+
+- #size-cells: Must be <0>.
+
+Properties for PIP interfaces which is a child the PIP nexus:
+- compatible: "cavium,octeon-3860-pip-interface"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The interface number.
+
+- #address-cells: Must be <1>.
+
+- #size-cells: Must be <0>.
+
+Properties for PIP port which is a child the PIP interface:
+- compatible: "cavium,octeon-3860-pip-port"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The port number within the interface group.
+
+- mac-address: Optional, the MAC address to assign to the device.
+
+- local-mac-address: Optional, the MAC address to assign to the device
+  if mac-address is not specified.
+
+- phy-handle: Optional, a phandle for the PHY device connected to this device.
+
+Example:
+
+       pip@11800a0000000 {
+               compatible = "cavium,octeon-3860-pip";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0x11800 0xa0000000 0x0 0x2000>;
+
+               interface@0 {
+                       compatible = "cavium,octeon-3860-pip-interface";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>; /* interface */
+
+                       ethernet@0 {
+                               compatible = "cavium,octeon-3860-pip-port";
+                               reg = <0x0>; /* Port */
+                               local-mac-address = [ 00 0f b7 10 63 60 ];
+                               phy-handle = <&phy2>;
+                       };
+                       ethernet@1 {
+                               compatible = "cavium,octeon-3860-pip-port";
+                               reg = <0x1>; /* Port */
+                               local-mac-address = [ 00 0f b7 10 63 61 ];
+                               phy-handle = <&phy3>;
+                       };
+                       ethernet@2 {
+                               compatible = "cavium,octeon-3860-pip-port";
+                               reg = <0x2>; /* Port */
+                               local-mac-address = [ 00 0f b7 10 63 62 ];
+                               phy-handle = <&phy4>;
+                       };
+                       ethernet@3 {
+                               compatible = "cavium,octeon-3860-pip-port";
+                               reg = <0x3>; /* Port */
+                               local-mac-address = [ 00 0f b7 10 63 63 ];
+                               phy-handle = <&phy5>;
+                       };
+               };
+
+               interface@1 {
+                       compatible = "cavium,octeon-3860-pip-interface";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <1>; /* interface */
+
+                       ethernet@0 {
+                               compatible = "cavium,octeon-3860-pip-port";
+                               reg = <0x0>; /* Port */
+                               local-mac-address = [ 00 0f b7 10 63 64 ];
+                               phy-handle = <&phy6>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt b/Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt
new file mode 100644 (file)
index 0000000..cfe1db3
--- /dev/null
@@ -0,0 +1,12 @@
+LPC32XX PWM controller
+
+Required properties:
+- compatible: should be "nxp,lpc3220-pwm"
+- reg: physical base address and length of the controller's registers
+
+Examples:
+
+pwm@0x4005C000 {
+       compatible = "nxp,lpc3220-pwm";
+       reg = <0x4005C000 0x8>;
+};
diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
new file mode 100644 (file)
index 0000000..b16f4a5
--- /dev/null
@@ -0,0 +1,17 @@
+Freescale MXS PWM controller
+
+Required properties:
+- compatible: should be "fsl,imx23-pwm"
+- reg: physical base address and length of the controller's registers
+- #pwm-cells: should be 2.  The first cell specifies the per-chip index
+  of the PWM to use and the second cell is the duty cycle in nanoseconds.
+- fsl,pwm-number: the number of PWM devices
+
+Example:
+
+pwm: pwm@80064000 {
+       compatible = "fsl,imx28-pwm", "fsl,imx23-pwm";
+       reg = <0x80064000 2000>;
+       #pwm-cells = <2>;
+       fsl,pwm-number = <8>;
+};
diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
new file mode 100644 (file)
index 0000000..bbbeedb
--- /dev/null
@@ -0,0 +1,18 @@
+Tegra SoC PWFM controller
+
+Required properties:
+- compatible: should be one of:
+  - "nvidia,tegra20-pwm"
+  - "nvidia,tegra30-pwm"
+- reg: physical base address and length of the controller's registers
+- #pwm-cells: On Tegra the number of cells used to specify a PWM is 2. The
+  first cell specifies the per-chip index of the PWM to use and the second
+  cell is the duty cycle in nanoseconds.
+
+Example:
+
+       pwm: pwm@7000a000 {
+               compatible = "nvidia,tegra20-pwm";
+               reg = <0x7000a000 0x100>;
+               #pwm-cells = <2>;
+       };
diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt b/Documentation/devicetree/bindings/pwm/pwm.txt
new file mode 100644 (file)
index 0000000..73ec962
--- /dev/null
@@ -0,0 +1,57 @@
+Specifying PWM information for devices
+======================================
+
+1) PWM user nodes
+-----------------
+
+PWM users should specify a list of PWM devices that they want to use
+with a property containing a 'pwm-list':
+
+       pwm-list ::= <single-pwm> [pwm-list]
+       single-pwm ::= <pwm-phandle> <pwm-specifier>
+       pwm-phandle : phandle to PWM controller node
+       pwm-specifier : array of #pwm-cells specifying the given PWM
+                       (controller specific)
+
+PWM properties should be named "pwms". The exact meaning of each pwms
+property must be documented in the device tree binding for each device.
+An optional property "pwm-names" may contain a list of strings to label
+each of the PWM devices listed in the "pwms" property. If no "pwm-names"
+property is given, the name of the user node will be used as fallback.
+
+Drivers for devices that use more than a single PWM device can use the
+"pwm-names" property to map the name of the PWM device requested by the
+pwm_get() call to an index into the list given by the "pwms" property.
+
+The following example could be used to describe a PWM-based backlight
+device:
+
+       pwm: pwm {
+               #pwm-cells = <2>;
+       };
+
+       [...]
+
+       bl: backlight {
+               pwms = <&pwm 0 5000000>;
+               pwm-names = "backlight";
+       };
+
+pwm-specifier typically encodes the chip-relative PWM number and the PWM
+period in nanoseconds. Note that in the example above, specifying the
+"pwm-names" is redundant because the name "backlight" would be used as
+fallback anyway.
+
+2) PWM controller nodes
+-----------------------
+
+PWM controller nodes must specify the number of cells used for the
+specifier using the '#pwm-cells' property.
+
+An example PWM controller might look like this:
+
+       pwm: pwm@7000a000 {
+               compatible = "nvidia,tegra20-pwm";
+               reg = <0x7000a000 0x100>;
+               #pwm-cells = <2>;
+       };
diff --git a/Documentation/devicetree/bindings/serial/cavium-uart.txt b/Documentation/devicetree/bindings/serial/cavium-uart.txt
new file mode 100644 (file)
index 0000000..87a6c37
--- /dev/null
@@ -0,0 +1,19 @@
+* Universal Asynchronous Receiver/Transmitter (UART)
+
+- compatible: "cavium,octeon-3860-uart"
+
+  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+
+- reg: The base address of the UART register bank.
+
+- interrupts: A single interrupt specifier.
+
+- current-speed: Optional, the current bit rate in bits per second.
+
+Example:
+       uart1: serial@1180000000c00 {
+               compatible = "cavium,octeon-3860-uart","ns16550";
+               reg = <0x11800 0x00000c00 0x0 0x400>;
+               current-speed = <115200>;
+               interrupts = <0 35>;
+       };
diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt
new file mode 100644 (file)
index 0000000..1e4fc72
--- /dev/null
@@ -0,0 +1,28 @@
+pwm-backlight bindings
+
+Required properties:
+  - compatible: "pwm-backlight"
+  - pwms: OF device-tree PWM specification (see PWM binding[0])
+  - brightness-levels: Array of distinct brightness levels. Typically these
+      are in the range from 0 to 255, but any range starting at 0 will do.
+      The actual brightness level (PWM duty cycle) will be interpolated
+      from these values. 0 means a 0% duty cycle (darkest/off), while the
+      last value in the array represents a 100% duty cycle (brightest).
+  - default-brightness-level: the default brightness level (index into the
+      array defined by the "brightness-levels" property)
+
+Optional properties:
+  - pwm-names: a list of names for the PWM devices specified in the
+               "pwms" property (see PWM binding[0])
+
+[0]: Documentation/devicetree/bindings/pwm/pwm.txt
+
+Example:
+
+       backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm 0 5000000>;
+
+               brightness-levels = <0 4 8 16 32 64 128 255>;
+               default-brightness-level = <6>;
+       };
index b4a898f43c37e72d728c17013520e44f56c87a5d..39462cf35cd4fe946dd0f0f5668defddde60d3cf 100644 (file)
@@ -150,7 +150,6 @@ keywords.c
 ksym.c*
 ksym.h*
 kxgettext
-lkc_defs.h
 lex.c
 lex.*.c
 linux
index fbb2411744864dba27ca6d2821c640f71643a89b..12d3952e83d5b0305c26afba116047aabf3c2850 100755 (executable)
@@ -29,7 +29,7 @@ use IO::Handle;
                "af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
                "lme2510c_s7395_old", "drxk", "drxk_terratec_h5",
                "drxk_hauppauge_hvr930c", "tda10071", "it9135", "it9137",
-               "drxk_pctv");
+               "drxk_pctv", "drxk_terratec_htc_stick", "sms1xxx_hcw");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -676,6 +676,24 @@ sub drxk_terratec_h5 {
     "$fwfile"
 }
 
+sub drxk_terratec_htc_stick {
+    my $url = "http://ftp.terratec.de/Receiver/Cinergy_HTC_Stick/Updates/";
+    my $zipfile = "Cinergy_HTC_Stick_Drv_5.09.1202.00_XP_Vista_7.exe";
+    my $hash = "6722a2442a05423b781721fbc069ed5e";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
+    my $drvfile = "Cinergy HTC Stick/BDA Driver 5.09.1202.00/Windows 32 Bit/emOEM.sys";
+    my $fwfile = "dvb-usb-terratec-htc-stick-drxk.fw";
+
+    checkstandard();
+
+    wgetfile($zipfile, $url . $zipfile);
+    verify($zipfile, $hash);
+    unzip($zipfile, $tmpdir);
+    extract("$tmpdir/$drvfile", 0x4e5c0, 42692, "$fwfile");
+
+    "$fwfile"
+}
+
 sub it9135 {
        my $sourcefile = "dvb-usb-it9135.zip";
        my $url = "http://www.ite.com.tw/uploads/firmware/v3.6.0.0/$sourcefile";
@@ -748,6 +766,28 @@ sub drxk_pctv {
     "$fwfile";
 }
 
+sub sms1xxx_hcw {
+    my $url = "http://steventoth.net/linux/sms1xxx/";
+    my %files = (
+       'sms1xxx-hcw-55xxx-dvbt-01.fw'  => "afb6f9fb9a71d64392e8564ef9577e5a",
+       'sms1xxx-hcw-55xxx-dvbt-02.fw'  => "b44807098ba26e52cbedeadc052ba58f",
+       'sms1xxx-hcw-55xxx-isdbt-02.fw' => "dae934eeea85225acbd63ce6cfe1c9e4",
+    );
+
+    checkstandard();
+
+    my $allfiles;
+    foreach my $fwfile (keys %files) {
+       wgetfile($fwfile, "$url/$fwfile");
+       verify($fwfile, $files{$fwfile});
+       $allfiles .= " $fwfile";
+    }
+
+    $allfiles =~ s/^\s//;
+
+    $allfiles;
+}
+
 # ---------------------------------------------------------------
 # Utilities
 
index 03df2b0203320d3451fad0765bb11e95661392f8..56c7e936430f172e135ea8d180682167ce907754 100644 (file)
@@ -232,116 +232,20 @@ EDAC control and attribute files.
 
 
 In 'mcX' directories are EDAC control and attribute files for
-this 'X' instance of the memory controllers:
-
-
-Counter reset control file:
-
-       'reset_counters'
-
-       This write-only control file will zero all the statistical counters
-       for UE and CE errors.  Zeroing the counters will also reset the timer
-       indicating how long since the last counter zero.  This is useful
-       for computing errors/time.  Since the counters are always reset at
-       driver initialization time, no module/kernel parameter is available.
-
-       RUN TIME: echo "anything" >/sys/devices/system/edac/mc/mc0/counter_reset
-
-               This resets the counters on memory controller 0
-
-
-Seconds since last counter reset control file:
-
-       'seconds_since_reset'
-
-       This attribute file displays how many seconds have elapsed since the
-       last counter reset. This can be used with the error counters to
-       measure error rates.
-
-
-
-Memory Controller name attribute file:
-
-       'mc_name'
-
-       This attribute file displays the type of memory controller
-       that is being utilized.
-
-
-Total memory managed by this memory controller attribute file:
-
-       'size_mb'
-
-       This attribute file displays, in count of megabytes, of memory
-       that this instance of memory controller manages.
-
-
-Total Uncorrectable Errors count attribute file:
-
-       'ue_count'
-
-       This attribute file displays the total count of uncorrectable
-       errors that have occurred on this memory controller. If panic_on_ue
-       is set this counter will not have a chance to increment,
-       since EDAC will panic the system.
-
-
-Total UE count that had no information attribute fileY:
-
-       'ue_noinfo_count'
-
-       This attribute file displays the number of UEs that have occurred
-       with no information as to which DIMM slot is having errors.
-
-
-Total Correctable Errors count attribute file:
-
-       'ce_count'
-
-       This attribute file displays the total count of correctable
-       errors that have occurred on this memory controller. This
-       count is very important to examine. CEs provide early
-       indications that a DIMM is beginning to fail. This count
-       field should be monitored for non-zero values and report
-       such information to the system administrator.
-
-
-Total Correctable Errors count attribute file:
-
-       'ce_noinfo_count'
-
-       This attribute file displays the number of CEs that
-       have occurred wherewith no information as to which DIMM slot
-       is having errors. Memory is handicapped, but operational,
-       yet no information is available to indicate which slot
-       the failing memory is in. This count field should be also
-       be monitored for non-zero values.
-
-Device Symlink:
-
-       'device'
-
-       Symlink to the memory controller device.
-
-Sdram memory scrubbing rate:
-
-       'sdram_scrub_rate'
-
-       Read/Write attribute file that controls memory scrubbing. The scrubbing
-       rate is set by writing a minimum bandwidth in bytes/sec to the attribute
-       file. The rate will be translated to an internal value that gives at
-       least the specified rate.
-
-       Reading the file will return the actual scrubbing rate employed.
-
-       If configuration fails or memory scrubbing is not implemented, accessing
-       that attribute will fail.
+this 'X' instance of the memory controllers.
 
+For a description of the sysfs API, please see:
+       Documentation/ABI/testing/sysfs/devices-edac
 
 
 ============================================================================
 'csrowX' DIRECTORIES
 
+When CONFIG_EDAC_LEGACY_SYSFS is enabled, the sysfs will contain the
+csrowX directories. As this API doesn't work properly for Rambus, FB-DIMMs
+and modern Intel Memory Controllers, this is being deprecated in favor
+of dimmX directories.
+
 In the 'csrowX' directories are EDAC control and attribute files for
 this 'X' instance of csrow:
 
index ba4be8b77093f2ea0399ae7c6662471e987a98e0..4cf1a2a6bd7257125e824f930d46c0e70b8fb8e6 100644 (file)
@@ -240,3 +240,30 @@ trap "echo 0 > /sys/kernel/debug/$FAILTYPE/probability" SIGINT SIGTERM EXIT
 echo "Injecting errors into the module $module... (interrupt to stop)"
 sleep 1000000
 
+Tool to run command with failslab or fail_page_alloc
+----------------------------------------------------
+In order to make it easier to accomplish the tasks mentioned above, we can use
+tools/testing/fault-injection/failcmd.sh.  Please run a command
+"./tools/testing/fault-injection/failcmd.sh --help" for more information and
+see the following examples.
+
+Examples:
+
+Run a command "make -C tools/testing/selftests/ run_tests" with injecting slab
+allocation failure.
+
+       # ./tools/testing/fault-injection/failcmd.sh \
+               -- make -C tools/testing/selftests/ run_tests
+
+Same as above except to specify 100 times failures at most instead of one time
+at most by default.
+
+       # ./tools/testing/fault-injection/failcmd.sh --times=100 \
+               -- make -C tools/testing/selftests/ run_tests
+
+Same as above except to inject page allocation failure instead of slab
+allocation failure.
+
+       # env FAILCMD_TYPE=fail_page_alloc \
+               ./tools/testing/fault-injection/failcmd.sh --times=100 \
+                -- make -C tools/testing/selftests/ run_tests
diff --git a/Documentation/fault-injection/notifier-error-inject.txt b/Documentation/fault-injection/notifier-error-inject.txt
new file mode 100644 (file)
index 0000000..c83526c
--- /dev/null
@@ -0,0 +1,99 @@
+Notifier error injection
+========================
+
+Notifier error injection provides the ability to inject artifical errors to
+specified notifier chain callbacks. It is useful to test the error handling of
+notifier call chain failures which is rarely executed.  There are kernel
+modules that can be used to test the following notifiers.
+
+ * CPU notifier
+ * PM notifier
+ * Memory hotplug notifier
+ * powerpc pSeries reconfig notifier
+
+CPU notifier error injection module
+-----------------------------------
+This feature can be used to test the error handling of the CPU notifiers by
+injecting artifical errors to CPU notifier chain callbacks.
+
+If the notifier call chain should be failed with some events notified, write
+the error code to debugfs interface
+/sys/kernel/debug/notifier-error-inject/cpu/actions/<notifier event>/error
+
+Possible CPU notifier events to be failed are:
+
+ * CPU_UP_PREPARE
+ * CPU_UP_PREPARE_FROZEN
+ * CPU_DOWN_PREPARE
+ * CPU_DOWN_PREPARE_FROZEN
+
+Example1: Inject CPU offline error (-1 == -EPERM)
+
+       # cd /sys/kernel/debug/notifier-error-inject/cpu
+       # echo -1 > actions/CPU_DOWN_PREPARE/error
+       # echo 0 > /sys/devices/system/cpu/cpu1/online
+       bash: echo: write error: Operation not permitted
+
+Example2: inject CPU online error (-2 == -ENOENT)
+
+       # echo -2 > actions/CPU_UP_PREPARE/error
+       # echo 1 > /sys/devices/system/cpu/cpu1/online
+       bash: echo: write error: No such file or directory
+
+PM notifier error injection module
+----------------------------------
+This feature is controlled through debugfs interface
+/sys/kernel/debug/notifier-error-inject/pm/actions/<notifier event>/error
+
+Possible PM notifier events to be failed are:
+
+ * PM_HIBERNATION_PREPARE
+ * PM_SUSPEND_PREPARE
+ * PM_RESTORE_PREPARE
+
+Example: Inject PM suspend error (-12 = -ENOMEM)
+
+       # cd /sys/kernel/debug/notifier-error-inject/pm/
+       # echo -12 > actions/PM_SUSPEND_PREPARE/error
+       # echo mem > /sys/power/state
+       bash: echo: write error: Cannot allocate memory
+
+Memory hotplug notifier error injection module
+----------------------------------------------
+This feature is controlled through debugfs interface
+/sys/kernel/debug/notifier-error-inject/memory/actions/<notifier event>/error
+
+Possible memory notifier events to be failed are:
+
+ * MEM_GOING_ONLINE
+ * MEM_GOING_OFFLINE
+
+Example: Inject memory hotplug offline error (-12 == -ENOMEM)
+
+       # cd /sys/kernel/debug/notifier-error-inject/memory
+       # echo -12 > actions/MEM_GOING_OFFLINE/error
+       # echo offline > /sys/devices/system/memory/memoryXXX/state
+       bash: echo: write error: Cannot allocate memory
+
+powerpc pSeries reconfig notifier error injection module
+--------------------------------------------------------
+This feature is controlled through debugfs interface
+/sys/kernel/debug/notifier-error-inject/pSeries-reconfig/actions/<notifier event>/error
+
+Possible pSeries reconfig notifier events to be failed are:
+
+ * PSERIES_RECONFIG_ADD
+ * PSERIES_RECONFIG_REMOVE
+ * PSERIES_DRCONF_MEM_ADD
+ * PSERIES_DRCONF_MEM_REMOVE
+
+For more usage examples
+-----------------------
+There are tools/testing/selftests using the notifier error injection features
+for CPU and memory notifiers.
+
+ * tools/testing/selftests/cpu-hotplug/on-off-test.sh
+ * tools/testing/selftests/memory-hotplug/on-off-test.sh
+
+These scripts first do simple online and offline tests and then do fault
+injection tests if notifier error injection module is available.
index 76112dac76592f4454fbdb20d43437079aef6c92..e9237fb719507abe070064c7fc62848e7307748d 100644 (file)
@@ -600,3 +600,21 @@ When:      June 2013
 Why:   Unsupported/unmaintained/unused since 2.6
 
 ----------------------------
+
+What:  V4L2 selections API target rectangle and flags unification, the
+       following definitions will be removed: V4L2_SEL_TGT_CROP_ACTIVE,
+       V4L2_SEL_TGT_COMPOSE_ACTIVE, V4L2_SUBDEV_SEL_*, V4L2_SUBDEV_SEL_FLAG_*
+       in favor of common V4L2_SEL_TGT_* and V4L2_SEL_FLAG_* definitions.
+       For more details see include/linux/v4l2-common.h.
+When:  3.8
+Why:   The regular V4L2 selections and the subdev selection API originally
+       defined distinct names for the target rectangles and flags - V4L2_SEL_*
+       and V4L2_SUBDEV_SEL_*. Although, it turned out that the meaning of these
+       target rectangles is virtually identical and the APIs were consolidated
+       to use single set of names - V4L2_SEL_*. This didn't involve any ABI
+       changes. Alias definitions were created for the original ones to avoid
+       any instabilities in the user space interface. After few cycles these
+       backward compatibility definitions will be removed.
+Who:   Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
+
+----------------------------
diff --git a/Documentation/input/edt-ft5x06.txt b/Documentation/input/edt-ft5x06.txt
new file mode 100644 (file)
index 0000000..2032f0b
--- /dev/null
@@ -0,0 +1,54 @@
+EDT ft5x06 based Polytouch devices
+----------------------------------
+
+The edt-ft5x06 driver is useful for the EDT "Polytouch" family of capacitive
+touch screens. Note that it is *not* suitable for other devices based on the
+focaltec ft5x06 devices, since they contain vendor-specific firmware. In
+particular this driver is not suitable for the Nook tablet.
+
+It has been tested with the following devices:
+  * EP0350M06
+  * EP0430M06
+  * EP0570M06
+  * EP0700M06
+
+The driver allows configuration of the touch screen via a set of sysfs files:
+
+/sys/class/input/eventX/device/device/threshold:
+    allows setting the "click"-threshold in the range from 20 to 80.
+
+/sys/class/input/eventX/device/device/gain:
+    allows setting the sensitivity in the range from 0 to 31. Note that
+    lower values indicate higher sensitivity.
+
+/sys/class/input/eventX/device/device/offset:
+    allows setting the edge compensation in the range from 0 to 31.
+
+/sys/class/input/eventX/device/device/report_rate:
+    allows setting the report rate in the range from 3 to 14.
+
+
+For debugging purposes the driver provides a few files in the debug
+filesystem (if available in the kernel). In /sys/kernel/debug/edt_ft5x06
+you'll find the following files:
+
+num_x, num_y:
+    (readonly) contains the number of sensor fields in X- and
+    Y-direction.
+
+mode:
+    allows switching the sensor between "factory mode" and "operation
+    mode" by writing "1" or "0" to it. In factory mode (1) it is
+    possible to get the raw data from the sensor. Note that in factory
+    mode regular events don't get delivered and the options described
+    above are unavailable.
+
+raw_data:
+    contains num_x * num_y big endian 16 bit values describing the raw
+    values for each sensor field. Note that each read() call on this
+    files triggers a new readout. It is recommended to provide a buffer
+    big enough to contain num_x * num_y * 2 bytes.
+
+Note that reading raw_data gives a I/O error when the device is not in factory
+mode. The same happens when reading/writing to the parameter files when the
+device is not in regular operation mode.
index c2619ef44a720d14bf23d9c842692b92d7b7a9ba..ad7e2e5088c126ce48e0362d1f3296f3e8b55d2b 100644 (file)
@@ -526,7 +526,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        coherent_pool=nn[KMG]   [ARM,KNL]
                        Sets the size of memory pool for coherent, atomic dma
-                       allocations if Contiguous Memory Allocator (CMA) is used.
+                       allocations, by default set to 256K.
 
        code_bytes      [X86] How many bytes of object code to print
                        in an oops report.
index 211831d4095fef63eacb13a2dbde8d647b5499a6..2f0ddc15b5ac3621a4caaa7933cfbc656b47016b 100644 (file)
@@ -112,14 +112,24 @@ CHARGE_COUNTER - the current charge counter (in ÂµAh).  This could easily
 be negative; there is no empty or full value.  It is only useful for
 relative, time-based measurements.
 
+CONSTANT_CHARGE_CURRENT - constant charge current programmed by charger.
+
+CONSTANT_CHARGE_VOLTAGE - constant charge voltage programmed by charger.
+
 ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.
 
 CAPACITY - capacity in percents.
+CAPACITY_ALERT_MIN - minimum capacity alert value in percents.
+CAPACITY_ALERT_MAX - maximum capacity alert value in percents.
 CAPACITY_LEVEL - capacity level. This corresponds to
 POWER_SUPPLY_CAPACITY_LEVEL_*.
 
 TEMP - temperature of the power supply.
+TEMP_ALERT_MIN - minimum battery temperature alert value in milli centigrade.
+TEMP_ALERT_MAX - maximum battery temperature alert value in milli centigrade.
 TEMP_AMBIENT - ambient temperature.
+TEMP_AMBIENT_ALERT_MIN - minimum ambient temperature alert value in milli centigrade.
+TEMP_AMBIENT_ALERT_MAX - maximum ambient temperature alert value in milli centigrade.
 
 TIME_TO_EMPTY - seconds left for battery to be considered empty (i.e.
 while battery powers a load)
index 5df176ed59b826e8cbeaca7c96d6ed6d06759fa8..7561d7ed8e11ef25a9a1fb479492148b6f038d5d 100644 (file)
@@ -53,9 +53,20 @@ Struct Resources:
        For printing struct resources. The 'R' and 'r' specifiers result in a
        printed resource with ('R') or without ('r') a decoded flags member.
 
+Raw buffer as a hex string:
+       %*ph    00 01 02  ...  3f
+       %*phC   00:01:02: ... :3f
+       %*phD   00-01-02- ... -3f
+       %*phN   000102 ... 3f
+
+       For printing a small buffers (up to 64 bytes long) as a hex string with
+       certain separator. For the larger buffers consider to use
+       print_hex_dump().
+
 MAC/FDDI addresses:
 
        %pM     00:01:02:03:04:05
+       %pMR    05:04:03:02:01:00
        %pMF    00-01-02-03-04-05
        %pm     000102030405
 
@@ -67,6 +78,10 @@ MAC/FDDI addresses:
        the 'M' specifier to use dash ('-') separators instead of the default
        separator.
 
+       For Bluetooth addresses the 'R' specifier shall be used after the 'M'
+       specifier to use reversed byte order suitable for visual interpretation
+       of Bluetooth addresses which are in the little endian order.
+
 IPv4 addresses:
 
        %pI4    1.2.3.4
diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
new file mode 100644 (file)
index 0000000..554290e
--- /dev/null
@@ -0,0 +1,76 @@
+Pulse Width Modulation (PWM) interface
+
+This provides an overview about the Linux PWM interface
+
+PWMs are commonly used for controlling LEDs, fans or vibrators in
+cell phones. PWMs with a fixed purpose have no need implementing
+the Linux PWM API (although they could). However, PWMs are often
+found as discrete devices on SoCs which have no fixed purpose. It's
+up to the board designer to connect them to LEDs or fans. To provide
+this kind of flexibility the generic PWM API exists.
+
+Identifying PWMs
+----------------
+
+Users of the legacy PWM API use unique IDs to refer to PWM devices.
+
+Instead of referring to a PWM device via its unique ID, board setup code
+should instead register a static mapping that can be used to match PWM
+consumers to providers, as given in the following example:
+
+       static struct pwm_lookup board_pwm_lookup[] = {
+               PWM_LOOKUP("tegra-pwm", 0, "pwm-backlight", NULL),
+       };
+
+       static void __init board_init(void)
+       {
+               ...
+               pwm_add_table(board_pwm_lookup, ARRAY_SIZE(board_pwm_lookup));
+               ...
+       }
+
+Using PWMs
+----------
+
+Legacy users can request a PWM device using pwm_request() and free it
+after usage with pwm_free().
+
+New users should use the pwm_get() function and pass to it the consumer
+device or a consumer name. pwm_put() is used to free the PWM device.
+
+After being requested a PWM has to be configured using:
+
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
+
+To start/stop toggling the PWM output use pwm_enable()/pwm_disable().
+
+Implementing a PWM driver
+-------------------------
+
+Currently there are two ways to implement pwm drivers. Traditionally
+there only has been the barebone API meaning that each driver has
+to implement the pwm_*() functions itself. This means that it's impossible
+to have multiple PWM drivers in the system. For this reason it's mandatory
+for new drivers to use the generic PWM framework.
+
+A new PWM controller/chip can be added using pwmchip_add() and removed
+again with pwmchip_remove(). pwmchip_add() takes a filled in struct
+pwm_chip as argument which provides a description of the PWM chip, the
+number of PWM devices provider by the chip and the chip-specific
+implementation of the supported PWM operations to the framework.
+
+Locking
+-------
+
+The PWM core list manipulations are protected by a mutex, so pwm_request()
+and pwm_free() may not be called from an atomic context. Currently the
+PWM core does not enforce any locking to pwm_enable(), pwm_disable() and
+pwm_config(), so the calling context is currently driver specific. This
+is an issue derived from the former barebone API and should be fixed soon.
+
+Helpers
+-------
+
+Currently a PWM can only be configured with period_ns and duty_ns. For several
+use cases freq_hz and duty_percent might be better. Instead of calculating
+this in your driver please consider adding appropriate helpers to the framework.
index 13d6166d7a2798fbd54b39a90b533ad5ddebe9eb..8c235b6e42460c5ed7eb485a1898cbcfb97793a0 100644 (file)
@@ -163,16 +163,22 @@ This value can be used to query and set the core dump mode for setuid
 or otherwise protected/tainted binaries. The modes are
 
 0 - (default) - traditional behaviour. Any process which has changed
-       privilege levels or is execute only will not be dumped
+       privilege levels or is execute only will not be dumped.
 1 - (debug) - all processes dump core when possible. The core dump is
        owned by the current user and no security is applied. This is
        intended for system debugging situations only. Ptrace is unchecked.
+       This is insecure as it allows regular users to examine the memory
+       contents of privileged processes.
 2 - (suidsafe) - any binary which normally would not be dumped is dumped
-       readable by root only. This allows the end user to remove
-       such a dump but not access it directly. For security reasons
-       core dumps in this mode will not overwrite one another or
-       other files. This mode is appropriate when administrators are
-       attempting to debug problems in a normal environment.
+       anyway, but only if the "core_pattern" kernel sysctl is set to
+       either a pipe handler or a fully qualified path. (For more details
+       on this limitation, see CVE-2006-2451.) This mode is appropriate
+       when administrators are attempting to debug problems in a normal
+       environment, and either have a core dump pipe handler that knows
+       to treat privileged core dumps with care, or specific directory
+       defined for catching core dumps. If a core dump happens without
+       a pipe handler or fully qualifid path, a message will be emitted
+       to syslog warning about the lack of a correct setting.
 
 ==============================================================
 
index 1f590527005064b677830745ad10eac22c1aa92f..89318be6c1d2117581b0dfbb5fc478370c8e0f5a 100644 (file)
@@ -594,6 +594,15 @@ You should also set these fields:
   unlocked_ioctl file operation is called this lock will be taken by the
   core and released afterwards. See the next section for more details.
 
+- queue: a pointer to the struct vb2_queue associated with this device node.
+  If queue is non-NULL, and queue->lock is non-NULL, then queue->lock is
+  used for the queuing ioctls (VIDIOC_REQBUFS, CREATE_BUFS, QBUF, DQBUF,
+  QUERYBUF, PREPARE_BUF, STREAMON and STREAMOFF) instead of the lock above.
+  That way the vb2 queuing framework does not have to wait for other ioctls.
+  This queue pointer is also used by the vb2 helper functions to check for
+  queuing ownership (i.e. is the filehandle calling it allowed to do the
+  operation).
+
 - prio: keeps track of the priorities. Used to implement VIDIOC_G/S_PRIORITY.
   If left to NULL, then it will use the struct v4l2_prio_state in v4l2_device.
   If you want to have a separate priority state per (group of) device node(s),
@@ -647,47 +656,43 @@ manually set the struct media_entity type and name fields.
 A reference to the entity will be automatically acquired/released when the
 video device is opened/closed.
 
-v4l2_file_operations and locking
---------------------------------
-
-You can set a pointer to a mutex_lock in struct video_device. Usually this
-will be either a top-level mutex or a mutex per device node. By default this
-lock will be used for unlocked_ioctl, but you can disable locking for
-selected ioctls by calling:
-
-       void v4l2_disable_ioctl_locking(struct video_device *vdev, unsigned int cmd);
-
-E.g.: v4l2_disable_ioctl_locking(vdev, VIDIOC_DQBUF);
+ioctls and locking
+------------------
 
-You have to call this before you register the video_device.
+The V4L core provides optional locking services. The main service is the
+lock field in struct video_device, which is a pointer to a mutex. If you set
+this pointer, then that will be used by unlocked_ioctl to serialize all ioctls.
 
-Particularly with USB drivers where certain commands such as setting controls
-can take a long time you may want to do your own locking for the buffer queuing
-ioctls.
+If you are using the videobuf2 framework, then there is a second lock that you
+can set: video_device->queue->lock. If set, then this lock will be used instead
+of video_device->lock to serialize all queuing ioctls (see the previous section
+for the full list of those ioctls).
 
-If you want still finer-grained locking then you have to set mutex_lock to NULL
-and do you own locking completely.
+The advantage of using a different lock for the queuing ioctls is that for some
+drivers (particularly USB drivers) certain commands such as setting controls
+can take a long time, so you want to use a separate lock for the buffer queuing
+ioctls. That way your VIDIOC_DQBUF doesn't stall because the driver is busy
+changing the e.g. exposure of the webcam.
 
-It is up to the driver developer to decide which method to use. However, if
-your driver has high-latency operations (for example, changing the exposure
-of a USB webcam might take a long time), then you might be better off with
-doing your own locking if you want to allow the user to do other things with
-the device while waiting for the high-latency command to finish.
+Of course, you can always do all the locking yourself by leaving both lock
+pointers at NULL.
 
-If a lock is specified then all ioctl commands will be serialized on that
-lock. If you use videobuf then you must pass the same lock to the videobuf
-queue initialize function: if videobuf has to wait for a frame to arrive, then
-it will temporarily unlock the lock and relock it afterwards. If your driver
-also waits in the code, then you should do the same to allow other processes
-to access the device node while the first process is waiting for something.
+If you use the old videobuf then you must pass the video_device lock to the
+videobuf queue initialize function: if videobuf has to wait for a frame to
+arrive, then it will temporarily unlock the lock and relock it afterwards. If
+your driver also waits in the code, then you should do the same to allow other
+processes to access the device node while the first process is waiting for
+something.
 
 In the case of videobuf2 you will need to implement the wait_prepare and
-wait_finish callbacks to unlock/lock if applicable. In particular, if you use
-the lock in struct video_device then you must unlock/lock this mutex in
-wait_prepare and wait_finish.
-
-The implementation of a hotplug disconnect should also take the lock before
-calling v4l2_device_disconnect.
+wait_finish callbacks to unlock/lock if applicable. If you use the queue->lock
+pointer, then you can use the helper functions vb2_ops_wait_prepare/finish.
+
+The implementation of a hotplug disconnect should also take the lock from
+video_device before calling v4l2_device_disconnect. If you are also using
+video_device->queue->lock, then you have to first lock video_device->queue->lock
+followed by video_device->lock. That way you can be sure no ioctl is running
+when you call v4l2_device_disconnect.
 
 video_device registration
 -------------------------
index bd451649f13a2ee9527bda181cfa002c77c526f4..5b44872b64ecf79162810e52602c9663364190e5 100644 (file)
@@ -1789,15 +1789,16 @@ F:      arch/powerpc/oprofile/*cell*
 F:     arch/powerpc/platforms/cell/
 
 CEPH DISTRIBUTED FILE SYSTEM CLIENT
-M:     Sage Weil <sage@newdream.net>
+M:     Sage Weil <sage@inktank.com>
 L:     ceph-devel@vger.kernel.org
-W:     http://ceph.newdream.net/
+W:     http://ceph.com/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
 S:     Supported
 F:     Documentation/filesystems/ceph.txt
 F:     fs/ceph
 F:     net/ceph
 F:     include/linux/ceph
+F:     include/linux/crush
 
 CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
 L:     linux-usb@vger.kernel.org
@@ -2750,6 +2751,7 @@ M:        Jingoo Han <jg1.han@samsung.com>
 L:     linux-fbdev@vger.kernel.org
 S:     Maintained
 F:     drivers/video/exynos/exynos_dp*
+F:     include/video/exynos_dp*
 
 EXYNOS MIPI DISPLAY DRIVERS
 M:     Inki Dae <inki.dae@samsung.com>
@@ -3155,8 +3157,7 @@ S:        Maintained
 F:     drivers/media/video/gspca/t613.c
 
 GSPCA USB WEBCAM DRIVER
-M:     Jean-Francois Moine <moinejf@free.fr>
-W:     http://moinejf.free.fr
+M:     Hans de Goede <hdegoede@redhat.com>
 L:     linux-media@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
@@ -5526,6 +5527,18 @@ S:       Maintained
 F:     Documentation/video4linux/README.pvrusb2
 F:     drivers/media/video/pvrusb2/
 
+PWM SUBSYSTEM
+M:     Thierry Reding <thierry.reding@avionic-design.de>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+W:     http://gitorious.org/linux-pwm
+T:     git git://gitorious.org/linux-pwm/linux-pwm.git
+F:     Documentation/pwm.txt
+F:     Documentation/devicetree/bindings/pwm/
+F:     include/linux/pwm.h
+F:     include/linux/of_pwm.h
+F:     drivers/pwm/
+
 PXA2xx/PXA3xx SUPPORT
 M:     Eric Miao <eric.y.miao@gmail.com>
 M:     Russell King <linux@arm.linux.org.uk>
@@ -5627,10 +5640,12 @@ S:      Supported
 F:     arch/hexagon/
 
 RADOS BLOCK DEVICE (RBD)
-F:     include/linux/qnxtypes.h
-M:     Yehuda Sadeh <yehuda@hq.newdream.net>
-M:     Sage Weil <sage@newdream.net>
+M:     Yehuda Sadeh <yehuda@inktank.com>
+M:     Sage Weil <sage@inktank.com>
+M:     Alex Elder <elder@inktank.com>
 M:     ceph-devel@vger.kernel.org
+W:     http://ceph.com/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
 S:     Supported
 F:     drivers/block/rbd.c
 F:     drivers/block/rbd_types.h
@@ -5900,6 +5915,16 @@ L:       linux-fbdev@vger.kernel.org
 S:     Maintained
 F:     drivers/video/s3c-fb.c
 
+SAMSUNG MULTIFUNCTION DEVICE DRIVERS
+M:     Sangbeom Kim <sbkim73@samsung.com>
+L:     linux-kernel@vger.kernel.org
+S:     Supported
+F:     drivers/mfd/sec*.c
+F:     drivers/regulator/s2m*.c
+F:     drivers/regulator/s5m*.c
+F:     drivers/rtc/rtc-sec.c
+F:     include/linux/mfd/samsung/
+
 SERIAL DRIVERS
 M:     Alan Cox <alan@linux.intel.com>
 L:     linux-serial@vger.kernel.org
index 4bb09e1b1230d33d9328c2a67ba32aff22ebde7d..8e4c0a7d402b02376263611a10fc26053e0ba9fa 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -535,11 +535,11 @@ PHONY += include/config/auto.conf
 
 include/config/auto.conf:
        $(Q)test -e include/generated/autoconf.h -a -e $@ || (          \
-       echo;                                                           \
-       echo "  ERROR: Kernel configuration is invalid.";               \
-       echo "         include/generated/autoconf.h or $@ are missing.";\
-       echo "         Run 'make oldconfig && make prepare' on kernel src to fix it.";  \
-       echo;                                                           \
+       echo >&2;                                                       \
+       echo >&2 "  ERROR: Kernel configuration is invalid.";           \
+       echo >&2 "         include/generated/autoconf.h or $@ are missing.";\
+       echo >&2 "         Run 'make oldconfig && make prepare' on kernel src to fix it.";      \
+       echo >&2 ;                                                      \
        /bin/false)
 
 endif # KBUILD_EXTMOD
@@ -796,8 +796,8 @@ prepare3: include/config/kernel.release
 ifneq ($(KBUILD_SRC),)
        @$(kecho) '  Using $(srctree) as source for kernel'
        $(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \
-               echo "  $(srctree) is not clean, please run 'make mrproper'"; \
-               echo "  in the '$(srctree)' directory.";\
+               echo >&2 "  $(srctree) is not clean, please run 'make mrproper'"; \
+               echo >&2 "  in the '$(srctree)' directory.";\
                /bin/false; \
        fi;
 endif
@@ -971,11 +971,11 @@ else # CONFIG_MODULES
 # ---------------------------------------------------------------------------
 
 modules modules_install: FORCE
-       @echo
-       @echo "The present kernel configuration has modules disabled."
-       @echo "Type 'make config' and enable loadable module support."
-       @echo "Then build a kernel with module support enabled."
-       @echo
+       @echo >&2
+       @echo >&2 "The present kernel configuration has modules disabled."
+       @echo >&2 "Type 'make config' and enable loadable module support."
+       @echo >&2 "Then build a kernel with module support enabled."
+       @echo >&2
        @exit 1
 
 endif # CONFIG_MODULES
index 8c3d957fa8e2f6b7794223791136c75d6a66b412..72f2fa189cc5200bb98143c6b35de8ffc9e0aaee 100644 (file)
@@ -248,7 +248,14 @@ config HAVE_CMPXCHG_LOCAL
 config HAVE_CMPXCHG_DOUBLE
        bool
 
+config ARCH_WANT_IPC_PARSE_VERSION
+       bool
+
+config ARCH_WANT_COMPAT_IPC_PARSE_VERSION
+       bool
+
 config ARCH_WANT_OLD_COMPAT_IPC
+       select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
        bool
 
 config HAVE_ARCH_SECCOMP_FILTER
index 3de74c9f961093ebbb7d87162ed6a6c3c96053d8..d5b9b5e645cc7ad6ee66984d78434b306bc1aa13 100644 (file)
@@ -14,6 +14,7 @@ config ALPHA
        select AUTO_IRQ_AFFINITY if SMP
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_OPTIONAL_GPIOLIB
+       select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_CMOS_UPDATE
index d1f23b722df4feb84d7978c4984efb5ccb6a0c36..633b23b0664ab2a4a075d648d26547dbc911a65d 100644 (file)
 
 #define NR_SYSCALLS                    504
 
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_GETHOSTNAME
index 0435921d41c6be15370b58210d8aaaaa2866ea9a..c803fc76ae4f40a04665e5624ee8eaf823334d7b 100644 (file)
@@ -933,18 +933,6 @@ void SMC37c669_display_device_info(
  *
  *--
  */
-#if 0
-/* $INCLUDE_OPTIONS$ */
-#include    "cp$inc:platform_io.h"
-/* $INCLUDE_OPTIONS_END$ */
-#include    "cp$src:common.h"
-#include    "cp$inc:prototypes.h"
-#include    "cp$src:kernel_def.h"
-#include    "cp$src:msg_def.h"
-#include    "cp$src:smcc669_def.h"
-/* Platform-specific includes */
-#include    "cp$src:platform.h"
-#endif
 
 #ifndef TRUE
 #define TRUE 1
index fbdd8533c05daeda38181127c077cd62430972ef..7980873525b264c5b8fe327387483d241662f3a1 100644 (file)
@@ -11,6 +11,7 @@ config ARM
        select RTC_LIB
        select SYS_SUPPORTS_APM_EMULATION
        select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI)
+       select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
        select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
        select HAVE_ARCH_KGDB
@@ -38,6 +39,7 @@ config ARM
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
        select GENERIC_IRQ_PROBE
+       select ARCH_WANT_IPC_PARSE_VERSION
        select HARDIRQS_SW_RESEND
        select CPU_PM if (SUSPEND || CPU_IDLE)
        select GENERIC_PCI_IOMAP
@@ -1009,7 +1011,6 @@ config ARCH_VT8500
        select ARCH_HAS_CPUFREQ
        select GENERIC_CLOCKEVENTS
        select ARCH_REQUIRE_GPIOLIB
-       select HAVE_PWM
        help
          Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip.
 
index 2e1cfa00c25b4af5bd81f328f775471f9ed2bee9..9fecf1ae777bac14b2770c0cf09dd601e85b73b8 100644 (file)
                        clocks = <&eclk>;
                };
 
+               memory-controller@fff00000 {
+                       compatible = "calxeda,hb-ddr-ctrl";
+                       reg = <0xfff00000 0x1000>;
+                       interrupts = <0 91 4>;
+               };
+
                ipc@fff20000 {
                        compatible = "arm,pl320", "arm,primecell";
                        reg = <0xfff20000 0x1000>;
                        };
                };
 
+               sregs@fff3c200 {
+                       compatible = "calxeda,hb-sregs-l2-ecc";
+                       reg = <0xfff3c200 0x100>;
+                       interrupts = <0 71 4  0 72 4>;
+               };
+
                dma@fff3d000 {
                        compatible = "arm,pl330", "arm,primecell";
                        reg = <0xfff3d000 0x1000>;
index 915db89e364431450347e69e93c9e73bb6b59108..787efac68da81b81f79318a0ac55817eb92c8879 100644 (file)
                                compatible = "fsl,imx28-i2c";
                                reg = <0x80058000 2000>;
                                interrupts = <111 68>;
+                               clock-frequency = <100000>;
                                status = "disabled";
                        };
 
                                compatible = "fsl,imx28-i2c";
                                reg = <0x8005a000 2000>;
                                interrupts = <110 69>;
+                               clock-frequency = <100000>;
                                status = "disabled";
                        };
 
diff --git a/arch/arm/boot/dts/r8a7740.dtsi b/arch/arm/boot/dts/r8a7740.dtsi
new file mode 100644 (file)
index 0000000..798fa35
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Device Tree Source for the r8a7740 SoC
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+       compatible = "renesas,r8a7740";
+
+       cpus {
+               cpu@0 {
+                       compatible = "arm,cortex-a9";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/sh7377.dtsi b/arch/arm/boot/dts/sh7377.dtsi
new file mode 100644 (file)
index 0000000..767ee07
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Device Tree Source for the sh7377 SoC
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+       compatible = "renesas,sh7377";
+
+       cpus {
+               cpu@0 {
+                       compatible = "arm,cortex-a8";
+               };
+       };
+};
index 9f1921634eb7b8ab19c671fc2de17f0d44a50fc4..405d1673904e53805a11551693446b55cfa1831c 100644 (file)
                status = "disabled";
        };
 
+       pwm {
+               compatible = "nvidia,tegra20-pwm";
+               reg = <0x7000a000 0x100>;
+               #pwm-cells = <2>;
+       };
+
        i2c@7000c000 {
                compatible = "nvidia,tegra20-i2c";
                reg = <0x7000c000 0x100>;
index da740191771f8493f1734636a88244869be5abff..3e4334d14efb4d70bdd88e46c44dc4b6af1e7cf2 100644 (file)
                status = "disabled";
        };
 
+       pwm {
+               compatible = "nvidia,tegra30-pwm", "nvidia,tegra20-pwm";
+               reg = <0x7000a000 0x100>;
+               #pwm-cells = <2>;
+       };
+
        i2c@7000c000 {
                compatible =  "nvidia,tegra30-i2c", "nvidia,tegra20-i2c";
                reg = <0x7000c000 0x100>;
index aa07f5938f05cfac42414a79f475135ff827c260..1143c4d5c56730e12221a6944acc6dc505465be1 100644 (file)
@@ -452,6 +452,7 @@ static struct dma_map_ops dmabounce_ops = {
        .alloc                  = arm_dma_alloc,
        .free                   = arm_dma_free,
        .mmap                   = arm_dma_mmap,
+       .get_sgtable            = arm_dma_get_sgtable,
        .map_page               = dmabounce_map_page,
        .unmap_page             = dmabounce_unmap_page,
        .sync_single_for_cpu    = dmabounce_sync_for_cpu,
index ddc9fe6a78acca672bc7cf2a91209eb18eca622d..7d8718468e0dff1ec28b63014f6c56ec62650d10 100644 (file)
@@ -5,10 +5,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
 # CONFIG_UTS_NS is not set
 # CONFIG_IPC_NS is not set
-# CONFIG_USER_NS is not set
 # CONFIG_PID_NS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
@@ -21,7 +18,7 @@ CONFIG_ARCH_SHMOBILE=y
 CONFIG_ARCH_R8A7740=y
 CONFIG_MACH_ARMADILLO800EVA=y
 # CONFIG_SH_TIMER_TMU is not set
-# CONFIG_ARM_THUMB is not set
+CONFIG_ARM_THUMB=y
 CONFIG_CPU_BPREDICT_DISABLE=y
 # CONFIG_CACHE_L2X0 is not set
 CONFIG_ARM_ERRATA_430973=y
@@ -39,6 +36,7 @@ CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096"
 CONFIG_CMDLINE_FORCE=y
 CONFIG_KEXEC=y
+CONFIG_VFP=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 # CONFIG_SUSPEND is not set
 CONFIG_NET=y
@@ -89,26 +87,32 @@ CONFIG_SERIAL_SH_SCI_CONSOLE=y
 CONFIG_I2C=y
 CONFIG_I2C_SH_MOBILE=y
 # CONFIG_HWMON is not set
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_RC_CORE is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+# CONFIG_V4L_USB_DRIVERS is not set
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_MT9T112=y
+CONFIG_VIDEO_SH_MOBILE_CEU=y
+# CONFIG_RADIO_ADAPTERS is not set
 CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_SH_MOBILE_LCDC=y
+CONFIG_FB_SH_MOBILE_HDMI=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
-CONFIG_SOUND=y
-CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
 # CONFIG_SND_VERBOSE_PROCFS is not set
 # CONFIG_SND_DRIVERS is not set
 # CONFIG_SND_ARM is not set
-CONFIG_SND_SOC=y
 CONFIG_SND_SOC_SH4_FSI=y
 # CONFIG_HID_SUPPORT is not set
 CONFIG_USB=y
-# CONFIG_USB_DEVICE_CLASS is not set
 CONFIG_USB_RENESAS_USBHS=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_RENESAS_USBHS_UDC=y
@@ -116,6 +120,8 @@ CONFIG_USB_ETH=m
 CONFIG_MMC=y
 CONFIG_MMC_SDHI=y
 CONFIG_MMC_SH_MMCIF=y
+CONFIG_DMADEVICES=y
+CONFIG_SH_DMAE=y
 CONFIG_UIO=y
 CONFIG_UIO_PDRV_GENIRQ=y
 # CONFIG_DNOTIFY is not set
@@ -124,7 +130,6 @@ CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 # CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
 CONFIG_NFS_V3_ACL=y
 CONFIG_NFS_V4=y
 CONFIG_NFS_V4_1=y
diff --git a/arch/arm/configs/kzm9d_defconfig b/arch/arm/configs/kzm9d_defconfig
new file mode 100644 (file)
index 0000000..26146ff
--- /dev/null
@@ -0,0 +1,89 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_SHMOBILE=y
+CONFIG_ARCH_EMEV2=y
+CONFIG_MACH_KZM9D=y
+CONFIG_MEMORY_START=0x40000000
+CONFIG_MEMORY_SIZE=0x10000000
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_SWP_EMULATE is not set
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_LOCAL_TIMERS is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_FORCE_MAX_ZONEORDER=13
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_CMDLINE="console=tty0 console=ttyS1,115200n81 earlyprintk=serial8250-em.1,115200n81 mem=128M@0x40000000 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096"
+CONFIG_CMDLINE_FORCE=y
+CONFIG_VFP=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_BLK_DEV is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+CONFIG_SMSC911X=y
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EM=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_EM=y
+# CONFIG_HWMON is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+# CONFIG_FTRACE is not set
index e3ebc20ed0a78a9a40ed76d44cfe907b01535ed3..2388c86106277dccb08e0c24820a6e4a0a733630 100644 (file)
@@ -100,7 +100,12 @@ CONFIG_SND_SOC_SH4_FSI=y
 CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 CONFIG_USB_R8A66597_HCD=y
+CONFIG_USB_RENESAS_USBHS=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_RENESAS_USBHS_UDC=y
+CONFIG_USB_ETH=m
+CONFIG_USB_MASS_STORAGE=m
 CONFIG_MMC=y
 # CONFIG_MMC_BLOCK_BOUNCE is not set
 CONFIG_MMC_SDHI=y
@@ -108,12 +113,13 @@ CONFIG_MMC_SH_MMCIF=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_RS5C372=y
 CONFIG_DMADEVICES=y
 CONFIG_SH_DMAE=y
 CONFIG_ASYNC_TX_DMA=y
 CONFIG_STAGING=y
 # CONFIG_DNOTIFY is not set
-# CONFIG_INOTIFY_USER is not set
+CONFIG_INOTIFY_USER=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 # CONFIG_MISC_FILESYSTEMS is not set
index 4be9c1e80ee63aac2c5d8239222ec1dcf147e683..db2245353f0f936aee5b86614e496aaafa044694 100644 (file)
@@ -106,6 +106,7 @@ CONFIG_I2C_TEGRA=y
 CONFIG_SPI=y
 CONFIG_SPI_TEGRA=y
 CONFIG_GPIO_TPS65910=y
+CONFIG_GPIO_TPS6586X=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_BATTERY_SBS=y
 CONFIG_SENSORS_LM90=y
index bbef15d04890b7c1ef4a9d4afec77867de1fc72d..2ae842df455180d3bcd445d339ecd332d3b36c4e 100644 (file)
@@ -186,17 +186,6 @@ extern int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
                        void *cpu_addr, dma_addr_t dma_addr, size_t size,
                        struct dma_attrs *attrs);
 
-#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL)
-
-static inline int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
-                                 void *cpu_addr, dma_addr_t dma_addr,
-                                 size_t size, struct dma_attrs *attrs)
-{
-       struct dma_map_ops *ops = get_dma_ops(dev);
-       BUG_ON(!ops);
-       return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
-}
-
 static inline void *dma_alloc_writecombine(struct device *dev, size_t size,
                                       dma_addr_t *dma_handle, gfp_t flag)
 {
@@ -213,20 +202,12 @@ static inline void dma_free_writecombine(struct device *dev, size_t size,
        return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs);
 }
 
-static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
-                     void *cpu_addr, dma_addr_t dma_addr, size_t size)
-{
-       DEFINE_DMA_ATTRS(attrs);
-       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
-       return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs);
-}
-
 /*
  * This can be called during boot to increase the size of the consistent
  * DMA region above it's default value of 2MB. It must be called before the
  * memory allocator is initialised, i.e. before any core_initcall.
  */
-extern void __init init_consistent_dma_size(unsigned long size);
+static inline void init_consistent_dma_size(unsigned long size) { }
 
 /*
  * For SA-1111, IXP425, and ADI systems  the dma-mapping functions are "magic"
@@ -280,6 +261,9 @@ extern void arm_dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int,
                enum dma_data_direction);
 extern void arm_dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
                enum dma_data_direction);
+extern int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
+               void *cpu_addr, dma_addr_t dma_addr, size_t size,
+               struct dma_attrs *attrs);
 
 #endif /* __KERNEL__ */
 #endif
index 512cd1473454c9ba26eaf51fbb659a313aad96b0..0cab47d4a83ff97a23c7a9d2975cfb855a687e3e 100644 (file)
 
 #ifdef __KERNEL__
 
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_GETHOSTNAME
 #define __ARCH_WANT_SYS_PAUSE
index 1b197ea7aab3a7a074624f1f9b5e0acafc4cac50..69719bad674ddc8bce50dc3e4880b0ac7d138217 100644 (file)
  *
  */
 #include <linux/linkage.h>
+#include <linux/kern_levels.h>
 #include <asm/assembler.h>
 
                .text
                .align
 
 .Liosl_warning:
-               .ascii  "<4>insl/outsl not implemented, called from %08lX\0"
+               .ascii  KERN_WARNING "insl/outsl not implemented, called from %08lX\0"
                .align
 
 /*
index 26fe9de35ecb8ca715f73a4cee3955591b1e2b2a..2f51293c18757712621bb26723f10d1ced8099dd 100644 (file)
@@ -619,10 +619,6 @@ static struct clk exynos4_init_clocks_off[] = {
                .devname        = "samsung-ac97",
                .enable         = exynos4_clk_ip_peril_ctrl,
                .ctrlbit        = (1 << 27),
-       }, {
-               .name           = "fimg2d",
-               .enable         = exynos4_clk_ip_image_ctrl,
-               .ctrlbit        = (1 << 0),
        }, {
                .name           = "mfc",
                .devname        = "s5p-mfc",
@@ -819,47 +815,21 @@ static struct clk *exynos4_clkset_mout_g2d0_list[] = {
        [1] = &exynos4_clk_sclk_apll.clk,
 };
 
-static struct clksrc_sources exynos4_clkset_mout_g2d0 = {
+struct clksrc_sources exynos4_clkset_mout_g2d0 = {
        .sources        = exynos4_clkset_mout_g2d0_list,
        .nr_sources     = ARRAY_SIZE(exynos4_clkset_mout_g2d0_list),
 };
 
-static struct clksrc_clk exynos4_clk_mout_g2d0 = {
-       .clk    = {
-               .name           = "mout_g2d0",
-       },
-       .sources = &exynos4_clkset_mout_g2d0,
-       .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 0, .size = 1 },
-};
-
 static struct clk *exynos4_clkset_mout_g2d1_list[] = {
        [0] = &exynos4_clk_mout_epll.clk,
        [1] = &exynos4_clk_sclk_vpll.clk,
 };
 
-static struct clksrc_sources exynos4_clkset_mout_g2d1 = {
+struct clksrc_sources exynos4_clkset_mout_g2d1 = {
        .sources        = exynos4_clkset_mout_g2d1_list,
        .nr_sources     = ARRAY_SIZE(exynos4_clkset_mout_g2d1_list),
 };
 
-static struct clksrc_clk exynos4_clk_mout_g2d1 = {
-       .clk    = {
-               .name           = "mout_g2d1",
-       },
-       .sources = &exynos4_clkset_mout_g2d1,
-       .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 4, .size = 1 },
-};
-
-static struct clk *exynos4_clkset_mout_g2d_list[] = {
-       [0] = &exynos4_clk_mout_g2d0.clk,
-       [1] = &exynos4_clk_mout_g2d1.clk,
-};
-
-static struct clksrc_sources exynos4_clkset_mout_g2d = {
-       .sources        = exynos4_clkset_mout_g2d_list,
-       .nr_sources     = ARRAY_SIZE(exynos4_clkset_mout_g2d_list),
-};
-
 static struct clk *exynos4_clkset_mout_mfc0_list[] = {
        [0] = &exynos4_clk_mout_mpll.clk,
        [1] = &exynos4_clk_sclk_apll.clk,
@@ -1124,13 +1094,6 @@ static struct clksrc_clk exynos4_clksrcs[] = {
                .sources = &exynos4_clkset_group,
                .reg_src = { .reg = EXYNOS4_CLKSRC_LCD0, .shift = 0, .size = 4 },
                .reg_div = { .reg = EXYNOS4_CLKDIV_LCD0, .shift = 0, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "sclk_fimg2d",
-               },
-               .sources = &exynos4_clkset_mout_g2d,
-               .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 8, .size = 1 },
-               .reg_div = { .reg = EXYNOS4_CLKDIV_IMAGE, .shift = 0, .size = 4 },
        }, {
                .clk    = {
                        .name           = "sclk_mfc",
index 28a1197011823b132c10542db7795d3b3eddb588..bd12d5f8b63d3824d9b5578844c84f4732ff5f40 100644 (file)
@@ -23,6 +23,9 @@ extern struct clksrc_sources exynos4_clkset_group;
 extern struct clk *exynos4_clkset_aclk_top_list[];
 extern struct clk *exynos4_clkset_group_list[];
 
+extern struct clksrc_sources exynos4_clkset_mout_g2d0;
+extern struct clksrc_sources exynos4_clkset_mout_g2d1;
+
 extern int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable);
 extern int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable);
 extern int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable);
index b8689ff60baf5cb721a5d1d5caef45393fa60743..fed4c26e9dad6b2ca8b10dd71e3423c9cb428d1a 100644 (file)
@@ -48,6 +48,32 @@ static struct clksrc_clk *sysclks[] = {
        /* nothing here yet */
 };
 
+static struct clksrc_clk exynos4210_clk_mout_g2d0 = {
+       .clk    = {
+               .name           = "mout_g2d0",
+       },
+       .sources = &exynos4_clkset_mout_g2d0,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 0, .size = 1 },
+};
+
+static struct clksrc_clk exynos4210_clk_mout_g2d1 = {
+       .clk    = {
+               .name           = "mout_g2d1",
+       },
+       .sources = &exynos4_clkset_mout_g2d1,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 4, .size = 1 },
+};
+
+static struct clk *exynos4210_clkset_mout_g2d_list[] = {
+       [0] = &exynos4210_clk_mout_g2d0.clk,
+       [1] = &exynos4210_clk_mout_g2d1.clk,
+};
+
+static struct clksrc_sources exynos4210_clkset_mout_g2d = {
+       .sources        = exynos4210_clkset_mout_g2d_list,
+       .nr_sources     = ARRAY_SIZE(exynos4210_clkset_mout_g2d_list),
+};
+
 static int exynos4_clksrc_mask_lcd1_ctrl(struct clk *clk, int enable)
 {
        return s5p_gatectrl(EXYNOS4210_CLKSRC_MASK_LCD1, clk, enable);
@@ -74,6 +100,13 @@ static struct clksrc_clk clksrcs[] = {
                .sources = &exynos4_clkset_group,
                .reg_src = { .reg = EXYNOS4210_CLKSRC_LCD1, .shift = 0, .size = 4 },
                .reg_div = { .reg = EXYNOS4210_CLKDIV_LCD1, .shift = 0, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_fimg2d",
+               },
+               .sources = &exynos4210_clkset_mout_g2d,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_IMAGE, .shift = 8, .size = 1 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_IMAGE, .shift = 0, .size = 4 },
        },
 };
 
@@ -105,6 +138,10 @@ static struct clk init_clocks_off[] = {
                .devname        = SYSMMU_CLOCK_DEVNAME(fimd1, 11),
                .enable         = exynos4_clk_ip_lcd1_ctrl,
                .ctrlbit        = (1 << 4),
+       }, {
+               .name           = "fimg2d",
+               .enable         = exynos4_clk_ip_image_ctrl,
+               .ctrlbit        = (1 << 0),
        },
 };
 
index da397d21bbcf438cb81f73fe28adbfc7d365668f..8fba0b5fb8ab895d6ef8c65b0aec576a6ad650df 100644 (file)
@@ -68,12 +68,45 @@ static struct clksrc_clk clk_mout_mpll_user = {
        .reg_src        = { .reg = EXYNOS4_CLKSRC_CPU, .shift = 24, .size = 1 },
 };
 
+static struct clksrc_clk exynos4x12_clk_mout_g2d0 = {
+       .clk    = {
+               .name           = "mout_g2d0",
+       },
+       .sources = &exynos4_clkset_mout_g2d0,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_DMC, .shift = 20, .size = 1 },
+};
+
+static struct clksrc_clk exynos4x12_clk_mout_g2d1 = {
+       .clk    = {
+               .name           = "mout_g2d1",
+       },
+       .sources = &exynos4_clkset_mout_g2d1,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_DMC, .shift = 24, .size = 1 },
+};
+
+static struct clk *exynos4x12_clkset_mout_g2d_list[] = {
+       [0] = &exynos4x12_clk_mout_g2d0.clk,
+       [1] = &exynos4x12_clk_mout_g2d1.clk,
+};
+
+static struct clksrc_sources exynos4x12_clkset_mout_g2d = {
+       .sources        = exynos4x12_clkset_mout_g2d_list,
+       .nr_sources     = ARRAY_SIZE(exynos4x12_clkset_mout_g2d_list),
+};
+
 static struct clksrc_clk *sysclks[] = {
        &clk_mout_mpll_user,
 };
 
 static struct clksrc_clk clksrcs[] = {
-       /* nothing here yet */
+       {
+               .clk    = {
+                       .name           = "sclk_fimg2d",
+               },
+               .sources = &exynos4x12_clkset_mout_g2d,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_DMC, .shift = 28, .size = 1 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_DMC1, .shift = 0, .size = 4 },
+       },
 };
 
 static struct clk init_clocks_off[] = {
@@ -102,7 +135,11 @@ static struct clk init_clocks_off[] = {
                .devname        = "exynos-fimc-lite.1",
                .enable         = exynos4212_clk_ip_isp0_ctrl,
                .ctrlbit        = (1 << 3),
-       }
+       }, {
+               .name           = "fimg2d",
+               .enable         = exynos4_clk_ip_dmc_ctrl,
+               .ctrlbit        = (1 << 23),
+       },
 };
 
 #ifdef CONFIG_PM_SLEEP
index f98a83a81ce73ed0cd89f364bfa87956802e7be8..ea785fcaf6c3262892f26dc6a3a7264d22a2e3d3 100644 (file)
@@ -1066,12 +1066,8 @@ static struct platform_device nuri_max8903_device = {
 static void __init nuri_power_init(void)
 {
        int gpio;
-       int irq_base = IRQ_GPIO_END + 1;
        int ta_en = 0;
 
-       nuri_max8997_pdata.irq_base = irq_base;
-       irq_base += MAX8997_IRQ_NR;
-
        gpio = EXYNOS4_GPX0(7);
        gpio_request(gpio, "AP_PMIC_IRQ");
        s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf));
index 5a12dc26f496a7e2ef3552f1728d66ea11f09ef8..5ca80307d6d7789c9fe1781dd6d56658f64f72e5 100644 (file)
@@ -426,7 +426,6 @@ static struct max8997_platform_data __initdata origen_max8997_pdata = {
        .buck1_gpiodvs  = false,
        .buck2_gpiodvs  = false,
        .buck5_gpiodvs  = false,
-       .irq_base       = IRQ_GPIO_END + 1,
 
        .ignore_gpiodvs_side_effect = true,
        .buck125_default_idx = 0x0,
index 2cdf6ef69beea89fa97c444e9ffa00473dd0e793..d122ee6ab9913aa8e8f2896ea0fee44a01832068 100644 (file)
@@ -69,29 +69,6 @@ void netx_clcd_remove(struct clcd_fb *fb)
                              fb->fb.screen_base, fb->fb.fix.smem_start);
 }
 
-void clk_disable(struct clk *clk)
-{
-}
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
-       return 0;
-}
-
-int clk_enable(struct clk *clk)
-{
-       return 0;
-}
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       return dev && strcmp(dev_name(dev), "fb") == 0 ? NULL : ERR_PTR(-ENOENT);
-}
-
-void clk_put(struct clk *clk)
-{
-}
-
 static AMBA_AHB_DEVICE(fb, "fb", 0, 0x00104000, { NETX_IRQ_LCD }, NULL);
 
 int netx_fb_init(struct clcd_board *board, struct clcd_panel *panel)
diff --git a/arch/arm/mach-pxa/eseries.h b/arch/arm/mach-pxa/eseries.h
deleted file mode 100644 (file)
index b96949d..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-void __init eseries_fixup(struct tag *tags, char **cmdline, struct meminfo *mi);
-
-extern struct pxa2xx_udc_mach_info e7xx_udc_mach_info;
-extern struct pxaficp_platform_data e7xx_ficp_platform_data;
-extern int e7xx_irda_init(void);
-
-extern int eseries_tmio_enable(struct platform_device *dev);
-extern int eseries_tmio_disable(struct platform_device *dev);
-extern int eseries_tmio_suspend(struct platform_device *dev);
-extern int eseries_tmio_resume(struct platform_device *dev);
-extern void eseries_get_tmio_gpios(void);
-extern struct resource eseries_tmio_resources[];
-extern struct platform_device e300_tc6387xb_device;
-
index d3de84b0dcbed280a27d12092509f6a9df4e181e..e6311988add2425be3e53324fa3b2f16fa40862e 100644 (file)
@@ -296,27 +296,11 @@ static struct asic3_led asic3_leds[ASIC3_NUM_LEDS] = {
 
 static struct resource asic3_resources[] = {
        /* GPIO part */
-       [0] = {
-               .start  = ASIC3_PHYS,
-               .end    = ASIC3_PHYS + ASIC3_MAP_SIZE_16BIT - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = PXA_GPIO_TO_IRQ(GPIO12_HX4700_ASIC3_IRQ),
-               .end    = PXA_GPIO_TO_IRQ(GPIO12_HX4700_ASIC3_IRQ),
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(ASIC3_PHYS, ASIC3_MAP_SIZE_16BIT),
+       [1] = DEFINE_RES_IRQ(PXA_GPIO_TO_IRQ(GPIO12_HX4700_ASIC3_IRQ)),
        /* SD part */
-       [2] = {
-               .start  = ASIC3_SD_PHYS,
-               .end    = ASIC3_SD_PHYS + ASIC3_MAP_SIZE_16BIT - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [3] = {
-               .start  = PXA_GPIO_TO_IRQ(GPIO66_HX4700_ASIC3_nSDIO_IRQ),
-               .end    = PXA_GPIO_TO_IRQ(GPIO66_HX4700_ASIC3_nSDIO_IRQ),
-               .flags  = IORESOURCE_IRQ,
-       },
+       [2] = DEFINE_RES_MEM(ASIC3_SD_PHYS, ASIC3_MAP_SIZE_16BIT),
+       [3] = DEFINE_RES_IRQ(PXA_GPIO_TO_IRQ(GPIO66_HX4700_ASIC3_nSDIO_IRQ)),
 };
 
 static struct asic3_platform_data asic3_platform_data = {
@@ -343,11 +327,7 @@ static struct platform_device asic3 = {
  */
 
 static struct resource egpio_resources[] = {
-       [0] = {
-               .start = PXA_CS5_PHYS,
-               .end   = PXA_CS5_PHYS + 0x4 - 1,
-               .flags = IORESOURCE_MEM,
-       },
+       [0] = DEFINE_RES_MEM(PXA_CS5_PHYS, 0x4),
 };
 
 static struct htc_egpio_chip egpio_chips[] = {
@@ -537,11 +517,7 @@ static struct w100fb_mach_info w3220_info = {
 };
 
 static struct resource w3220_resources[] = {
-       [0] = {
-               .start  = ATI_W3220_PHYS,
-               .end    = ATI_W3220_PHYS + 0x00ffffff,
-               .flags  = IORESOURCE_MEM,
-       },
+       [0] = DEFINE_RES_MEM(ATI_W3220_PHYS, SZ_16M),
 };
 
 static struct platform_device w3220 = {
@@ -683,20 +659,12 @@ static struct pda_power_pdata power_supply_info = {
 };
 
 static struct resource power_supply_resources[] = {
-       [0] = {
-               .name  = "ac",
-               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
-                        IORESOURCE_IRQ_LOWEDGE,
-               .start = PXA_GPIO_TO_IRQ(GPIOD9_nAC_IN),
-               .end   = PXA_GPIO_TO_IRQ(GPIOD9_nAC_IN),
-       },
-       [1] = {
-               .name  = "usb",
-               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
-                        IORESOURCE_IRQ_LOWEDGE,
-               .start = PXA_GPIO_TO_IRQ(GPIOD14_nUSBC_DETECT),
-               .end   = PXA_GPIO_TO_IRQ(GPIOD14_nUSBC_DETECT),
-       },
+       [0] = DEFINE_RES_NAMED(PXA_GPIO_TO_IRQ(GPIOD9_nAC_IN), 1, "ac",
+               IORESOURCE_IRQ |
+               IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE),
+       [1] = DEFINE_RES_NAMED(PXA_GPIO_TO_IRQ(GPIOD14_nUSBC_DETECT), 1, "usb",
+               IORESOURCE_IRQ |
+               IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE),
 };
 
 static struct platform_device power_supply = {
index fcf3dcabb6944678e9dfabd5cbc67a3e490deade..c0537f40a3d859205fb7609ad912fa8ecf64c053 100644 (file)
@@ -12,6 +12,9 @@
  * published by the Free Software Foundation.
  */
 
+#ifndef __MACH_S3C64XX_PM_CORE_H
+#define __MACH_S3C64XX_PM_CORE_H __FILE__
+
 #include <mach/regs-gpio.h>
 
 static inline void s3c_pm_debug_init_uart(void)
@@ -113,3 +116,4 @@ static inline void samsung_pm_saved_gpios(void)
 
        __raw_writel(S3C64XX_SLPEN_USE_xSLP, S3C64XX_SLPEN);
 }
+#endif /* __MACH_S3C64XX_PM_CORE_H */
index df33909205e2ce6155553a8485512bdd4817422b..4cacc2d22fbeb78b483d4510f4e0eb7a880ef757 100644 (file)
@@ -19,6 +19,7 @@ config ARCH_SH7372
        select CPU_V7
        select SH_CLK_CPG
        select ARCH_WANT_OPTIONAL_GPIOLIB
+       select ARM_CPU_SUSPEND if PM || CPU_IDLE
 
 config ARCH_SH73A0
        bool "SH-Mobile AG5 (R8A73A00)"
@@ -58,6 +59,7 @@ config MACH_G4EVM
        bool "G4EVM board"
        depends on ARCH_SH7377
        select ARCH_REQUIRE_GPIOLIB
+       select REGULATOR_FIXED_VOLTAGE if REGULATOR
 
 config MACH_AP4EVB
        bool "AP4EVB board"
@@ -65,6 +67,7 @@ config MACH_AP4EVB
        select ARCH_REQUIRE_GPIOLIB
        select SH_LCD_MIPI_DSI
        select SND_SOC_AK4642 if SND_SIMPLE_CARD
+       select REGULATOR_FIXED_VOLTAGE if REGULATOR
 
 choice
        prompt "AP4EVB LCD panel selection"
@@ -83,6 +86,7 @@ config MACH_AG5EVM
        bool "AG5EVM board"
        select ARCH_REQUIRE_GPIOLIB
        select SH_LCD_MIPI_DSI
+       select REGULATOR_FIXED_VOLTAGE if REGULATOR
        depends on ARCH_SH73A0
 
 config MACH_MACKEREL
@@ -90,15 +94,18 @@ config MACH_MACKEREL
        depends on ARCH_SH7372
        select ARCH_REQUIRE_GPIOLIB
        select SND_SOC_AK4642 if SND_SIMPLE_CARD
+       select REGULATOR_FIXED_VOLTAGE if REGULATOR
 
 config MACH_KOTA2
        bool "KOTA2 board"
        select ARCH_REQUIRE_GPIOLIB
+       select REGULATOR_FIXED_VOLTAGE if REGULATOR
        depends on ARCH_SH73A0
 
 config MACH_BONITO
        bool "bonito board"
        select ARCH_REQUIRE_GPIOLIB
+       select REGULATOR_FIXED_VOLTAGE if REGULATOR
        depends on ARCH_R8A7740
 
 config MACH_ARMADILLO800EVA
@@ -106,22 +113,28 @@ config MACH_ARMADILLO800EVA
        depends on ARCH_R8A7740
        select ARCH_REQUIRE_GPIOLIB
        select USE_OF
+       select REGULATOR_FIXED_VOLTAGE if REGULATOR
+       select SND_SOC_WM8978 if SND_SIMPLE_CARD
 
 config MACH_MARZEN
        bool "MARZEN board"
        depends on ARCH_R8A7779
        select ARCH_REQUIRE_GPIOLIB
+       select REGULATOR_FIXED_VOLTAGE if REGULATOR
 
 config MACH_KZM9D
        bool "KZM9D board"
        depends on ARCH_EMEV2
        select USE_OF
+       select REGULATOR_FIXED_VOLTAGE if REGULATOR
 
 config MACH_KZM9G
        bool "KZM-A9-GT board"
        depends on ARCH_SH73A0
        select ARCH_REQUIRE_GPIOLIB
        select USE_OF
+       select SND_SOC_AK4642 if SND_SIMPLE_CARD
+       select REGULATOR_FIXED_VOLTAGE if REGULATOR
 
 comment "SH-Mobile System Configuration"
 
index 8aa1962c22a278dd233022b0886b9a77bba39af4..0df5ae6740c6e491895cc20adfda5096437beb74 100644 (file)
@@ -39,7 +39,9 @@ obj-$(CONFIG_ARCH_R8A7740)    += entry-intc.o
 # PM objects
 obj-$(CONFIG_SUSPEND)          += suspend.o
 obj-$(CONFIG_CPU_IDLE)         += cpuidle.o
+obj-$(CONFIG_ARCH_SHMOBILE)    += pm-rmobile.o
 obj-$(CONFIG_ARCH_SH7372)      += pm-sh7372.o sleep-sh7372.o
+obj-$(CONFIG_ARCH_R8A7740)     += pm-r8a7740.o
 obj-$(CONFIG_ARCH_R8A7779)     += pm-r8a7779.o
 
 # Board objects
index 5a6f22f05e99bc3a166a92d968f48e3d43c56e5b..d82c010fdfc6f7682f2c4774db3038656a96a3a6 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <linux/serial_sci.h>
 #include <linux/smsc911x.h>
 #include <linux/gpio.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/traps.h>
 
+/* Dummy supplies, where voltage doesn't matter */
+static struct regulator_consumer_supply dummy_supplies[] = {
+       REGULATOR_SUPPLY("vddvario", "smsc911x"),
+       REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+};
+
 static struct resource smsc9220_resources[] = {
        [0] = {
                .start          = 0x14000000,
@@ -142,6 +150,13 @@ static struct platform_device fsi_device = {
        .resource       = fsi_resources,
 };
 
+/* Fixed 1.8V regulator to be used by MMCIF */
+static struct regulator_consumer_supply fixed1v8_power_consumers[] =
+{
+       REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"),
+};
+
 static struct resource sh_mmcif_resources[] = {
        [0] = {
                .name   = "MMCIF",
@@ -364,6 +379,13 @@ static struct platform_device mipidsi0_device = {
        },
 };
 
+/* Fixed 2.8V regulators to be used by SDHI0 */
+static struct regulator_consumer_supply fixed2v8_power_consumers[] =
+{
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"),
+};
+
 /* SDHI0 */
 static struct sh_mobile_sdhi_info sdhi0_info = {
        .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
@@ -408,8 +430,57 @@ static struct platform_device sdhi0_device = {
        },
 };
 
-void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state)
+/* Fixed 3.3V regulator to be used by SDHI1 */
+static struct regulator_consumer_supply cn4_power_consumers[] =
 {
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"),
+};
+
+static struct regulator_init_data cn4_power_init_data = {
+       .constraints = {
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = ARRAY_SIZE(cn4_power_consumers),
+       .consumer_supplies      = cn4_power_consumers,
+};
+
+static struct fixed_voltage_config cn4_power_info = {
+       .supply_name = "CN4 SD/MMC Vdd",
+       .microvolts = 3300000,
+       .gpio = GPIO_PORT114,
+       .enable_high = 1,
+       .init_data = &cn4_power_init_data,
+};
+
+static struct platform_device cn4_power = {
+       .name = "reg-fixed-voltage",
+       .id   = 2,
+       .dev  = {
+               .platform_data = &cn4_power_info,
+       },
+};
+
+static void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state)
+{
+       static int power_gpio = -EINVAL;
+
+       if (power_gpio < 0) {
+               int ret = gpio_request(GPIO_PORT114, "sdhi1_power");
+               if (!ret) {
+                       power_gpio = GPIO_PORT114;
+                       gpio_direction_output(power_gpio, 0);
+               }
+       }
+
+       /*
+        * If requesting the GPIO above failed, it means, that the regulator got
+        * probed and grabbed the GPIO, but we don't know, whether the sdhi
+        * driver already uses the regulator. If it doesn't, we have to toggle
+        * the GPIO ourselves, even though it is now owned by the fixed
+        * regulator driver. We have to live with the race in case the driver
+        * gets unloaded and the GPIO freed between these two steps.
+        */
        gpio_set_value(GPIO_PORT114, state);
 }
 
@@ -455,6 +526,7 @@ static struct platform_device sdhi1_device = {
 };
 
 static struct platform_device *ag5evm_devices[] __initdata = {
+       &cn4_power,
        &eth_device,
        &keysc_device,
        &fsi_device,
@@ -468,6 +540,12 @@ static struct platform_device *ag5evm_devices[] __initdata = {
 
 static void __init ag5evm_init(void)
 {
+       regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers,
+                                    ARRAY_SIZE(fixed1v8_power_consumers), 1800000);
+       regulator_register_always_on(1, "fixed-2.8V", fixed2v8_power_consumers,
+                                    ARRAY_SIZE(fixed2v8_power_consumers), 3300000);
+       regulator_register_fixed(3, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
        sh73a0_pinmux_init();
 
        /* enable SCIFA2 */
@@ -562,8 +640,6 @@ static void __init ag5evm_init(void)
        gpio_request(GPIO_FN_SDHID1_2_PU, NULL);
        gpio_request(GPIO_FN_SDHID1_1_PU, NULL);
        gpio_request(GPIO_FN_SDHID1_0_PU, NULL);
-       gpio_request(GPIO_PORT114, "sdhi1_power");
-       gpio_direction_output(GPIO_PORT114, 0);
 
 #ifdef CONFIG_CACHE_L2X0
        /* Shared attribute override enable, 64K*8way */
index ace60246a5dfd429d3ffd98c778c6910cd839d39..f172ca85905cdf68d114d046ea987e43b0570af9 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/i2c.h>
 #include <linux/i2c/tsc2007.h>
 #include <linux/io.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <linux/smsc911x.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_clk.h>
  * CN12: 3.3v
  */
 
+/* Dummy supplies, where voltage doesn't matter */
+static struct regulator_consumer_supply fixed1v8_power_consumers[] =
+{
+       /* J22 default position: 1.8V */
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"),
+       REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"),
+};
+
+static struct regulator_consumer_supply fixed3v3_power_consumers[] =
+{
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"),
+};
+
+static struct regulator_consumer_supply dummy_supplies[] = {
+       REGULATOR_SUPPLY("vddvario", "smsc911x"),
+       REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+};
+
 /* MTD */
 static struct mtd_partition nor_flash_partitions[] = {
        {
@@ -1138,21 +1161,6 @@ static void __init fsi_init_pm_clock(void)
        clk_put(fsia_ick);
 }
 
-/*
- * FIXME !!
- *
- * gpio_no_direction
- * are quick_hack.
- *
- * current gpio frame work doesn't have
- * the method to control only pull up/down/free.
- * this function should be replaced by correct gpio function
- */
-static void __init gpio_no_direction(u32 addr)
-{
-       __raw_writeb(0x00, addr);
-}
-
 /* TouchScreen */
 #ifdef CONFIG_AP4EVB_QHD
 # define GPIO_TSC_IRQ  GPIO_FN_IRQ28_123
@@ -1224,6 +1232,12 @@ static void __init ap4evb_init(void)
        u32 srcr4;
        struct clk *clk;
 
+       regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers,
+                                    ARRAY_SIZE(fixed1v8_power_consumers), 1800000);
+       regulator_register_always_on(1, "fixed-3.3V", fixed3v3_power_consumers,
+                                    ARRAY_SIZE(fixed3v3_power_consumers), 3300000);
+       regulator_register_fixed(2, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
        /* External clock source */
        clk_set_rate(&sh7372_dv_clki_clk, 27000000);
 
@@ -1302,8 +1316,8 @@ static void __init ap4evb_init(void)
 
        gpio_request(GPIO_PORT9, NULL);
        gpio_request(GPIO_PORT10, NULL);
-       gpio_no_direction(GPIO_PORT9CR);  /* FSIAOBT needs no direction */
-       gpio_no_direction(GPIO_PORT10CR); /* FSIAOLR needs no direction */
+       gpio_direction_none(GPIO_PORT9CR);  /* FSIAOBT needs no direction */
+       gpio_direction_none(GPIO_PORT10CR); /* FSIAOLR needs no direction */
 
        /* card detect pin for MMC slot (CN7) */
        gpio_request(GPIO_PORT41, NULL);
@@ -1447,14 +1461,14 @@ static void __init ap4evb_init(void)
 
        platform_add_devices(ap4evb_devices, ARRAY_SIZE(ap4evb_devices));
 
-       sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc1_device);
-       sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device);
-       sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4lc, &lcdc1_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4lc, &lcdc_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4mp, &fsi_device);
 
-       sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device);
-       sh7372_add_device_to_domain(&sh7372_a4r, &ceu_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sh_mmcif_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi0_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi1_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4r, &ceu_device);
 
        hdmi_init_pm_clock();
        fsi_init_pm_clock();
index 9bd135531d76118feecbc2a02647344ce21b25c5..cf10f92856dcbb905712024b1d6a00e55c77cf51 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <linux/sh_eth.h>
 #include <linux/videodev2.h>
 #include <linux/usb/renesas_usbhs.h>
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <mach/common.h>
 #include <mach/irqs.h>
+#include <mach/r8a7740.h>
+#include <media/mt9t112.h>
+#include <media/sh_mobile_ceu.h>
+#include <media/soc_camera.h>
 #include <asm/page.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 #include <asm/hardware/cache-l2x0.h>
-#include <mach/r8a7740.h>
 #include <video/sh_mobile_lcdc.h>
+#include <video/sh_mobile_hdmi.h>
+#include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
 
 /*
  * CON1                Camera Module
  *-----------+---------------+----------------------------
  */
 
+/*
+ * FSI-WM8978
+ *
+ * this command is required when playback.
+ *
+ * # amixer set "Headphone" 50
+ */
+
 /*
  * USB function
  *
  * These are a little bit complex.
  * see
  *     usbhsf_power_ctrl()
- *
- * CAUTION
- *
- * It uses autonomy mode for USB hotplug at this point
- * (= usbhs_private.platform_callback.get_vbus is NULL),
- * since we don't know what's happen on PM control
- * on this workaround.
  */
+#define IRQ7           evt2irq(0x02e0)
 #define USBCR1         0xe605810a
 #define USBH           0xC6700000
 #define USBH_USBCTR    0x10834
@@ -204,6 +214,20 @@ static void usbhsf_power_ctrl(struct platform_device *pdev,
        }
 }
 
+static int usbhsf_get_vbus(struct platform_device *pdev)
+{
+       return gpio_get_value(GPIO_PORT209);
+}
+
+static irqreturn_t usbhsf_interrupt(int irq, void *data)
+{
+       struct platform_device *pdev = data;
+
+       renesas_usbhs_call_notify_hotplug(pdev);
+
+       return IRQ_HANDLED;
+}
+
 static void usbhsf_hardware_exit(struct platform_device *pdev)
 {
        struct usbhsf_private *priv = usbhsf_get_priv(pdev);
@@ -227,11 +251,14 @@ static void usbhsf_hardware_exit(struct platform_device *pdev)
        priv->host      = NULL;
        priv->func      = NULL;
        priv->usbh_base = NULL;
+
+       free_irq(IRQ7, pdev);
 }
 
 static int usbhsf_hardware_init(struct platform_device *pdev)
 {
        struct usbhsf_private *priv = usbhsf_get_priv(pdev);
+       int ret;
 
        priv->phy       = clk_get(&pdev->dev, "phy");
        priv->usb24     = clk_get(&pdev->dev, "usb24");
@@ -251,6 +278,14 @@ static int usbhsf_hardware_init(struct platform_device *pdev)
                return -EIO;
        }
 
+       ret = request_irq(IRQ7, usbhsf_interrupt, IRQF_TRIGGER_NONE,
+                         dev_name(&pdev->dev), pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "request_irq err\n");
+               return ret;
+       }
+       irq_set_irq_type(IRQ7, IRQ_TYPE_EDGE_BOTH);
+
        /* usb24 use 1/1 of parent clock (= usb24s = 24MHz) */
        clk_set_rate(priv->usb24,
                     clk_get_rate(clk_get_parent(priv->usb24)));
@@ -262,6 +297,7 @@ static struct usbhsf_private usbhsf_private = {
        .info = {
                .platform_callback = {
                        .get_id         = usbhsf_get_id,
+                       .get_vbus       = usbhsf_get_vbus,
                        .hardware_init  = usbhsf_hardware_init,
                        .hardware_exit  = usbhsf_hardware_exit,
                        .power_ctrl     = usbhsf_power_ctrl,
@@ -269,6 +305,8 @@ static struct usbhsf_private usbhsf_private = {
                .driver_param = {
                        .buswait_bwait          = 5,
                        .detection_delay        = 5,
+                       .d0_rx_id       = SHDMA_SLAVE_USBHS_RX,
+                       .d1_tx_id       = SHDMA_SLAVE_USBHS_TX,
                },
        }
 };
@@ -384,6 +422,103 @@ static struct platform_device lcdc0_device = {
        },
 };
 
+/*
+ * LCDC1/HDMI
+ */
+static struct sh_mobile_hdmi_info hdmi_info = {
+       .flags          = HDMI_OUTPUT_PUSH_PULL |
+                         HDMI_OUTPUT_POLARITY_HI |
+                         HDMI_32BIT_REG |
+                         HDMI_HAS_HTOP1 |
+                         HDMI_SND_SRC_SPDIF,
+};
+
+static struct resource hdmi_resources[] = {
+       [0] = {
+               .name   = "HDMI",
+               .start  = 0xe6be0000,
+               .end    = 0xe6be03ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x1700),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .name   = "HDMI emma3pf",
+               .start  = 0xe6be4000,
+               .end    = 0xe6be43ff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device hdmi_device = {
+       .name           = "sh-mobile-hdmi",
+       .num_resources  = ARRAY_SIZE(hdmi_resources),
+       .resource       = hdmi_resources,
+       .id             = -1,
+       .dev    = {
+               .platform_data  = &hdmi_info,
+       },
+};
+
+static const struct fb_videomode lcdc1_mode = {
+       .name           = "HDMI 720p",
+       .xres           = 1280,
+       .yres           = 720,
+       .pixclock       = 13468,
+       .left_margin    = 220,
+       .right_margin   = 110,
+       .hsync_len      = 40,
+       .upper_margin   = 20,
+       .lower_margin   = 5,
+       .vsync_len      = 5,
+       .refresh        = 60,
+       .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
+};
+
+static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
+       .clock_source   = LCDC_CLK_PERIPHERAL, /* HDMI clock */
+       .ch[0] = {
+               .chan                   = LCDC_CHAN_MAINLCD,
+               .fourcc                 = V4L2_PIX_FMT_RGB565,
+               .interface_type         = RGB24,
+               .clock_divider          = 1,
+               .flags                  = LCDC_FLAGS_DWPOL,
+               .lcd_modes              = &lcdc1_mode,
+               .num_modes              = 1,
+               .tx_dev                 = &hdmi_device,
+               .panel_cfg = {
+                       .width  = 1280,
+                       .height = 720,
+               },
+       },
+};
+
+static struct resource hdmi_lcdc_resources[] = {
+       [0] = {
+               .name   = "LCDC1",
+               .start  = 0xfe944000,
+               .end    = 0xfe948000 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = intcs_evt2irq(0x1780),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device hdmi_lcdc_device = {
+       .name           = "sh_mobile_lcdc_fb",
+       .num_resources  = ARRAY_SIZE(hdmi_lcdc_resources),
+       .resource       = hdmi_lcdc_resources,
+       .id             = 1,
+       .dev    = {
+               .platform_data  = &hdmi_lcdc_info,
+               .coherent_dma_mask = ~0,
+       },
+};
+
 /* GPIO KEY */
 #define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 }
 
@@ -407,6 +542,17 @@ static struct platform_device gpio_keys_device = {
        },
 };
 
+/* Fixed 3.3V regulator to be used by SDHI0, SDHI1, MMCIF */
+static struct regulator_consumer_supply fixed3v3_power_consumers[] =
+{
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"),
+       REGULATOR_SUPPLY("vmmc", "sh_mmcif"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mmcif"),
+};
+
 /* SDHI0 */
 /*
  * FIXME
@@ -418,6 +564,8 @@ static struct platform_device gpio_keys_device = {
  */
 #define IRQ31  evt2irq(0x33E0)
 static struct sh_mobile_sdhi_info sdhi0_info = {
+       .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
+       .dma_slave_rx   = SHDMA_SLAVE_SDHI0_RX,
        .tmio_caps      = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |\
                          MMC_CAP_NEEDS_POLL,
        .tmio_ocr_mask  = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
@@ -458,6 +606,8 @@ static struct platform_device sdhi0_device = {
 
 /* SDHI1 */
 static struct sh_mobile_sdhi_info sdhi1_info = {
+       .dma_slave_tx   = SHDMA_SLAVE_SDHI1_TX,
+       .dma_slave_rx   = SHDMA_SLAVE_SDHI1_RX,
        .tmio_caps      = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
        .tmio_ocr_mask  = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT,
@@ -532,12 +682,209 @@ static struct platform_device sh_mmcif_device = {
        .resource       = sh_mmcif_resources,
 };
 
+/* Camera */
+static int mt9t111_power(struct device *dev, int mode)
+{
+       struct clk *mclk = clk_get(NULL, "video1");
+
+       if (IS_ERR(mclk)) {
+               dev_err(dev, "can't get video1 clock\n");
+               return -EINVAL;
+       }
+
+       if (mode) {
+               /* video1 (= CON1 camera) expect 24MHz */
+               clk_set_rate(mclk, clk_round_rate(mclk, 24000000));
+               clk_enable(mclk);
+               gpio_direction_output(GPIO_PORT158, 1);
+       } else {
+               gpio_direction_output(GPIO_PORT158, 0);
+               clk_disable(mclk);
+       }
+
+       clk_put(mclk);
+
+       return 0;
+}
+
+static struct i2c_board_info i2c_camera_mt9t111 = {
+       I2C_BOARD_INFO("mt9t112", 0x3d),
+};
+
+static struct mt9t112_camera_info mt9t111_info = {
+       .divider = { 16, 0, 0, 7, 0, 10, 14, 7, 7 },
+};
+
+static struct soc_camera_link mt9t111_link = {
+       .i2c_adapter_id = 0,
+       .bus_id         = 0,
+       .board_info     = &i2c_camera_mt9t111,
+       .power          = mt9t111_power,
+       .priv           = &mt9t111_info,
+};
+
+static struct platform_device camera_device = {
+       .name   = "soc-camera-pdrv",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &mt9t111_link,
+       },
+};
+
+/* CEU0 */
+static struct sh_mobile_ceu_info sh_mobile_ceu0_info = {
+       .flags = SH_CEU_FLAG_LOWER_8BIT,
+};
+
+static struct resource ceu0_resources[] = {
+       [0] = {
+               .name   = "CEU",
+               .start  = 0xfe910000,
+               .end    = 0xfe91009f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = intcs_evt2irq(0x0500),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               /* place holder for contiguous memory */
+       },
+};
+
+static struct platform_device ceu0_device = {
+       .name           = "sh_mobile_ceu",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(ceu0_resources),
+       .resource       = ceu0_resources,
+       .dev    = {
+               .platform_data          = &sh_mobile_ceu0_info,
+               .coherent_dma_mask      = 0xffffffff,
+       },
+};
+
+/* FSI */
+static int fsi_hdmi_set_rate(struct device *dev, int rate, int enable)
+{
+       struct clk *fsib;
+       int ret;
+
+       /* it support 48KHz only */
+       if (48000 != rate)
+               return -EINVAL;
+
+       fsib = clk_get(dev, "ickb");
+       if (IS_ERR(fsib))
+               return -EINVAL;
+
+       if (enable) {
+               ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
+               clk_enable(fsib);
+       } else {
+               ret = 0;
+               clk_disable(fsib);
+       }
+
+       clk_put(fsib);
+
+       return ret;
+}
+
+static struct sh_fsi_platform_info fsi_info = {
+       /* FSI-WM8978 */
+       .port_a = {
+               .tx_id = SHDMA_SLAVE_FSIA_TX,
+       },
+       /* FSI-HDMI */
+       .port_b = {
+               .flags          = SH_FSI_FMT_SPDIF |
+                                 SH_FSI_ENABLE_STREAM_MODE,
+               .set_rate       = fsi_hdmi_set_rate,
+               .tx_id          = SHDMA_SLAVE_FSIB_TX,
+       }
+};
+
+static struct resource fsi_resources[] = {
+       [0] = {
+               .name   = "FSI",
+               .start  = 0xfe1f0000,
+               .end    = 0xfe1f8400 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x1840),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device fsi_device = {
+       .name           = "sh_fsi2",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(fsi_resources),
+       .resource       = fsi_resources,
+       .dev    = {
+               .platform_data  = &fsi_info,
+       },
+};
+
+/* FSI-WM8978 */
+static struct asoc_simple_dai_init_info fsi_wm8978_init_info = {
+       .fmt            = SND_SOC_DAIFMT_I2S,
+       .codec_daifmt   = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF,
+       .cpu_daifmt     = SND_SOC_DAIFMT_CBS_CFS,
+       .sysclk         = 12288000,
+};
+
+static struct asoc_simple_card_info fsi_wm8978_info = {
+       .name           = "wm8978",
+       .card           = "FSI2A-WM8978",
+       .cpu_dai        = "fsia-dai",
+       .codec          = "wm8978.0-001a",
+       .platform       = "sh_fsi2",
+       .codec_dai      = "wm8978-hifi",
+       .init           = &fsi_wm8978_init_info,
+};
+
+static struct platform_device fsi_wm8978_device = {
+       .name   = "asoc-simple-card",
+       .id     = 0,
+       .dev    = {
+               .platform_data  = &fsi_wm8978_info,
+       },
+};
+
+/* FSI-HDMI */
+static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
+       .cpu_daifmt     = SND_SOC_DAIFMT_CBM_CFM,
+};
+
+static struct asoc_simple_card_info fsi2_hdmi_info = {
+       .name           = "HDMI",
+       .card           = "FSI2B-HDMI",
+       .cpu_dai        = "fsib-dai",
+       .codec          = "sh-mobile-hdmi",
+       .platform       = "sh_fsi2",
+       .codec_dai      = "sh_mobile_hdmi-hifi",
+       .init           = &fsi2_hdmi_init_info,
+};
+
+static struct platform_device fsi_hdmi_device = {
+       .name   = "asoc-simple-card",
+       .id     = 1,
+       .dev    = {
+               .platform_data  = &fsi2_hdmi_info,
+       },
+};
+
 /* I2C */
 static struct i2c_board_info i2c0_devices[] = {
        {
                I2C_BOARD_INFO("st1232-ts", 0x55),
                .irq = evt2irq(0x0340),
        },
+       {
+               I2C_BOARD_INFO("wm8978", 0x1a),
+       },
 };
 
 /*
@@ -549,6 +896,13 @@ static struct platform_device *eva_devices[] __initdata = {
        &sh_eth_device,
        &sdhi0_device,
        &sh_mmcif_device,
+       &hdmi_device,
+       &hdmi_lcdc_device,
+       &camera_device,
+       &ceu0_device,
+       &fsi_device,
+       &fsi_hdmi_device,
+       &fsi_wm8978_device,
 };
 
 static void __init eva_clock_init(void)
@@ -556,10 +910,14 @@ static void __init eva_clock_init(void)
        struct clk *system      = clk_get(NULL, "system_clk");
        struct clk *xtal1       = clk_get(NULL, "extal1");
        struct clk *usb24s      = clk_get(NULL, "usb24s");
+       struct clk *fsibck      = clk_get(NULL, "fsibck");
+       struct clk *fsib        = clk_get(&fsi_device.dev, "ickb");
 
        if (IS_ERR(system)      ||
            IS_ERR(xtal1)       ||
-           IS_ERR(usb24s)) {
+           IS_ERR(usb24s)      ||
+           IS_ERR(fsibck)      ||
+           IS_ERR(fsib)) {
                pr_err("armadillo800eva board clock init failed\n");
                goto clock_error;
        }
@@ -570,6 +928,11 @@ static void __init eva_clock_init(void)
        /* usb24s use extal1 (= system) clock (= 24MHz) */
        clk_set_parent(usb24s, system);
 
+       /* FSIBCK is 12.288MHz, and it is parent of FSI-B */
+       clk_set_parent(fsib, fsibck);
+       clk_set_rate(fsibck, 12288000);
+       clk_set_rate(fsib,   12288000);
+
 clock_error:
        if (!IS_ERR(system))
                clk_put(system);
@@ -577,16 +940,26 @@ clock_error:
                clk_put(xtal1);
        if (!IS_ERR(usb24s))
                clk_put(usb24s);
+       if (!IS_ERR(fsibck))
+               clk_put(fsibck);
+       if (!IS_ERR(fsib))
+               clk_put(fsib);
 }
 
 /*
  * board init
  */
+#define GPIO_PORT7CR   0xe6050007
+#define GPIO_PORT8CR   0xe6050008
 static void __init eva_init(void)
 {
-       eva_clock_init();
+       struct platform_device *usb = NULL;
+
+       regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers,
+                                    ARRAY_SIZE(fixed3v3_power_consumers), 3300000);
 
        r8a7740_pinmux_init();
+       r8a7740_meram_workaround();
 
        /* SCIFA1 */
        gpio_request(GPIO_FN_SCIFA1_RXD, NULL);
@@ -667,8 +1040,19 @@ static void __init eva_init(void)
                /* USB Host */
        } else {
                /* USB Func */
-               gpio_request(GPIO_FN_VBUS, NULL);
+               /*
+                * A1 chip has 2 IRQ7 pin and it was controled by MSEL register.
+                * OTOH, usbhs interrupt needs its value (HI/LOW) to decide
+                * USB connection/disconnection (usbhsf_get_vbus()).
+                * This means we needs to select GPIO_FN_IRQ7_PORT209 first,
+                * and select GPIO_PORT209 here
+                */
+               gpio_request(GPIO_FN_IRQ7_PORT209, NULL);
+               gpio_request(GPIO_PORT209, NULL);
+               gpio_direction_input(GPIO_PORT209);
+
                platform_device_register(&usbhsf_device);
+               usb = &usbhsf_device;
        }
 
        /* SDHI0 */
@@ -706,6 +1090,48 @@ static void __init eva_init(void)
        gpio_request(GPIO_FN_MMC1_D6_PORT143,   NULL);
        gpio_request(GPIO_FN_MMC1_D7_PORT142,   NULL);
 
+       /* CEU0 */
+       gpio_request(GPIO_FN_VIO0_D7,           NULL);
+       gpio_request(GPIO_FN_VIO0_D6,           NULL);
+       gpio_request(GPIO_FN_VIO0_D5,           NULL);
+       gpio_request(GPIO_FN_VIO0_D4,           NULL);
+       gpio_request(GPIO_FN_VIO0_D3,           NULL);
+       gpio_request(GPIO_FN_VIO0_D2,           NULL);
+       gpio_request(GPIO_FN_VIO0_D1,           NULL);
+       gpio_request(GPIO_FN_VIO0_D0,           NULL);
+       gpio_request(GPIO_FN_VIO0_CLK,          NULL);
+       gpio_request(GPIO_FN_VIO0_HD,           NULL);
+       gpio_request(GPIO_FN_VIO0_VD,           NULL);
+       gpio_request(GPIO_FN_VIO0_FIELD,        NULL);
+       gpio_request(GPIO_FN_VIO_CKO,           NULL);
+
+       /* CON1/CON15 Camera */
+       gpio_request(GPIO_PORT173, NULL); /* STANDBY */
+       gpio_request(GPIO_PORT172, NULL); /* RST */
+       gpio_request(GPIO_PORT158, NULL); /* CAM_PON */
+       gpio_direction_output(GPIO_PORT173, 0);
+       gpio_direction_output(GPIO_PORT172, 1);
+       gpio_direction_output(GPIO_PORT158, 0); /* see mt9t111_power() */
+
+       /* FSI-WM8978 */
+       gpio_request(GPIO_FN_FSIAIBT,           NULL);
+       gpio_request(GPIO_FN_FSIAILR,           NULL);
+       gpio_request(GPIO_FN_FSIAOMC,           NULL);
+       gpio_request(GPIO_FN_FSIAOSLD,          NULL);
+       gpio_request(GPIO_FN_FSIAISLD_PORT5,    NULL);
+
+       gpio_request(GPIO_PORT7, NULL);
+       gpio_request(GPIO_PORT8, NULL);
+       gpio_direction_none(GPIO_PORT7CR); /* FSIAOBT needs no direction */
+       gpio_direction_none(GPIO_PORT8CR); /* FSIAOLR needs no direction */
+
+       /* FSI-HDMI */
+       gpio_request(GPIO_FN_FSIBCK,            NULL);
+
+       /* HDMI */
+       gpio_request(GPIO_FN_HDMI_HPD,          NULL);
+       gpio_request(GPIO_FN_HDMI_CEC,          NULL);
+
        /*
         * CAUTION
         *
@@ -752,6 +1178,13 @@ static void __init eva_init(void)
 
        platform_add_devices(eva_devices,
                             ARRAY_SIZE(eva_devices));
+
+       eva_clock_init();
+
+       rmobile_add_device_to_domain(&r8a7740_pd_a4lc, &lcdc0_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a4lc, &hdmi_lcdc_device);
+       if (usb)
+               rmobile_add_device_to_domain(&r8a7740_pd_a3sp, usb);
 }
 
 static void __init eva_earlytimer_init(void)
index e9b32cfbf741061f378fedf05b556553cdd6ceb3..4129008eae290d445a274ca6c1a9ed27c91c37bc 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <linux/smsc911x.h>
 #include <linux/videodev2.h>
 #include <mach/common.h>
  * S38.2 = OFF
  */
 
+/* Dummy supplies, where voltage doesn't matter */
+static struct regulator_consumer_supply dummy_supplies[] = {
+       REGULATOR_SUPPLY("vddvario", "smsc911x"),
+       REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+};
+
 /*
  * FPGA
  */
@@ -360,6 +368,8 @@ static void __init bonito_init(void)
 {
        u16 val;
 
+       regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
        r8a7740_pinmux_init();
        bonito_fpga_init();
 
index f1257321999a3ca585b15706d413077339552f46..fa5dfc5c8ed6ecd91966e178db9d010e499111c7 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/io.h>
 #include <linux/input.h>
@@ -196,6 +198,15 @@ static struct platform_device keysc_device = {
        },
 };
 
+/* Fixed 3.3V regulator to be used by SDHI0 and SDHI1 */
+static struct regulator_consumer_supply fixed3v3_power_consumers[] =
+{
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"),
+};
+
 /* SDHI */
 static struct sh_mobile_sdhi_info sdhi0_info = {
        .tmio_caps      = MMC_CAP_SDIO_IRQ,
@@ -271,26 +282,11 @@ static struct platform_device *g4evm_devices[] __initdata = {
 #define GPIO_SDHID1_D3 0xe6052106
 #define GPIO_SDHICMD1  0xe6052107
 
-/*
- * FIXME !!
- *
- * gpio_pull_up is quick_hack.
- *
- * current gpio frame work doesn't have
- * the method to control only pull up/down/free.
- * this function should be replaced by correct gpio function
- */
-static void __init gpio_pull_up(u32 addr)
-{
-       u8 data = __raw_readb(addr);
-
-       data &= 0x0F;
-       data |= 0xC0;
-       __raw_writeb(data, addr);
-}
-
 static void __init g4evm_init(void)
 {
+       regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers,
+                                    ARRAY_SIZE(fixed3v3_power_consumers), 3300000);
+
        sh7377_pinmux_init();
 
        /* Lit DS14 LED */
@@ -351,11 +347,11 @@ static void __init g4evm_init(void)
        gpio_request(GPIO_FN_SDHID0_3, NULL);
        gpio_request(GPIO_FN_SDHICMD0, NULL);
        gpio_request(GPIO_FN_SDHIWP0, NULL);
-       gpio_pull_up(GPIO_SDHID0_D0);
-       gpio_pull_up(GPIO_SDHID0_D1);
-       gpio_pull_up(GPIO_SDHID0_D2);
-       gpio_pull_up(GPIO_SDHID0_D3);
-       gpio_pull_up(GPIO_SDHICMD0);
+       gpio_request_pullup(GPIO_SDHID0_D0);
+       gpio_request_pullup(GPIO_SDHID0_D1);
+       gpio_request_pullup(GPIO_SDHID0_D2);
+       gpio_request_pullup(GPIO_SDHID0_D3);
+       gpio_request_pullup(GPIO_SDHICMD0);
 
        /* SDHI1 */
        gpio_request(GPIO_FN_SDHICLK1, NULL);
@@ -364,11 +360,11 @@ static void __init g4evm_init(void)
        gpio_request(GPIO_FN_SDHID1_2, NULL);
        gpio_request(GPIO_FN_SDHID1_3, NULL);
        gpio_request(GPIO_FN_SDHICMD1, NULL);
-       gpio_pull_up(GPIO_SDHID1_D0);
-       gpio_pull_up(GPIO_SDHID1_D1);
-       gpio_pull_up(GPIO_SDHID1_D2);
-       gpio_pull_up(GPIO_SDHID1_D3);
-       gpio_pull_up(GPIO_SDHICMD1);
+       gpio_request_pullup(GPIO_SDHID1_D0);
+       gpio_request_pullup(GPIO_SDHID1_D1);
+       gpio_request_pullup(GPIO_SDHID1_D2);
+       gpio_request_pullup(GPIO_SDHID1_D3);
+       gpio_request_pullup(GPIO_SDHICMD1);
 
        sh7377_add_standard_devices();
 
index f60f1b281cc46117c2cd2a03585ac8b21a8359dd..21dbe54304d5b9f82cf346a00c620264b0e83c11 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <linux/smsc911x.h>
 #include <linux/gpio.h>
 #include <linux/input.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/traps.h>
 
+/* Dummy supplies, where voltage doesn't matter */
+static struct regulator_consumer_supply dummy_supplies[] = {
+       REGULATOR_SUPPLY("vddvario", "smsc911x"),
+       REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+};
+
 /* SMSC 9220 */
 static struct resource smsc9220_resources[] = {
        [0] = {
@@ -288,6 +296,13 @@ static struct platform_device leds_tpu30_device = {
        .resource       = tpu30_resources,
 };
 
+/* Fixed 1.8V regulator to be used by MMCIF */
+static struct regulator_consumer_supply fixed1v8_power_consumers[] =
+{
+       REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"),
+};
+
 /* MMCIF */
 static struct resource mmcif_resources[] = {
        [0] = {
@@ -321,6 +336,15 @@ static struct platform_device mmcif_device = {
        .resource       = mmcif_resources,
 };
 
+/* Fixed 3.3V regulator to be used by SDHI0 and SDHI1 */
+static struct regulator_consumer_supply fixed3v3_power_consumers[] =
+{
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"),
+};
+
 /* SDHI0 */
 static struct sh_mobile_sdhi_info sdhi0_info = {
        .tmio_caps      = MMC_CAP_SD_HIGHSPEED,
@@ -411,6 +435,12 @@ static struct platform_device *kota2_devices[] __initdata = {
 
 static void __init kota2_init(void)
 {
+       regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers,
+                                    ARRAY_SIZE(fixed1v8_power_consumers), 1800000);
+       regulator_register_always_on(1, "fixed-3.3V", fixed3v3_power_consumers,
+                                    ARRAY_SIZE(fixed3v3_power_consumers), 3300000);
+       regulator_register_fixed(2, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
        sh73a0_pinmux_init();
 
        /* SCIFA2 (UART2) */
index 6a33cf393428f730d9cc2b44633af997e4c7d3df..2c986eaae7b4d5ec77e4394dd2826f8ec3f67354 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <linux/smsc911x.h>
 #include <mach/common.h>
 #include <mach/emev2.h>
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
 
+/* Dummy supplies, where voltage doesn't matter */
+static struct regulator_consumer_supply dummy_supplies[] = {
+       REGULATOR_SUPPLY("vddvario", "smsc911x"),
+       REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+};
+
 /* Ether */
 static struct resource smsc911x_resources[] = {
        [0] = {
@@ -63,6 +71,8 @@ static struct platform_device *kzm9d_devices[] __initdata = {
 
 void __init kzm9d_add_standard_devices(void)
 {
+       regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
        emev2_add_standard_devices();
 
        platform_add_devices(kzm9d_devices, ARRAY_SIZE(kzm9d_devices));
index c0ae815e7beb18a9be40be4bb892bfb725af7b78..53b7ea92c32c119bcfc6d44a96b92fac915363da 100644 (file)
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <linux/mfd/tmio.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <linux/smsc911x.h>
 #include <linux/usb/r8a66597.h>
+#include <linux/usb/renesas_usbhs.h>
 #include <linux/videodev2.h>
+#include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
 #include <mach/irqs.h>
 #include <mach/sh73a0.h>
 #include <mach/common.h>
 #define GPIO_PCF8575_PORT15    (GPIO_NR + 13)
 #define GPIO_PCF8575_PORT16    (GPIO_NR + 14)
 
+/* Dummy supplies, where voltage doesn't matter */
+static struct regulator_consumer_supply dummy_supplies[] = {
+       REGULATOR_SUPPLY("vddvario", "smsc911x"),
+       REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+};
+
+/*
+ * FSI-AK4648
+ *
+ * this command is required when playback.
+ *
+ * # amixer set "LINEOUT Mixer DACL" on
+ */
+
 /* SMSC 9221 */
 static struct resource smsc9221_resources[] = {
        [0] = {
@@ -112,6 +131,151 @@ static struct platform_device usb_host_device = {
        .resource       = usb_resources,
 };
 
+/* USB Func CN17 */
+struct usbhs_private {
+       unsigned int phy;
+       unsigned int cr2;
+       struct renesas_usbhs_platform_info info;
+};
+
+#define IRQ15                  intcs_evt2irq(0x03e0)
+#define USB_PHY_MODE           (1 << 4)
+#define USB_PHY_INT_EN         ((1 << 3) | (1 << 2))
+#define USB_PHY_ON             (1 << 1)
+#define USB_PHY_OFF            (1 << 0)
+#define USB_PHY_INT_CLR                (USB_PHY_ON | USB_PHY_OFF)
+
+#define usbhs_get_priv(pdev) \
+       container_of(renesas_usbhs_get_info(pdev), struct usbhs_private, info)
+
+static int usbhs_get_vbus(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       return !((1 << 7) & __raw_readw(priv->cr2));
+}
+
+static void usbhs_phy_reset(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       /* init phy */
+       __raw_writew(0x8a0a, priv->cr2);
+}
+
+static int usbhs_get_id(struct platform_device *pdev)
+{
+       return USBHS_GADGET;
+}
+
+static irqreturn_t usbhs_interrupt(int irq, void *data)
+{
+       struct platform_device *pdev = data;
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       renesas_usbhs_call_notify_hotplug(pdev);
+
+       /* clear status */
+       __raw_writew(__raw_readw(priv->phy) | USB_PHY_INT_CLR, priv->phy);
+
+       return IRQ_HANDLED;
+}
+
+static int usbhs_hardware_init(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+       int ret;
+
+       /* clear interrupt status */
+       __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->phy);
+
+       ret = request_irq(IRQ15, usbhs_interrupt, IRQF_TRIGGER_HIGH,
+                         dev_name(&pdev->dev), pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "request_irq err\n");
+               return ret;
+       }
+
+       /* enable USB phy interrupt */
+       __raw_writew(USB_PHY_MODE | USB_PHY_INT_EN, priv->phy);
+
+       return 0;
+}
+
+static void usbhs_hardware_exit(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       /* clear interrupt status */
+       __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->phy);
+
+       free_irq(IRQ15, pdev);
+}
+
+static u32 usbhs_pipe_cfg[] = {
+       USB_ENDPOINT_XFER_CONTROL,
+       USB_ENDPOINT_XFER_ISOC,
+       USB_ENDPOINT_XFER_ISOC,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_INT,
+       USB_ENDPOINT_XFER_INT,
+       USB_ENDPOINT_XFER_INT,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usbhs_private usbhs_private = {
+       .phy    = 0xe60781e0,           /* USBPHYINT */
+       .cr2    = 0xe605810c,           /* USBCR2 */
+       .info = {
+               .platform_callback = {
+                       .hardware_init  = usbhs_hardware_init,
+                       .hardware_exit  = usbhs_hardware_exit,
+                       .get_id         = usbhs_get_id,
+                       .phy_reset      = usbhs_phy_reset,
+                       .get_vbus       = usbhs_get_vbus,
+               },
+               .driver_param = {
+                       .buswait_bwait  = 4,
+                       .has_otg        = 1,
+                       .pipe_type      = usbhs_pipe_cfg,
+                       .pipe_size      = ARRAY_SIZE(usbhs_pipe_cfg),
+               },
+       },
+};
+
+static struct resource usbhs_resources[] = {
+       [0] = {
+               .start  = 0xE6890000,
+               .end    = 0xE68900e6 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = gic_spi(62),
+               .end    = gic_spi(62),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device usbhs_device = {
+       .name   = "renesas_usbhs",
+       .id     = -1,
+       .dev = {
+               .dma_mask               = NULL,
+               .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = &usbhs_private.info,
+       },
+       .num_resources  = ARRAY_SIZE(usbhs_resources),
+       .resource       = usbhs_resources,
+};
+
 /* LCDC */
 static struct fb_videomode kzm_lcdc_mode = {
        .name           = "WVGA Panel",
@@ -166,6 +330,13 @@ static struct platform_device lcdc_device = {
        },
 };
 
+/* Fixed 1.8V regulator to be used by MMCIF */
+static struct regulator_consumer_supply fixed1v8_power_consumers[] =
+{
+       REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"),
+};
+
 /* MMCIF */
 static struct resource sh_mmcif_resources[] = {
        [0] = {
@@ -187,6 +358,8 @@ static struct resource sh_mmcif_resources[] = {
 static struct sh_mmcif_plat_data sh_mmcif_platdata = {
        .ocr            = MMC_VDD_165_195,
        .caps           = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
+       .slave_id_tx    = SHDMA_SLAVE_MMCIF_TX,
+       .slave_id_rx    = SHDMA_SLAVE_MMCIF_RX,
 };
 
 static struct platform_device mmc_device = {
@@ -200,6 +373,15 @@ static struct platform_device mmc_device = {
        .resource       = sh_mmcif_resources,
 };
 
+/* Fixed 2.8V regulators to be used by SDHI0 and SDHI2 */
+static struct regulator_consumer_supply fixed2v8_power_consumers[] =
+{
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.2"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.2"),
+};
+
 /* SDHI */
 static struct sh_mobile_sdhi_info sdhi0_info = {
        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT,
@@ -240,6 +422,50 @@ static struct platform_device sdhi0_device = {
        },
 };
 
+/* Micro SD */
+static struct sh_mobile_sdhi_info sdhi2_info = {
+       .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT |
+                         TMIO_MMC_USE_GPIO_CD |
+                         TMIO_MMC_WRPROTECT_DISABLE,
+       .tmio_caps      = MMC_CAP_SD_HIGHSPEED,
+       .tmio_ocr_mask  = MMC_VDD_27_28 | MMC_VDD_28_29,
+       .cd_gpio        = GPIO_PORT13,
+};
+
+static struct resource sdhi2_resources[] = {
+       [0] = {
+               .name   = "SDHI2",
+               .start  = 0xee140000,
+               .end    = 0xee1400ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .name   = SH_MOBILE_SDHI_IRQ_CARD_DETECT,
+               .start  = gic_spi(103),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .name   = SH_MOBILE_SDHI_IRQ_SDCARD,
+               .start  = gic_spi(104),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .name   = SH_MOBILE_SDHI_IRQ_SDIO,
+               .start  = gic_spi(105),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device sdhi2_device = {
+       .name           = "sh_mobile_sdhi",
+       .id             = 2,
+       .num_resources  = ARRAY_SIZE(sdhi2_resources),
+       .resource       = sdhi2_resources,
+       .dev    = {
+               .platform_data  = &sdhi2_info,
+       },
+};
+
 /* KEY */
 #define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 }
 
@@ -267,11 +493,74 @@ static struct platform_device gpio_keys_device = {
        },
 };
 
+/* FSI-AK4648 */
+static struct sh_fsi_platform_info fsi_info = {
+       .port_a = {
+               .tx_id = SHDMA_SLAVE_FSI2A_TX,
+       },
+};
+
+static struct resource fsi_resources[] = {
+       [0] = {
+               .name   = "FSI",
+               .start  = 0xEC230000,
+               .end    = 0xEC230400 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = gic_spi(146),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device fsi_device = {
+       .name           = "sh_fsi2",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(fsi_resources),
+       .resource       = fsi_resources,
+       .dev    = {
+               .platform_data  = &fsi_info,
+       },
+};
+
+static struct asoc_simple_dai_init_info fsi2_ak4648_init_info = {
+       .fmt            = SND_SOC_DAIFMT_LEFT_J,
+       .codec_daifmt   = SND_SOC_DAIFMT_CBM_CFM,
+       .cpu_daifmt     = SND_SOC_DAIFMT_CBS_CFS,
+       .sysclk         = 11289600,
+};
+
+static struct asoc_simple_card_info fsi2_ak4648_info = {
+       .name           = "AK4648",
+       .card           = "FSI2A-AK4648",
+       .cpu_dai        = "fsia-dai",
+       .codec          = "ak4642-codec.0-0012",
+       .platform       = "sh_fsi2",
+       .codec_dai      = "ak4642-hifi",
+       .init           = &fsi2_ak4648_init_info,
+};
+
+static struct platform_device fsi_ak4648_device = {
+       .name   = "asoc-simple-card",
+       .dev    = {
+               .platform_data  = &fsi2_ak4648_info,
+       },
+};
+
 /* I2C */
 static struct pcf857x_platform_data pcf8575_pdata = {
        .gpio_base      = GPIO_PCF8575_BASE,
 };
 
+static struct i2c_board_info i2c0_devices[] = {
+       {
+               I2C_BOARD_INFO("ak4648", 0x12),
+       },
+       {
+               I2C_BOARD_INFO("r2025sd", 0x32),
+       }
+};
+
 static struct i2c_board_info i2c1_devices[] = {
        {
                I2C_BOARD_INFO("st1232-ts", 0x55),
@@ -289,10 +578,14 @@ static struct i2c_board_info i2c3_devices[] = {
 static struct platform_device *kzm_devices[] __initdata = {
        &smsc_device,
        &usb_host_device,
+       &usbhs_device,
        &lcdc_device,
        &mmc_device,
        &sdhi0_device,
+       &sdhi2_device,
        &gpio_keys_device,
+       &fsi_device,
+       &fsi_ak4648_device,
 };
 
 /*
@@ -350,6 +643,12 @@ device_initcall(as3711_enable_lcdc_backlight);
 
 static void __init kzm_init(void)
 {
+       regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers,
+                                    ARRAY_SIZE(fixed1v8_power_consumers), 1800000);
+       regulator_register_always_on(1, "fixed-2.8V", fixed2v8_power_consumers,
+                                    ARRAY_SIZE(fixed2v8_power_consumers), 2800000);
+       regulator_register_fixed(2, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
        sh73a0_pinmux_init();
 
        /* enable SCIFA4 */
@@ -427,15 +726,36 @@ static void __init kzm_init(void)
        gpio_request(GPIO_PORT15, NULL);
        gpio_direction_output(GPIO_PORT15, 1); /* power */
 
+       /* enable Micro SD */
+       gpio_request(GPIO_FN_SDHID2_0,          NULL);
+       gpio_request(GPIO_FN_SDHID2_1,          NULL);
+       gpio_request(GPIO_FN_SDHID2_2,          NULL);
+       gpio_request(GPIO_FN_SDHID2_3,          NULL);
+       gpio_request(GPIO_FN_SDHICMD2,          NULL);
+       gpio_request(GPIO_FN_SDHICLK2,          NULL);
+       gpio_request(GPIO_PORT14, NULL);
+       gpio_direction_output(GPIO_PORT14, 1); /* power */
+
        /* I2C 3 */
        gpio_request(GPIO_FN_PORT27_I2C_SCL3, NULL);
        gpio_request(GPIO_FN_PORT28_I2C_SDA3, NULL);
 
+       /* enable FSI2 port A (ak4648) */
+       gpio_request(GPIO_FN_FSIACK,    NULL);
+       gpio_request(GPIO_FN_FSIAILR,   NULL);
+       gpio_request(GPIO_FN_FSIAIBT,   NULL);
+       gpio_request(GPIO_FN_FSIAISLD,  NULL);
+       gpio_request(GPIO_FN_FSIAOSLD,  NULL);
+
+       /* enable USB */
+       gpio_request(GPIO_FN_VBUS_0,    NULL);
+
 #ifdef CONFIG_CACHE_L2X0
        /* Early BRESP enable, Shared attribute override enable, 64K*8way */
        l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff);
 #endif
 
+       i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices));
        i2c_register_board_info(1, i2c1_devices, ARRAY_SIZE(i2c1_devices));
        i2c_register_board_info(3, i2c3_devices, ARRAY_SIZE(i2c3_devices));
 
index 150122a446304071d23595c291b906b7b537707c..7ea2b31e31991355cb9304dfcafcc4ab6db6f628 100644 (file)
@@ -41,6 +41,8 @@
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/sh_flctl.h>
 #include <linux/pm_clock.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <linux/smsc911x.h>
 #include <linux/sh_intc.h>
 #include <linux/tca6416_keypad.h>
  * amixer set "HPOUTR Mixer DACH" on
  */
 
-/*
- * FIXME !!
- *
- * gpio_no_direction
- * gpio_pull_down
- * are quick_hack.
- *
- * current gpio frame work doesn't have
- * the method to control only pull up/down/free.
- * this function should be replaced by correct gpio function
- */
-static void __init gpio_no_direction(u32 addr)
+/* Fixed 3.3V and 1.8V regulators to be used by multiple devices */
+static struct regulator_consumer_supply fixed1v8_power_consumers[] =
 {
-       __raw_writeb(0x00, addr);
-}
+       /*
+        * J22 on mackerel switches mmcif.0 and sdhi.1 between 1.8V and 3.3V
+        * Since we cannot support both voltages, we support the default 1.8V
+        */
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"),
+       REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"),
+};
 
-static void __init gpio_pull_down(u32 addr)
+static struct regulator_consumer_supply fixed3v3_power_consumers[] =
 {
-       u8 data = __raw_readb(addr);
-
-       data &= 0x0F;
-       data |= 0xA0;
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"),
+       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.2"),
+       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.2"),
+};
 
-       __raw_writeb(data, addr);
-}
+/* Dummy supplies, where voltage doesn't matter */
+static struct regulator_consumer_supply dummy_supplies[] = {
+       REGULATOR_SUPPLY("vddvario", "smsc911x"),
+       REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+};
 
 /* MTD */
 static struct mtd_partition nor_flash_partitions[] = {
@@ -1409,6 +1412,12 @@ static void __init mackerel_init(void)
        u32 srcr4;
        struct clk *clk;
 
+       regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers,
+                                    ARRAY_SIZE(fixed1v8_power_consumers), 1800000);
+       regulator_register_always_on(1, "fixed-3.3V", fixed3v3_power_consumers,
+                                    ARRAY_SIZE(fixed3v3_power_consumers), 3300000);
+       regulator_register_fixed(2, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
        /* External clock source */
        clk_set_rate(&sh7372_dv_clki_clk, 27000000);
 
@@ -1458,11 +1467,11 @@ static void __init mackerel_init(void)
 
        /* USBHS0 */
        gpio_request(GPIO_FN_VBUS0_0, NULL);
-       gpio_pull_down(GPIO_PORT168CR); /* VBUS0_0 pull down */
+       gpio_request_pulldown(GPIO_PORT168CR); /* VBUS0_0 pull down */
 
        /* USBHS1 */
        gpio_request(GPIO_FN_VBUS0_1, NULL);
-       gpio_pull_down(GPIO_PORT167CR); /* VBUS0_1 pull down */
+       gpio_request_pulldown(GPIO_PORT167CR); /* VBUS0_1 pull down */
        gpio_request(GPIO_FN_IDIN_1_113, NULL);
 
        /* enable FSI2 port A (ak4643) */
@@ -1475,8 +1484,8 @@ static void __init mackerel_init(void)
 
        gpio_request(GPIO_PORT9,  NULL);
        gpio_request(GPIO_PORT10, NULL);
-       gpio_no_direction(GPIO_PORT9CR);  /* FSIAOBT needs no direction */
-       gpio_no_direction(GPIO_PORT10CR); /* FSIAOLR needs no direction */
+       gpio_direction_none(GPIO_PORT9CR);  /* FSIAOBT needs no direction */
+       gpio_direction_none(GPIO_PORT10CR); /* FSIAOLR needs no direction */
 
        intc_set_priority(IRQ_FSI, 3); /* irq priority FSI(3) > SMSC911X(2) */
 
@@ -1614,20 +1623,20 @@ static void __init mackerel_init(void)
 
        platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices));
 
-       sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device);
-       sh7372_add_device_to_domain(&sh7372_a4lc, &hdmi_lcdc_device);
-       sh7372_add_device_to_domain(&sh7372_a4lc, &meram_device);
-       sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs0_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs1_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &nand_flash_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4lc, &lcdc_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4lc, &hdmi_lcdc_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4lc, &meram_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4mp, &fsi_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usbhs0_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usbhs1_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &nand_flash_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sh_mmcif_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi0_device);
 #if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
-       sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi1_device);
 #endif
-       sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi2_device);
-       sh7372_add_device_to_domain(&sh7372_a4r, &ceu_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi2_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4r, &ceu_device);
 
        hdmi_init_pm_clock();
        sh7372_pm_init();
index 14de3787cafcc7193abefe6e4c1c589988a76acc..3a528cf4366cb6addff63fb9e7032948f71f49e2 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/dma-mapping.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <linux/smsc911x.h>
 #include <mach/hardware.h>
 #include <mach/r8a7779.h>
 #include <asm/hardware/gic.h>
 #include <asm/traps.h>
 
+/* Dummy supplies, where voltage doesn't matter */
+static struct regulator_consumer_supply dummy_supplies[] = {
+       REGULATOR_SUPPLY("vddvario", "smsc911x"),
+       REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+};
+
 /* SMSC LAN89218 */
 static struct resource smsc911x_resources[] = {
        [0] = {
@@ -73,6 +81,8 @@ static struct platform_device *marzen_devices[] __initdata = {
 
 static void __init marzen_init(void)
 {
+       regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
+
        r8a7779_pinmux_init();
 
        /* SCIF2 (CN18: DEBUG0) */
index 26eea5f2105420116bb5332633d4a1385ed949d7..ad5fccc7b5e711e68f6b48f743b20ac21279c700 100644 (file)
 /* CPG registers */
 #define FRQCRA         0xe6150000
 #define FRQCRB         0xe6150004
+#define VCLKCR1                0xE6150008
+#define VCLKCR2                0xE615000c
 #define FRQCRC         0xe61500e0
+#define FSIACKCR       0xe6150018
 #define PLLC01CR       0xe6150028
 
 #define SUBCKCR                0xe6150080
@@ -54,6 +57,8 @@
 #define MSTPSR2                0xe6150040
 #define MSTPSR3                0xe6150048
 #define MSTPSR4                0xe615004c
+#define FSIBCKCR       0xe6150090
+#define HDMICKCR       0xe6150094
 #define SMSTPCR0       0xe6150130
 #define SMSTPCR1       0xe6150134
 #define SMSTPCR2       0xe6150138
@@ -271,6 +276,13 @@ static struct clk usb24_clk = {
        .parent         = &usb24s_clk,
 };
 
+/* External FSIACK/FSIBCK clock */
+static struct clk fsiack_clk = {
+};
+
+static struct clk fsibck_clk = {
+};
+
 struct clk *main_clks[] = {
        &extalr_clk,
        &extal1_clk,
@@ -288,6 +300,8 @@ struct clk *main_clks[] = {
        &pllc1_div2_clk,
        &usb24s_clk,
        &usb24_clk,
+       &fsiack_clk,
+       &fsibck_clk,
 };
 
 static void div4_kick(struct clk *clk)
@@ -313,6 +327,107 @@ static struct clk_div4_table div4_table = {
        .kick = div4_kick,
 };
 
+/* DIV6 reparent */
+enum {
+       DIV6_HDMI,
+       DIV6_VCLK1, DIV6_VCLK2,
+       DIV6_FSIA, DIV6_FSIB,
+       DIV6_REPARENT_NR,
+};
+
+static struct clk *hdmi_parent[] = {
+       [0] = &pllc1_div2_clk,
+       [1] = &system_clk,
+       [2] = &dv_clk
+};
+
+static struct clk *vclk_parents[8] = {
+       [0] = &pllc1_div2_clk,
+       [2] = &dv_clk,
+       [3] = &usb24s_clk,
+       [4] = &extal1_div2_clk,
+       [5] = &extalr_clk,
+};
+
+static struct clk *fsia_parents[] = {
+       [0] = &pllc1_div2_clk,
+       [1] = &fsiack_clk, /* external clock */
+};
+
+static struct clk *fsib_parents[] = {
+       [0] = &pllc1_div2_clk,
+       [1] = &fsibck_clk, /* external clock */
+};
+
+static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
+       [DIV6_HDMI] = SH_CLK_DIV6_EXT(HDMICKCR, 0,
+                                     hdmi_parent, ARRAY_SIZE(hdmi_parent), 6, 2),
+       [DIV6_VCLK1] = SH_CLK_DIV6_EXT(VCLKCR1, 0,
+                                      vclk_parents, ARRAY_SIZE(vclk_parents), 12, 3),
+       [DIV6_VCLK2] = SH_CLK_DIV6_EXT(VCLKCR2, 0,
+                                      vclk_parents, ARRAY_SIZE(vclk_parents), 12, 3),
+       [DIV6_FSIA] = SH_CLK_DIV6_EXT(FSIACKCR, 0,
+                                     fsia_parents, ARRAY_SIZE(fsia_parents), 6, 2),
+       [DIV6_FSIB] = SH_CLK_DIV6_EXT(FSIBCKCR, 0,
+                                     fsib_parents, ARRAY_SIZE(fsib_parents), 6, 2),
+};
+
+/* HDMI1/2 clock */
+static unsigned long hdmi12_recalc(struct clk *clk)
+{
+       u32 val = __raw_readl(HDMICKCR);
+       int shift = (int)clk->priv;
+
+       val >>= shift;
+       val &= 0x3;
+
+       return clk->parent->rate / (1 << val);
+};
+
+static int hdmi12_set_rate(struct clk *clk, unsigned long rate)
+{
+       u32 val, mask;
+       int i, shift;
+
+       for (i = 0; i < 3; i++)
+               if (rate == clk->parent->rate / (1 << i))
+                       goto find;
+       return -ENODEV;
+
+find:
+       shift = (int)clk->priv;
+
+       val = __raw_readl(HDMICKCR);
+       mask = ~(0x3 << shift);
+       val = (val & mask) | i << shift;
+       __raw_writel(val, HDMICKCR);
+
+       return 0;
+};
+
+static struct sh_clk_ops hdmi12_clk_ops = {
+       .recalc         = hdmi12_recalc,
+       .set_rate       = hdmi12_set_rate,
+};
+
+static struct clk hdmi1_clk = {
+       .ops            = &hdmi12_clk_ops,
+       .priv           = (void *)9,
+       .parent         = &div6_reparent_clks[DIV6_HDMI],  /* late install */
+};
+
+static struct clk hdmi2_clk = {
+       .ops            = &hdmi12_clk_ops,
+       .priv           = (void *)11,
+       .parent         = &div6_reparent_clks[DIV6_HDMI], /* late install */
+};
+
+static struct clk *late_main_clks[] = {
+       &hdmi1_clk,
+       &hdmi2_clk,
+};
+
+/* MSTP */
 enum {
        DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_HP,
        DIV4_HPP, DIV4_USBP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP,
@@ -343,11 +458,12 @@ static struct clk div6_clks[DIV6_NR] = {
 };
 
 enum {
-       MSTP125,
+       MSTP128, MSTP127, MSTP125,
        MSTP116, MSTP111, MSTP100, MSTP117,
 
        MSTP230,
        MSTP222,
+       MSTP218, MSTP217, MSTP216, MSTP214,
        MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
 
        MSTP329, MSTP328, MSTP323, MSTP320,
@@ -360,6 +476,8 @@ enum {
 };
 
 static struct clk mstp_clks[MSTP_NR] = {
+       [MSTP128] = SH_CLK_MSTP32(&div4_clks[DIV4_S],   SMSTPCR1, 28, 0), /* CEU21 */
+       [MSTP127] = SH_CLK_MSTP32(&div4_clks[DIV4_S],   SMSTPCR1, 27, 0), /* CEU20 */
        [MSTP125] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */
        [MSTP117] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   SMSTPCR1, 17, 0), /* LCDC1 */
        [MSTP116] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */
@@ -368,6 +486,10 @@ static struct clk mstp_clks[MSTP_NR] = {
 
        [MSTP230] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 30, 0), /* SCIFA6 */
        [MSTP222] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 22, 0), /* SCIFA7 */
+       [MSTP218] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],  SMSTPCR2, 18, 0), /* DMAC1 */
+       [MSTP217] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],  SMSTPCR2, 17, 0), /* DMAC2 */
+       [MSTP216] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],  SMSTPCR2, 16, 0), /* DMAC3 */
+       [MSTP214] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],  SMSTPCR2, 14, 0), /* USBDMAC */
        [MSTP207] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2,  7, 0), /* SCIFA5 */
        [MSTP206] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2,  6, 0), /* SCIFB */
        [MSTP204] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2,  4, 0), /* SCIFA0 */
@@ -408,6 +530,12 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("pllc1_clk",              &pllc1_clk),
        CLKDEV_CON_ID("pllc1_div2_clk",         &pllc1_div2_clk),
        CLKDEV_CON_ID("usb24s",                 &usb24s_clk),
+       CLKDEV_CON_ID("hdmi1",                  &hdmi1_clk),
+       CLKDEV_CON_ID("hdmi2",                  &hdmi2_clk),
+       CLKDEV_CON_ID("video1",                 &div6_reparent_clks[DIV6_VCLK1]),
+       CLKDEV_CON_ID("video2",                 &div6_reparent_clks[DIV6_VCLK2]),
+       CLKDEV_CON_ID("fsiack",                 &fsiack_clk),
+       CLKDEV_CON_ID("fsibck",                 &fsibck_clk),
 
        /* DIV4 clocks */
        CLKDEV_CON_ID("i_clk",                  &div4_clks[DIV4_I]),
@@ -430,6 +558,8 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("i2c-sh_mobile.0",        &mstp_clks[MSTP116]),
        CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1",    &mstp_clks[MSTP117]),
        CLKDEV_DEV_ID("sh_tmu.0",               &mstp_clks[MSTP125]),
+       CLKDEV_DEV_ID("sh_mobile_ceu.0",        &mstp_clks[MSTP127]),
+       CLKDEV_DEV_ID("sh_mobile_ceu.1",        &mstp_clks[MSTP128]),
 
        CLKDEV_DEV_ID("sh-sci.4",               &mstp_clks[MSTP200]),
        CLKDEV_DEV_ID("sh-sci.3",               &mstp_clks[MSTP201]),
@@ -438,7 +568,10 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("sh-sci.0",               &mstp_clks[MSTP204]),
        CLKDEV_DEV_ID("sh-sci.8",               &mstp_clks[MSTP206]),
        CLKDEV_DEV_ID("sh-sci.5",               &mstp_clks[MSTP207]),
-
+       CLKDEV_DEV_ID("sh-dma-engine.3",        &mstp_clks[MSTP214]),
+       CLKDEV_DEV_ID("sh-dma-engine.2",        &mstp_clks[MSTP216]),
+       CLKDEV_DEV_ID("sh-dma-engine.1",        &mstp_clks[MSTP217]),
+       CLKDEV_DEV_ID("sh-dma-engine.0",        &mstp_clks[MSTP218]),
        CLKDEV_DEV_ID("sh-sci.7",               &mstp_clks[MSTP222]),
        CLKDEV_DEV_ID("sh-sci.6",               &mstp_clks[MSTP230]),
 
@@ -459,6 +592,10 @@ static struct clk_lookup lookups[] = {
        CLKDEV_ICK_ID("phy",    "renesas_usbhs",        &mstp_clks[MSTP406]),
        CLKDEV_ICK_ID("pci",    "renesas_usbhs",        &div4_clks[DIV4_USBP]),
        CLKDEV_ICK_ID("usb24",  "renesas_usbhs",        &usb24_clk),
+       CLKDEV_ICK_ID("ick",    "sh-mobile-hdmi",       &div6_reparent_clks[DIV6_HDMI]),
+
+       CLKDEV_ICK_ID("icka", "sh_fsi2",        &div6_reparent_clks[DIV6_FSIA]),
+       CLKDEV_ICK_ID("ickb", "sh_fsi2",        &div6_reparent_clks[DIV6_FSIB]),
 };
 
 void __init r8a7740_clock_init(u8 md_ck)
@@ -495,7 +632,14 @@ void __init r8a7740_clock_init(u8 md_ck)
                ret = sh_clk_div6_register(div6_clks, DIV6_NR);
 
        if (!ret)
-               ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+               ret = sh_clk_div6_reparent_register(div6_reparent_clks,
+                                                   DIV6_REPARENT_NR);
+
+       if (!ret)
+               ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
+
+       for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++)
+               ret = clk_register(late_main_clks[k]);
 
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
index 7d6e9fe47b56a812e7fbb7c1343da1eb9d045141..339c62c824d5178ba1a22ef1fac082edd65cd9ba 100644 (file)
@@ -162,7 +162,7 @@ void __init r8a7779_clock_init(void)
                ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
 
        if (!ret)
-               ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+               ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
 
        for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++)
                ret = clk_register(late_main_clks[k]);
index 006e7b5d304c36207780ebbcde9f34a833ea2605..162b791b89847a5ec3f0b06c3af3c12ca05e2173 100644 (file)
@@ -344,7 +344,7 @@ void __init sh7367_clock_init(void)
                ret = sh_clk_div6_register(div6_clks, DIV6_NR);
 
        if (!ret)
-               ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+               ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
 
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
index 94d1f88246d3fc780267ad698b9d43e73c339eaa..5a2894b1c96553976b6e4f089f832cb4a2e6a05d 100644 (file)
@@ -704,7 +704,7 @@ void __init sh7372_clock_init(void)
                ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_REPARENT_NR);
 
        if (!ret)
-               ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+               ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
 
        for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++)
                ret = clk_register(late_main_clks[k]);
index 0798a15936c3cc41a6d51c70e909503d3f02afd8..85f2a3ec2c4431d324400bf52bcb628decc1fcf5 100644 (file)
@@ -355,7 +355,7 @@ void __init sh7377_clock_init(void)
                ret = sh_clk_div6_register(div6_clks, DIV6_NR);
 
        if (!ret)
-               ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+               ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
 
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
index 3946c4ba2aa813f0cea841b5c66b622c5f0d3950..7f8da18a8580a234a0becb3bc8ec360b39d98202 100644 (file)
@@ -475,9 +475,9 @@ static struct clk *late_main_clks[] = {
 
 enum { MSTP001,
        MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, MSTP118, MSTP116, MSTP100,
-       MSTP219, MSTP218,
+       MSTP219, MSTP218, MSTP217,
        MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
-       MSTP331, MSTP329, MSTP325, MSTP323,
+       MSTP331, MSTP329, MSTP328, MSTP325, MSTP323, MSTP322,
        MSTP314, MSTP313, MSTP312, MSTP311,
        MSTP303, MSTP302, MSTP301, MSTP300,
        MSTP411, MSTP410, MSTP403,
@@ -498,6 +498,7 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */
        [MSTP219] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 19, 0), /* SCIFA7 */
        [MSTP218] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 18, 0), /* SY-DMAC */
+       [MSTP217] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 17, 0), /* MP-DMAC */
        [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
        [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
        [MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */
@@ -507,8 +508,10 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
        [MSTP331] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 31, 0), /* SCIFA6 */
        [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
+       [MSTP328] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 28, 0), /*FSI*/
        [MSTP325] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 25, 0), /* IrDA */
        [MSTP323] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 23, 0), /* IIC1 */
+       [MSTP322] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 22, 0), /* USB */
        [MSTP314] = MSTP(&div6_clks[DIV6_SDHI0], SMSTPCR3, 14, 0), /* SDHI0 */
        [MSTP313] = MSTP(&div6_clks[DIV6_SDHI1], SMSTPCR3, 13, 0), /* SDHI1 */
        [MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMCIF0 */
@@ -553,6 +556,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */
        CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP219]), /* SCIFA7 */
        CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), /* SY-DMAC */
+       CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP217]), /* MP-DMAC */
        CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
        CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP206]), /* SCIFB */
        CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
@@ -562,8 +566,10 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
        CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */
        CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
+       CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI */
        CLKDEV_DEV_ID("sh_irda.0", &mstp_clks[MSTP325]), /* IrDA */
        CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* I2C1 */
+       CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP322]), /* USB */
        CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
        CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
        CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMCIF0 */
@@ -612,7 +618,7 @@ void __init sh73a0_clock_init(void)
                ret = sh_clk_div6_reparent_register(div6_clks, DIV6_NR);
 
        if (!ret)
-               ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+               ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
 
        for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++)
                ret = clk_register(late_main_clks[k]);
index 01e2bc014f1501f41f2f2a9b18a7596bb686ac27..45e61dada030ba263fd721d4210d477e8664faba 100644 (file)
@@ -77,6 +77,7 @@ extern void r8a7779_add_standard_devices(void);
 extern void r8a7779_clock_init(void);
 extern void r8a7779_pinmux_init(void);
 extern void r8a7779_pm_init(void);
+extern void r8a7740_meram_workaround(void);
 
 extern unsigned int r8a7779_get_core_count(void);
 extern int r8a7779_platform_cpu_kill(unsigned int cpu);
diff --git a/arch/arm/mach-shmobile/include/mach/dma-register.h b/arch/arm/mach-shmobile/include/mach/dma-register.h
new file mode 100644 (file)
index 0000000..97c40bd
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * SH-ARM CPU-specific DMA definitions, used by both DMA drivers
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp
+ *
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * Based on arch/sh/include/cpu-sh4/cpu/dma-register.h
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef DMA_REGISTER_H
+#define DMA_REGISTER_H
+
+/*
+ *             Direct Memory Access Controller
+ */
+
+/* Transmit sizes and respective CHCR register values */
+enum {
+       XMIT_SZ_8BIT            = 0,
+       XMIT_SZ_16BIT           = 1,
+       XMIT_SZ_32BIT           = 2,
+       XMIT_SZ_64BIT           = 7,
+       XMIT_SZ_128BIT          = 3,
+       XMIT_SZ_256BIT          = 4,
+       XMIT_SZ_512BIT          = 5,
+};
+
+/* log2(size / 8) - used to calculate number of transfers */
+static const unsigned int dma_ts_shift[] = {
+       [XMIT_SZ_8BIT]          = 0,
+       [XMIT_SZ_16BIT]         = 1,
+       [XMIT_SZ_32BIT]         = 2,
+       [XMIT_SZ_64BIT]         = 3,
+       [XMIT_SZ_128BIT]        = 4,
+       [XMIT_SZ_256BIT]        = 5,
+       [XMIT_SZ_512BIT]        = 6,
+};
+
+#define TS_LOW_BIT     0x3 /* --xx */
+#define TS_HI_BIT      0xc /* xx-- */
+
+#define TS_LOW_SHIFT   (3)
+#define TS_HI_SHIFT    (20 - 2)        /* 2 bits for shifted low TS */
+
+#define TS_INDEX2VAL(i) \
+       ((((i) & TS_LOW_BIT) << TS_LOW_SHIFT) |\
+        (((i) & TS_HI_BIT)  << TS_HI_SHIFT))
+
+#define CHCR_TX(xmit_sz) (DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL((xmit_sz)))
+#define CHCR_RX(xmit_sz) (DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL((xmit_sz)))
+
+
+/*
+ *             USB High-Speed DMAC
+ */
+/* Transmit sizes and respective CHCR register values */
+enum {
+       USBTS_XMIT_SZ_8BYTE             = 0,
+       USBTS_XMIT_SZ_16BYTE            = 1,
+       USBTS_XMIT_SZ_32BYTE            = 2,
+};
+
+/* log2(size / 8) - used to calculate number of transfers */
+static const unsigned int dma_usbts_shift[] = {
+       [USBTS_XMIT_SZ_8BYTE]   = 3,
+       [USBTS_XMIT_SZ_16BYTE]  = 4,
+       [USBTS_XMIT_SZ_32BYTE]  = 5,
+};
+
+#define USBTS_LOW_BIT  0x3 /* --xx */
+#define USBTS_HI_BIT   0x0 /* ---- */
+
+#define USBTS_LOW_SHIFT        6
+#define USBTS_HI_SHIFT 0
+
+#define USBTS_INDEX2VAL(i) (((i) & 3) << 6)
+
+#endif /* DMA_REGISTER_H */
index de795b42232a8940720ed8e44ca3bc7da7431372..844507d937cbc2937f6489046bd0b9898d2d1f74 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/sh_pfc.h>
+#include <linux/io.h>
 
 #ifdef CONFIG_GPIOLIB
 
@@ -27,4 +28,35 @@ static inline int irq_to_gpio(unsigned int irq)
 
 #endif /* CONFIG_GPIOLIB */
 
+/*
+ * FIXME !!
+ *
+ * current gpio frame work doesn't have
+ * the method to control only pull up/down/free.
+ * this function should be replaced by correct gpio function
+ */
+static inline void __init gpio_direction_none(u32 addr)
+{
+       __raw_writeb(0x00, addr);
+}
+
+static inline void __init gpio_request_pullup(u32 addr)
+{
+       u8 data = __raw_readb(addr);
+
+       data &= 0x0F;
+       data |= 0xC0;
+       __raw_writeb(data, addr);
+}
+
+static inline void __init gpio_request_pulldown(u32 addr)
+{
+       u8 data = __raw_readb(addr);
+
+       data &= 0x0F;
+       data |= 0xA0;
+
+       __raw_writeb(data, addr);
+}
+
 #endif /* __ASM_ARCH_GPIO_H */
diff --git a/arch/arm/mach-shmobile/include/mach/pm-rmobile.h b/arch/arm/mach-shmobile/include/mach/pm-rmobile.h
new file mode 100644 (file)
index 0000000..5a40284
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef PM_RMOBILE_H
+#define PM_RMOBILE_H
+
+#include <linux/pm_domain.h>
+
+struct platform_device;
+
+struct rmobile_pm_domain {
+       struct generic_pm_domain genpd;
+       struct dev_power_governor *gov;
+       int (*suspend)(void);
+       void (*resume)(void);
+       unsigned int bit_shift;
+       bool no_debug;
+};
+
+static inline
+struct rmobile_pm_domain *to_rmobile_pd(struct generic_pm_domain *d)
+{
+       return container_of(d, struct rmobile_pm_domain, genpd);
+}
+
+#ifdef CONFIG_PM
+extern void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd);
+extern void rmobile_add_device_to_domain(struct rmobile_pm_domain *rmobile_pd,
+                                       struct platform_device *pdev);
+extern void rmobile_pm_add_subdomain(struct rmobile_pm_domain *rmobile_pd,
+                                   struct rmobile_pm_domain *rmobile_sd);
+#else
+#define rmobile_init_pm_domain(pd) do { } while (0)
+#define rmobile_add_device_to_domain(pd, pdev) do { } while (0)
+#define rmobile_pm_add_subdomain(pd, sd) do { } while (0)
+#endif /* CONFIG_PM */
+
+#endif /* PM_RMOBILE_H */
index 9d447abb969c22de557005e6e595a836317abb12..7143147780df55f6e17a689e9cc67ed2a9cd17e9 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef __ASM_R8A7740_H__
 #define __ASM_R8A7740_H__
 
+#include <mach/pm-rmobile.h>
+
 /*
  * MD_CKx pin
  */
@@ -139,7 +141,7 @@ enum {
        GPIO_FN_DBGMD10,        GPIO_FN_DBGMD11,        GPIO_FN_DBGMD20,
        GPIO_FN_DBGMD21,
 
-       /* FSI */
+       /* FSI-A */
        GPIO_FN_FSIAISLD_PORT0,         /* FSIAISLD Port 0/5 */
        GPIO_FN_FSIAISLD_PORT5,
        GPIO_FN_FSIASPDIF_PORT9,        /* FSIASPDIF Port 9/18 */
@@ -150,6 +152,9 @@ enum {
        GPIO_FN_FSIACK,         GPIO_FN_FSIAILR,
        GPIO_FN_FSIAIBT,
 
+       /* FSI-B */
+       GPIO_FN_FSIBCK,
+
        /* FMSI */
        GPIO_FN_FMSISLD_PORT1, /* FMSISLD Port 1/6 */
        GPIO_FN_FMSISLD_PORT6,
@@ -565,6 +570,10 @@ enum {
        GPIO_FN_RESETP_PULLUP,
        GPIO_FN_RESETP_PLAIN,
 
+       /* HDMI */
+       GPIO_FN_HDMI_HPD,
+       GPIO_FN_HDMI_CEC,
+
        /* SDENC */
        GPIO_FN_SDENC_CPG,
        GPIO_FN_SDENC_DV_CLKI,
@@ -581,4 +590,26 @@ enum {
        GPIO_FN_TRACEAUD_FROM_MEMC,
 };
 
+/* DMA slave IDs */
+enum {
+       SHDMA_SLAVE_INVALID,
+       SHDMA_SLAVE_SDHI0_RX,
+       SHDMA_SLAVE_SDHI0_TX,
+       SHDMA_SLAVE_SDHI1_RX,
+       SHDMA_SLAVE_SDHI1_TX,
+       SHDMA_SLAVE_SDHI2_RX,
+       SHDMA_SLAVE_SDHI2_TX,
+       SHDMA_SLAVE_FSIA_RX,
+       SHDMA_SLAVE_FSIA_TX,
+       SHDMA_SLAVE_FSIB_TX,
+       SHDMA_SLAVE_USBHS_TX,
+       SHDMA_SLAVE_USBHS_RX,
+};
+
+#ifdef CONFIG_PM
+extern struct rmobile_pm_domain r8a7740_pd_a4s;
+extern struct rmobile_pm_domain r8a7740_pd_a3sp;
+extern struct rmobile_pm_domain r8a7740_pd_a4lc;
+#endif /* CONFIG_PM */
+
 #endif /* __ASM_R8A7740_H__ */
index 915d0093da0853280dc55eb06ba18d88cc1c3a8d..b59048e6d8fd7302717b9bb4f9359eae95ce10e5 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/sh_clk.h>
 #include <linux/pm_domain.h>
+#include <mach/pm-rmobile.h>
 
 /*
  * Pin Function Controller:
@@ -477,42 +478,16 @@ extern struct clk sh7372_fsibck_clk;
 extern struct clk sh7372_fsidiva_clk;
 extern struct clk sh7372_fsidivb_clk;
 
-struct platform_device;
-
-struct sh7372_pm_domain {
-       struct generic_pm_domain genpd;
-       struct dev_power_governor *gov;
-       int (*suspend)(void);
-       void (*resume)(void);
-       unsigned int bit_shift;
-       bool no_debug;
-};
-
-static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d)
-{
-       return container_of(d, struct sh7372_pm_domain, genpd);
-}
-
 #ifdef CONFIG_PM
-extern struct sh7372_pm_domain sh7372_a4lc;
-extern struct sh7372_pm_domain sh7372_a4mp;
-extern struct sh7372_pm_domain sh7372_d4;
-extern struct sh7372_pm_domain sh7372_a4r;
-extern struct sh7372_pm_domain sh7372_a3rv;
-extern struct sh7372_pm_domain sh7372_a3ri;
-extern struct sh7372_pm_domain sh7372_a4s;
-extern struct sh7372_pm_domain sh7372_a3sp;
-extern struct sh7372_pm_domain sh7372_a3sg;
-
-extern void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd);
-extern void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
-                                       struct platform_device *pdev);
-extern void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
-                                   struct sh7372_pm_domain *sh7372_sd);
-#else
-#define sh7372_init_pm_domain(pd) do { } while(0)
-#define sh7372_add_device_to_domain(pd, pdev) do { } while(0)
-#define sh7372_pm_add_subdomain(pd, sd) do { } while(0)
+extern struct rmobile_pm_domain sh7372_pd_a4lc;
+extern struct rmobile_pm_domain sh7372_pd_a4mp;
+extern struct rmobile_pm_domain sh7372_pd_d4;
+extern struct rmobile_pm_domain sh7372_pd_a4r;
+extern struct rmobile_pm_domain sh7372_pd_a3rv;
+extern struct rmobile_pm_domain sh7372_pd_a3ri;
+extern struct rmobile_pm_domain sh7372_pd_a4s;
+extern struct rmobile_pm_domain sh7372_pd_a3sp;
+extern struct rmobile_pm_domain sh7372_pd_a3sg;
 #endif /* CONFIG_PM */
 
 extern void sh7372_intcs_suspend(void);
index 398e2c10913bc3581b145c2a96192d66af011d1d..fe950f25d793966750f3e506034a831bee5d86ad 100644 (file)
@@ -516,6 +516,13 @@ enum {
        SHDMA_SLAVE_SDHI2_RX,
        SHDMA_SLAVE_MMCIF_TX,
        SHDMA_SLAVE_MMCIF_RX,
+       SHDMA_SLAVE_FSI2A_TX,
+       SHDMA_SLAVE_FSI2A_RX,
+       SHDMA_SLAVE_FSI2B_TX,
+       SHDMA_SLAVE_FSI2B_RX,
+       SHDMA_SLAVE_FSI2C_TX,
+       SHDMA_SLAVE_FSI2C_RX,
+       SHDMA_SLAVE_FSI2D_RX,
 };
 
 /*
index 09c42afcb22dae848551c1306b922866fc78a957..9a69a31918ba074d01501f210bfe162e0a216b56 100644 (file)
@@ -71,10 +71,12 @@ enum {
        DMAC3_1_DEI0, DMAC3_1_DEI1, DMAC3_1_DEI2, DMAC3_1_DEI3,
        DMAC3_2_DEI4, DMAC3_2_DEI5, DMAC3_2_DADERR,
        SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM,
+       HDMI,
        USBH_INT, USBH_OHCI, USBH_EHCI, USBH_PME, USBH_BIND,
        RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF,
        SPU2_0, SPU2_1,
        FSI, FMSI,
+       HDMI_SSS, HDMI_KEY,
        IPMMU,
        AP_ARM_CTIIRQ, AP_ARM_PMURQ,
        MFIS2,
@@ -182,6 +184,7 @@ static struct intc_vect intca_vectors[] __initdata = {
        INTC_VECT(USBH_EHCI,            0x1580),
        INTC_VECT(USBH_PME,             0x15A0),
        INTC_VECT(USBH_BIND,            0x15C0),
+       INTC_VECT(HDMI,                 0x1700),
        INTC_VECT(RSPI_OVRF,            0x1780),
        INTC_VECT(RSPI_SPTEF,           0x17A0),
        INTC_VECT(RSPI_SPRF,            0x17C0),
@@ -189,6 +192,8 @@ static struct intc_vect intca_vectors[] __initdata = {
        INTC_VECT(SPU2_1,               0x1820),
        INTC_VECT(FSI,                  0x1840),
        INTC_VECT(FMSI,                 0x1860),
+       INTC_VECT(HDMI_SSS,             0x18A0),
+       INTC_VECT(HDMI_KEY,             0x18C0),
        INTC_VECT(IPMMU,                0x1920),
        INTC_VECT(AP_ARM_CTIIRQ,        0x1980),
        INTC_VECT(AP_ARM_PMURQ,         0x19A0),
@@ -304,11 +309,11 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = {
            USBH_EHCI, USBH_PME, USBH_BIND, 0 } },
          /* IMR3A3 / IMCR3A3 */
        { /* IMR4A3 / IMCR4A3 */ 0xe6950090, 0xe69500d0, 8,
-         { 0, 0, 0, 0,
+         { HDMI, 0, 0, 0,
            RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF, 0 } },
        { /* IMR5A3 / IMCR5A3 */ 0xe6950094, 0xe69500d4, 8,
          { SPU2_0, SPU2_1, FSI, FMSI,
-           0, 0, 0, 0 } },
+           0, HDMI_SSS, HDMI_KEY, 0 } },
        { /* IMR6A3 / IMCR6A3 */ 0xe6950098, 0xe69500d8, 8,
          { 0, IPMMU, 0, 0,
            AP_ARM_CTIIRQ, AP_ARM_PMURQ, 0, 0 } },
@@ -353,10 +358,10 @@ static struct intc_prio_reg intca_prio_registers[] __initdata = {
        { 0xe6950014, 0, 16, 4, /* IPRFA3 */ { USBH2, 0, 0, 0 } },
                                /* IPRGA3 */
                                /* IPRHA3 */
-                               /* IPRIA3 */
+       { 0xe6950020, 0, 16, 4, /* IPRIA3 */ { HDMI, 0, 0, 0 } },
        { 0xe6950024, 0, 16, 4, /* IPRJA3 */ { RSPI, 0, 0, 0 } },
        { 0xe6950028, 0, 16, 4, /* IPRKA3 */ { SPU2, 0, FSI, FMSI } },
-                               /* IPRLA3 */
+       { 0xe695002c, 0, 16, 4, /* IPRLA3 */ { 0, HDMI_SSS, HDMI_KEY, 0 } },
        { 0xe6950030, 0, 16, 4, /* IPRMA3 */ { IPMMU, 0, 0, 0 } },
        { 0xe6950034, 0, 16, 4, /* IPRNA3 */ { AP_ARM2, 0, 0, 0 } },
        { 0xe6950038, 0, 16, 4, /* IPROA3 */ { MFIS2, CPORTR2S,
index 670fe1869dbc4e9488651ab336f2da0167e41965..ce9e7fa5cc8a6f4c2c2cba6efa31014fa6303b9f 100644 (file)
@@ -169,7 +169,7 @@ enum {
        DBGMD10_MARK,   DBGMD11_MARK,   DBGMD20_MARK,
        DBGMD21_MARK,
 
-       /* FSI */
+       /* FSI-A */
        FSIAISLD_PORT0_MARK,    /* FSIAISLD Port 0/5 */
        FSIAISLD_PORT5_MARK,
        FSIASPDIF_PORT9_MARK,   /* FSIASPDIF Port 9/18 */
@@ -178,6 +178,9 @@ enum {
        FSIAOBT_MARK,   FSIAOSLD_MARK,  FSIAOMC_MARK,
        FSIACK_MARK,    FSIAILR_MARK,   FSIAIBT_MARK,
 
+       /* FSI-B */
+       FSIBCK_MARK,
+
        /* FMSI */
        FMSISLD_PORT1_MARK, /* FMSISLD Port 1/6 */
        FMSISLD_PORT6_MARK,
@@ -560,6 +563,9 @@ enum {
        /* SDENC */
        SDENC_CPG_MARK,         SDENC_DV_CLKI_MARK,
 
+       /* HDMI */
+       HDMI_HPD_MARK, HDMI_CEC_MARK,
+
        /* DEBUG */
        EDEBGREQ_PULLUP_MARK,   /* for JTAG */
        EDEBGREQ_PULLDOWN_MARK,
@@ -771,6 +777,7 @@ static pinmux_enum_t pinmux_data[] = {
 
        /* Port11 */
        PINMUX_DATA(FSIACK_MARK,                PORT11_FN1),
+       PINMUX_DATA(FSIBCK_MARK,                PORT11_FN2),
        PINMUX_DATA(IRQ2_PORT11_MARK,           PORT11_FN0,     MSEL1CR_2_0),
 
        /* Port12 */
@@ -1254,7 +1261,7 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(A21_MARK,                   PORT120_FN1),
        PINMUX_DATA(MSIOF0_RSYNC_MARK,          PORT120_FN2),
        PINMUX_DATA(MSIOF1_TSYNC_PORT120_MARK,  PORT120_FN3,    MSEL4CR_10_0),
-       PINMUX_DATA(IRQ7_PORT120_MARK,          PORT120_FN0,    MSEL1CR_7_0),
+       PINMUX_DATA(IRQ7_PORT120_MARK,          PORT120_FN0,    MSEL1CR_7_1),
 
        /* Port121 */
        PINMUX_DATA(A20_MARK,                   PORT121_FN1),
@@ -1616,13 +1623,15 @@ static pinmux_enum_t pinmux_data[] = {
 
        /* Port209 */
        PINMUX_DATA(VBUS_MARK,                  PORT209_FN1),
-       PINMUX_DATA(IRQ7_PORT209_MARK,          PORT209_FN0,    MSEL1CR_7_1),
+       PINMUX_DATA(IRQ7_PORT209_MARK,          PORT209_FN0,    MSEL1CR_7_0),
 
        /* Port210 */
        PINMUX_DATA(IRQ9_PORT210_MARK,          PORT210_FN0,    MSEL1CR_9_1),
+       PINMUX_DATA(HDMI_HPD_MARK,              PORT210_FN1),
 
        /* Port211 */
        PINMUX_DATA(IRQ16_PORT211_MARK,         PORT211_FN0,    MSEL1CR_16_1),
+       PINMUX_DATA(HDMI_CEC_MARK,              PORT211_FN1),
 
        /* LCDC select */
        PINMUX_DATA(LCDC0_SELECT_MARK,                          MSEL3CR_6_0),
@@ -1691,7 +1700,7 @@ static struct pinmux_gpio pinmux_gpios[] = {
        GPIO_FN(DBGMD10),       GPIO_FN(DBGMD11),       GPIO_FN(DBGMD20),
        GPIO_FN(DBGMD21),
 
-       /* FSI */
+       /* FSI-A */
        GPIO_FN(FSIAISLD_PORT0),        /* FSIAISLD Port 0/5 */
        GPIO_FN(FSIAISLD_PORT5),
        GPIO_FN(FSIASPDIF_PORT9),       /* FSIASPDIF Port 9/18 */
@@ -1700,6 +1709,9 @@ static struct pinmux_gpio pinmux_gpios[] = {
        GPIO_FN(FSIAOBT),       GPIO_FN(FSIAOSLD),      GPIO_FN(FSIAOMC),
        GPIO_FN(FSIACK),        GPIO_FN(FSIAILR),       GPIO_FN(FSIAIBT),
 
+       /* FSI-B */
+       GPIO_FN(FSIBCK),
+
        /* FMSI */
        GPIO_FN(FMSISLD_PORT1), /* FMSISLD Port 1/6 */
        GPIO_FN(FMSISLD_PORT6),
@@ -2097,6 +2109,10 @@ static struct pinmux_gpio pinmux_gpios[] = {
        GPIO_FN(SDENC_CPG),
        GPIO_FN(SDENC_DV_CLKI),
 
+       /* HDMI */
+       GPIO_FN(HDMI_HPD),
+       GPIO_FN(HDMI_CEC),
+
        /* SYSC */
        GPIO_FN(RESETP_PULLUP),
        GPIO_FN(RESETP_PLAIN),
diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c
new file mode 100644 (file)
index 0000000..893504d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * r8a7740 power management support
+ *
+ * Copyright (C) 2012  Renesas Solutions Corp.
+ * Copyright (C) 2012  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/console.h>
+#include <mach/pm-rmobile.h>
+
+#ifdef CONFIG_PM
+static int r8a7740_pd_a4s_suspend(void)
+{
+       /*
+        * The A4S domain contains the CPU core and therefore it should
+        * only be turned off if the CPU is in use.
+        */
+       return -EBUSY;
+}
+
+struct rmobile_pm_domain r8a7740_pd_a4s = {
+       .genpd.name     = "A4S",
+       .bit_shift      = 10,
+       .gov            = &pm_domain_always_on_gov,
+       .no_debug       = true,
+       .suspend        = r8a7740_pd_a4s_suspend,
+};
+
+static int r8a7740_pd_a3sp_suspend(void)
+{
+       /*
+        * Serial consoles make use of SCIF hardware located in A3SP,
+        * keep such power domain on if "no_console_suspend" is set.
+        */
+       return console_suspend_enabled ? 0 : -EBUSY;
+}
+
+struct rmobile_pm_domain r8a7740_pd_a3sp = {
+       .genpd.name     = "A3SP",
+       .bit_shift      = 11,
+       .gov            = &pm_domain_always_on_gov,
+       .no_debug       = true,
+       .suspend        = r8a7740_pd_a3sp_suspend,
+};
+
+struct rmobile_pm_domain r8a7740_pd_a4lc = {
+       .genpd.name     = "A4LC",
+       .bit_shift      = 1,
+};
+
+#endif /* CONFIG_PM */
diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c
new file mode 100644 (file)
index 0000000..a856254
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * rmobile power management support
+ *
+ * Copyright (C) 2012  Renesas Solutions Corp.
+ * Copyright (C) 2012  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * based on pm-sh7372.c
+ *  Copyright (C) 2011 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_clock.h>
+#include <asm/io.h>
+#include <mach/pm-rmobile.h>
+
+/* SYSC */
+#define SPDCR          0xe6180008
+#define SWUCR          0xe6180014
+#define PSTR           0xe6180080
+
+#define PSTR_RETRIES   100
+#define PSTR_DELAY_US  10
+
+#ifdef CONFIG_PM
+static int rmobile_pd_power_down(struct generic_pm_domain *genpd)
+{
+       struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd);
+       unsigned int mask = 1 << rmobile_pd->bit_shift;
+
+       if (rmobile_pd->suspend) {
+               int ret = rmobile_pd->suspend();
+
+               if (ret)
+                       return ret;
+       }
+
+       if (__raw_readl(PSTR) & mask) {
+               unsigned int retry_count;
+               __raw_writel(mask, SPDCR);
+
+               for (retry_count = PSTR_RETRIES; retry_count; retry_count--) {
+                       if (!(__raw_readl(SPDCR) & mask))
+                               break;
+                       cpu_relax();
+               }
+       }
+
+       if (!rmobile_pd->no_debug)
+               pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n",
+                        genpd->name, mask, __raw_readl(PSTR));
+
+       return 0;
+}
+
+static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd,
+                                bool do_resume)
+{
+       unsigned int mask = 1 << rmobile_pd->bit_shift;
+       unsigned int retry_count;
+       int ret = 0;
+
+       if (__raw_readl(PSTR) & mask)
+               goto out;
+
+       __raw_writel(mask, SWUCR);
+
+       for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) {
+               if (!(__raw_readl(SWUCR) & mask))
+                       break;
+               if (retry_count > PSTR_RETRIES)
+                       udelay(PSTR_DELAY_US);
+               else
+                       cpu_relax();
+       }
+       if (!retry_count)
+               ret = -EIO;
+
+       if (!rmobile_pd->no_debug)
+               pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n",
+                        rmobile_pd->genpd.name, mask, __raw_readl(PSTR));
+
+out:
+       if (ret == 0 && rmobile_pd->resume && do_resume)
+               rmobile_pd->resume();
+
+       return ret;
+}
+
+static int rmobile_pd_power_up(struct generic_pm_domain *genpd)
+{
+       return __rmobile_pd_power_up(to_rmobile_pd(genpd), true);
+}
+
+static bool rmobile_pd_active_wakeup(struct device *dev)
+{
+       bool (*active_wakeup)(struct device *dev);
+
+       active_wakeup = dev_gpd_data(dev)->ops.active_wakeup;
+       return active_wakeup ? active_wakeup(dev) : true;
+}
+
+static int rmobile_pd_stop_dev(struct device *dev)
+{
+       int (*stop)(struct device *dev);
+
+       stop = dev_gpd_data(dev)->ops.stop;
+       if (stop) {
+               int ret = stop(dev);
+               if (ret)
+                       return ret;
+       }
+       return pm_clk_suspend(dev);
+}
+
+static int rmobile_pd_start_dev(struct device *dev)
+{
+       int (*start)(struct device *dev);
+       int ret;
+
+       ret = pm_clk_resume(dev);
+       if (ret)
+               return ret;
+
+       start = dev_gpd_data(dev)->ops.start;
+       if (start)
+               ret = start(dev);
+
+       return ret;
+}
+
+void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
+{
+       struct generic_pm_domain *genpd = &rmobile_pd->genpd;
+       struct dev_power_governor *gov = rmobile_pd->gov;
+
+       pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
+       genpd->dev_ops.stop             = rmobile_pd_stop_dev;
+       genpd->dev_ops.start            = rmobile_pd_start_dev;
+       genpd->dev_ops.active_wakeup    = rmobile_pd_active_wakeup;
+       genpd->dev_irq_safe             = true;
+       genpd->power_off                = rmobile_pd_power_down;
+       genpd->power_on                 = rmobile_pd_power_up;
+       __rmobile_pd_power_up(rmobile_pd, false);
+}
+
+void rmobile_add_device_to_domain(struct rmobile_pm_domain *rmobile_pd,
+                                struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+
+       pm_genpd_add_device(&rmobile_pd->genpd, dev);
+       if (pm_clk_no_clocks(dev))
+               pm_clk_add(dev, NULL);
+}
+
+void rmobile_pm_add_subdomain(struct rmobile_pm_domain *rmobile_pd,
+                            struct rmobile_pm_domain *rmobile_sd)
+{
+       pm_genpd_add_subdomain(&rmobile_pd->genpd, &rmobile_sd->genpd);
+}
+#endif /* CONFIG_PM */
index a3bdb12acde99771357de0fb95c1e207ece71e3f..79203706922651dad75595869802fa3520c78a8c 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/suspend.h>
 #include <mach/common.h>
 #include <mach/sh7372.h>
+#include <mach/pm-rmobile.h>
 
 /* DBG */
 #define DBGREG1 0xe6100020
 #define PLLC01STPCR 0xe61500c8
 
 /* SYSC */
-#define SPDCR 0xe6180008
-#define SWUCR 0xe6180014
 #define SBAR 0xe6180020
 #define WUPRMSK 0xe6180028
 #define WUPSMSK 0xe618002c
 #define WUPSMSK2 0xe6180048
-#define PSTR 0xe6180080
 #define WUPSFAC 0xe6180098
 #define IRQCR 0xe618022c
 #define IRQCR2 0xe6180238
 /* AP-System Core */
 #define APARMBAREA 0xe6f10020
 
-#define PSTR_RETRIES 100
-#define PSTR_DELAY_US 10
-
 #ifdef CONFIG_PM
 
-static int pd_power_down(struct generic_pm_domain *genpd)
-{
-       struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd);
-       unsigned int mask = 1 << sh7372_pd->bit_shift;
-
-       if (sh7372_pd->suspend) {
-               int ret = sh7372_pd->suspend();
-
-               if (ret)
-                       return ret;
-       }
-
-       if (__raw_readl(PSTR) & mask) {
-               unsigned int retry_count;
-
-               __raw_writel(mask, SPDCR);
-
-               for (retry_count = PSTR_RETRIES; retry_count; retry_count--) {
-                       if (!(__raw_readl(SPDCR) & mask))
-                               break;
-                       cpu_relax();
-               }
-       }
-
-       if (!sh7372_pd->no_debug)
-               pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n",
-                        genpd->name, mask, __raw_readl(PSTR));
-
-       return 0;
-}
-
-static int __pd_power_up(struct sh7372_pm_domain *sh7372_pd, bool do_resume)
-{
-       unsigned int mask = 1 << sh7372_pd->bit_shift;
-       unsigned int retry_count;
-       int ret = 0;
-
-       if (__raw_readl(PSTR) & mask)
-               goto out;
-
-       __raw_writel(mask, SWUCR);
-
-       for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) {
-               if (!(__raw_readl(SWUCR) & mask))
-                       break;
-               if (retry_count > PSTR_RETRIES)
-                       udelay(PSTR_DELAY_US);
-               else
-                       cpu_relax();
-       }
-       if (!retry_count)
-               ret = -EIO;
-
-       if (!sh7372_pd->no_debug)
-               pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n",
-                        sh7372_pd->genpd.name, mask, __raw_readl(PSTR));
-
- out:
-       if (ret == 0 && sh7372_pd->resume && do_resume)
-               sh7372_pd->resume();
-
-       return ret;
-}
-
-static int pd_power_up(struct generic_pm_domain *genpd)
-{
-        return __pd_power_up(to_sh7372_pd(genpd), true);
-}
-
-static int sh7372_a4r_suspend(void)
-{
-       sh7372_intcs_suspend();
-       __raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */
-       return 0;
-}
-
-static bool pd_active_wakeup(struct device *dev)
-{
-       bool (*active_wakeup)(struct device *dev);
-
-       active_wakeup = dev_gpd_data(dev)->ops.active_wakeup;
-       return active_wakeup ? active_wakeup(dev) : true;
-}
-
-static int sh7372_stop_dev(struct device *dev)
-{
-       int (*stop)(struct device *dev);
-
-       stop = dev_gpd_data(dev)->ops.stop;
-       if (stop) {
-               int ret = stop(dev);
-               if (ret)
-                       return ret;
-       }
-       return pm_clk_suspend(dev);
-}
-
-static int sh7372_start_dev(struct device *dev)
-{
-       int (*start)(struct device *dev);
-       int ret;
-
-       ret = pm_clk_resume(dev);
-       if (ret)
-               return ret;
-
-       start = dev_gpd_data(dev)->ops.start;
-       if (start)
-               ret = start(dev);
-
-       return ret;
-}
-
-void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd)
-{
-       struct generic_pm_domain *genpd = &sh7372_pd->genpd;
-       struct dev_power_governor *gov = sh7372_pd->gov;
-
-       pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
-       genpd->dev_ops.stop = sh7372_stop_dev;
-       genpd->dev_ops.start = sh7372_start_dev;
-       genpd->dev_ops.active_wakeup = pd_active_wakeup;
-       genpd->dev_irq_safe = true;
-       genpd->power_off = pd_power_down;
-       genpd->power_on = pd_power_up;
-       __pd_power_up(sh7372_pd, false);
-}
-
-void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
-                                struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-
-       pm_genpd_add_device(&sh7372_pd->genpd, dev);
-       if (pm_clk_no_clocks(dev))
-               pm_clk_add(dev, NULL);
-}
-
-void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
-                            struct sh7372_pm_domain *sh7372_sd)
-{
-       pm_genpd_add_subdomain(&sh7372_pd->genpd, &sh7372_sd->genpd);
-}
-
-struct sh7372_pm_domain sh7372_a4lc = {
+struct rmobile_pm_domain sh7372_pd_a4lc = {
        .genpd.name = "A4LC",
        .bit_shift = 1,
 };
 
-struct sh7372_pm_domain sh7372_a4mp = {
+struct rmobile_pm_domain sh7372_pd_a4mp = {
        .genpd.name = "A4MP",
        .bit_shift = 2,
 };
 
-struct sh7372_pm_domain sh7372_d4 = {
+struct rmobile_pm_domain sh7372_pd_d4 = {
        .genpd.name = "D4",
        .bit_shift = 3,
 };
 
-struct sh7372_pm_domain sh7372_a4r = {
+static int sh7372_a4r_pd_suspend(void)
+{
+       sh7372_intcs_suspend();
+       __raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */
+       return 0;
+}
+
+struct rmobile_pm_domain sh7372_pd_a4r = {
        .genpd.name = "A4R",
        .bit_shift = 5,
-       .suspend = sh7372_a4r_suspend,
+       .suspend = sh7372_a4r_pd_suspend,
        .resume = sh7372_intcs_resume,
 };
 
-struct sh7372_pm_domain sh7372_a3rv = {
+struct rmobile_pm_domain sh7372_pd_a3rv = {
        .genpd.name = "A3RV",
        .bit_shift = 6,
 };
 
-struct sh7372_pm_domain sh7372_a3ri = {
+struct rmobile_pm_domain sh7372_pd_a3ri = {
        .genpd.name = "A3RI",
        .bit_shift = 8,
 };
 
-static int sh7372_a4s_suspend(void)
+static int sh7372_pd_a4s_suspend(void)
 {
        /*
         * The A4S domain contains the CPU core and therefore it should
@@ -261,15 +119,15 @@ static int sh7372_a4s_suspend(void)
        return -EBUSY;
 }
 
-struct sh7372_pm_domain sh7372_a4s = {
+struct rmobile_pm_domain sh7372_pd_a4s = {
        .genpd.name = "A4S",
        .bit_shift = 10,
        .gov = &pm_domain_always_on_gov,
        .no_debug = true,
-       .suspend = sh7372_a4s_suspend,
+       .suspend = sh7372_pd_a4s_suspend,
 };
 
-static int sh7372_a3sp_suspend(void)
+static int sh7372_a3sp_pd_suspend(void)
 {
        /*
         * Serial consoles make use of SCIF hardware located in A3SP,
@@ -278,32 +136,22 @@ static int sh7372_a3sp_suspend(void)
        return console_suspend_enabled ? 0 : -EBUSY;
 }
 
-struct sh7372_pm_domain sh7372_a3sp = {
+struct rmobile_pm_domain sh7372_pd_a3sp = {
        .genpd.name = "A3SP",
        .bit_shift = 11,
        .gov = &pm_domain_always_on_gov,
        .no_debug = true,
-       .suspend = sh7372_a3sp_suspend,
+       .suspend = sh7372_a3sp_pd_suspend,
 };
 
-struct sh7372_pm_domain sh7372_a3sg = {
+struct rmobile_pm_domain sh7372_pd_a3sg = {
        .genpd.name = "A3SG",
        .bit_shift = 13,
 };
 
-#else /* !CONFIG_PM */
-
-static inline void sh7372_a3sp_init(void) {}
-
-#endif /* !CONFIG_PM */
+#endif /* CONFIG_PM */
 
 #if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
-static int sh7372_do_idle_core_standby(unsigned long unused)
-{
-       cpu_do_idle(); /* WFI when SYSTBCR == 0x10 -> Core Standby */
-       return 0;
-}
-
 static void sh7372_set_reset_vector(unsigned long address)
 {
        /* set reset vector, translate 4k */
@@ -311,21 +159,6 @@ static void sh7372_set_reset_vector(unsigned long address)
        __raw_writel(0, APARMBAREA);
 }
 
-static void sh7372_enter_core_standby(void)
-{
-       sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
-
-       /* enter sleep mode with SYSTBCR to 0x10 */
-       __raw_writel(0x10, SYSTBCR);
-       cpu_suspend(0, sh7372_do_idle_core_standby);
-       __raw_writel(0, SYSTBCR);
-
-        /* disable reset vector translation */
-       __raw_writel(0, SBAR);
-}
-#endif
-
-#ifdef CONFIG_SUSPEND
 static void sh7372_enter_sysc(int pllc0_on, unsigned long sleep_mode)
 {
        if (pllc0_on)
@@ -465,22 +298,42 @@ static void sh7372_setup_sysc(unsigned long msk, unsigned long msk2)
 
 static void sh7372_enter_a3sm_common(int pllc0_on)
 {
+       /* use INTCA together with SYSC for wakeup */
+       sh7372_setup_sysc(1 << 0, 0);
        sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
        sh7372_enter_sysc(pllc0_on, 1 << 12);
 }
+#endif /* CONFIG_SUSPEND || CONFIG_CPU_IDLE */
 
-static void sh7372_enter_a4s_common(int pllc0_on)
+#ifdef CONFIG_CPU_IDLE
+static int sh7372_do_idle_core_standby(unsigned long unused)
 {
-       sh7372_intca_suspend();
-       memcpy((void *)SMFRAM, sh7372_resume_core_standby_sysc, 0x100);
-       sh7372_set_reset_vector(SMFRAM);
-       sh7372_enter_sysc(pllc0_on, 1 << 10);
-       sh7372_intca_resume();
+       cpu_do_idle(); /* WFI when SYSTBCR == 0x10 -> Core Standby */
+       return 0;
 }
 
-#endif
+static void sh7372_enter_core_standby(void)
+{
+       sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
 
-#ifdef CONFIG_CPU_IDLE
+       /* enter sleep mode with SYSTBCR to 0x10 */
+       __raw_writel(0x10, SYSTBCR);
+       cpu_suspend(0, sh7372_do_idle_core_standby);
+       __raw_writel(0, SYSTBCR);
+
+        /* disable reset vector translation */
+       __raw_writel(0, SBAR);
+}
+
+static void sh7372_enter_a3sm_pll_on(void)
+{
+       sh7372_enter_a3sm_common(1);
+}
+
+static void sh7372_enter_a3sm_pll_off(void)
+{
+       sh7372_enter_a3sm_common(0);
+}
 
 static void sh7372_cpuidle_setup(struct cpuidle_driver *drv)
 {
@@ -492,7 +345,24 @@ static void sh7372_cpuidle_setup(struct cpuidle_driver *drv)
        state->target_residency = 20 + 10;
        state->flags = CPUIDLE_FLAG_TIME_VALID;
        shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_core_standby;
+       drv->state_count++;
+
+       state = &drv->states[drv->state_count];
+       snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
+       strncpy(state->desc, "A3SM PLL ON", CPUIDLE_DESC_LEN);
+       state->exit_latency = 20;
+       state->target_residency = 30 + 20;
+       state->flags = CPUIDLE_FLAG_TIME_VALID;
+       shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_a3sm_pll_on;
+       drv->state_count++;
 
+       state = &drv->states[drv->state_count];
+       snprintf(state->name, CPUIDLE_NAME_LEN, "C4");
+       strncpy(state->desc, "A3SM PLL OFF", CPUIDLE_DESC_LEN);
+       state->exit_latency = 120;
+       state->target_residency = 30 + 120;
+       state->flags = CPUIDLE_FLAG_TIME_VALID;
+       shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_a3sm_pll_off;
        drv->state_count++;
 }
 
@@ -505,6 +375,14 @@ static void sh7372_cpuidle_init(void) {}
 #endif
 
 #ifdef CONFIG_SUSPEND
+static void sh7372_enter_a4s_common(int pllc0_on)
+{
+       sh7372_intca_suspend();
+       memcpy((void *)SMFRAM, sh7372_resume_core_standby_sysc, 0x100);
+       sh7372_set_reset_vector(SMFRAM);
+       sh7372_enter_sysc(pllc0_on, 1 << 10);
+       sh7372_intca_resume();
+}
 
 static int sh7372_enter_suspend(suspend_state_t suspend_state)
 {
@@ -512,24 +390,21 @@ static int sh7372_enter_suspend(suspend_state_t suspend_state)
 
        /* check active clocks to determine potential wakeup sources */
        if (sh7372_sysc_valid(&msk, &msk2)) {
-               /* convert INTC mask and sense to SYSC mask and sense */
-               sh7372_setup_sysc(msk, msk2);
-
                if (!console_suspend_enabled &&
-                   sh7372_a4s.genpd.status == GPD_STATE_POWER_OFF) {
+                   sh7372_pd_a4s.genpd.status == GPD_STATE_POWER_OFF) {
+                       /* convert INTC mask/sense to SYSC mask/sense */
+                       sh7372_setup_sysc(msk, msk2);
+
                        /* enter A4S sleep with PLLC0 off */
                        pr_debug("entering A4S\n");
                        sh7372_enter_a4s_common(0);
-               } else {
-                       /* enter A3SM sleep with PLLC0 off */
-                       pr_debug("entering A3SM\n");
-                       sh7372_enter_a3sm_common(0);
+                       return 0;
                }
-       } else {
-               /* default to Core Standby that supports all wakeup sources */
-               pr_debug("entering Core Standby\n");
-               sh7372_enter_core_standby();
        }
+
+       /* default to enter A3SM sleep with PLLC0 off */
+       pr_debug("entering A3SM\n");
+       sh7372_enter_a3sm_common(0);
        return 0;
 }
 
@@ -550,7 +425,7 @@ static int sh7372_pm_notifier_fn(struct notifier_block *notifier,
                 * executed during system suspend and resume, respectively, so
                 * that those functions don't crash while accessing the INTCS.
                 */
-               pm_genpd_poweron(&sh7372_a4r.genpd);
+               pm_genpd_poweron(&sh7372_pd_a4r.genpd);
                break;
        case PM_POST_SUSPEND:
                pm_genpd_poweroff_unused();
index ec4eb49c16938a28b438282353e5194bc2592688..78948a9dba0ec47547f5fca10b7aa71452600d7b 100644 (file)
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/of_platform.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
+#include <linux/dma-mapping.h>
+#include <mach/dma-register.h>
 #include <mach/r8a7740.h>
+#include <mach/pm-rmobile.h>
 #include <mach/common.h>
 #include <mach/irqs.h>
 #include <asm/mach-types.h>
@@ -276,6 +281,272 @@ static struct platform_device *r8a7740_early_devices[] __initdata = {
        &cmt10_device,
 };
 
+/* DMA */
+static const struct sh_dmae_slave_config r8a7740_dmae_slaves[] = {
+       {
+               .slave_id       = SHDMA_SLAVE_SDHI0_TX,
+               .addr           = 0xe6850030,
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc1,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI0_RX,
+               .addr           = 0xe6850030,
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc2,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI1_TX,
+               .addr           = 0xe6860030,
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc9,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI1_RX,
+               .addr           = 0xe6860030,
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xca,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI2_TX,
+               .addr           = 0xe6870030,
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xcd,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI2_RX,
+               .addr           = 0xe6870030,
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xce,
+       }, {
+               .slave_id       = SHDMA_SLAVE_FSIA_TX,
+               .addr           = 0xfe1f0024,
+               .chcr           = CHCR_TX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xb1,
+       }, {
+               .slave_id       = SHDMA_SLAVE_FSIA_RX,
+               .addr           = 0xfe1f0020,
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xb2,
+       }, {
+               .slave_id       = SHDMA_SLAVE_FSIB_TX,
+               .addr           = 0xfe1f0064,
+               .chcr           = CHCR_TX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xb5,
+       },
+};
+
+#define DMA_CHANNEL(a, b, c)                   \
+{                                              \
+       .offset         = a,                    \
+       .dmars          = b,                    \
+       .dmars_bit      = c,                    \
+       .chclr_offset   = (0x220 - 0x20) + a    \
+}
+
+static const struct sh_dmae_channel r8a7740_dmae_channels[] = {
+       DMA_CHANNEL(0x00, 0, 0),
+       DMA_CHANNEL(0x10, 0, 8),
+       DMA_CHANNEL(0x20, 4, 0),
+       DMA_CHANNEL(0x30, 4, 8),
+       DMA_CHANNEL(0x50, 8, 0),
+       DMA_CHANNEL(0x60, 8, 8),
+};
+
+static struct sh_dmae_pdata dma_platform_data = {
+       .slave          = r8a7740_dmae_slaves,
+       .slave_num      = ARRAY_SIZE(r8a7740_dmae_slaves),
+       .channel        = r8a7740_dmae_channels,
+       .channel_num    = ARRAY_SIZE(r8a7740_dmae_channels),
+       .ts_low_shift   = TS_LOW_SHIFT,
+       .ts_low_mask    = TS_LOW_BIT << TS_LOW_SHIFT,
+       .ts_high_shift  = TS_HI_SHIFT,
+       .ts_high_mask   = TS_HI_BIT << TS_HI_SHIFT,
+       .ts_shift       = dma_ts_shift,
+       .ts_shift_num   = ARRAY_SIZE(dma_ts_shift),
+       .dmaor_init     = DMAOR_DME,
+       .chclr_present  = 1,
+};
+
+/* Resource order important! */
+static struct resource r8a7740_dmae0_resources[] = {
+       {
+               /* Channel registers and DMAOR */
+               .start  = 0xfe008020,
+               .end    = 0xfe00828f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* DMARSx */
+               .start  = 0xfe009000,
+               .end    = 0xfe00900b,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "error_irq",
+               .start  = evt2irq(0x20c0),
+               .end    = evt2irq(0x20c0),
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               /* IRQ for channels 0-5 */
+               .start  = evt2irq(0x2000),
+               .end    = evt2irq(0x20a0),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+/* Resource order important! */
+static struct resource r8a7740_dmae1_resources[] = {
+       {
+               /* Channel registers and DMAOR */
+               .start  = 0xfe018020,
+               .end    = 0xfe01828f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* DMARSx */
+               .start  = 0xfe019000,
+               .end    = 0xfe01900b,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "error_irq",
+               .start  = evt2irq(0x21c0),
+               .end    = evt2irq(0x21c0),
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               /* IRQ for channels 0-5 */
+               .start  = evt2irq(0x2100),
+               .end    = evt2irq(0x21a0),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+/* Resource order important! */
+static struct resource r8a7740_dmae2_resources[] = {
+       {
+               /* Channel registers and DMAOR */
+               .start  = 0xfe028020,
+               .end    = 0xfe02828f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* DMARSx */
+               .start  = 0xfe029000,
+               .end    = 0xfe02900b,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "error_irq",
+               .start  = evt2irq(0x22c0),
+               .end    = evt2irq(0x22c0),
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               /* IRQ for channels 0-5 */
+               .start  = evt2irq(0x2200),
+               .end    = evt2irq(0x22a0),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dma0_device = {
+       .name           = "sh-dma-engine",
+       .id             = 0,
+       .resource       = r8a7740_dmae0_resources,
+       .num_resources  = ARRAY_SIZE(r8a7740_dmae0_resources),
+       .dev            = {
+               .platform_data  = &dma_platform_data,
+       },
+};
+
+static struct platform_device dma1_device = {
+       .name           = "sh-dma-engine",
+       .id             = 1,
+       .resource       = r8a7740_dmae1_resources,
+       .num_resources  = ARRAY_SIZE(r8a7740_dmae1_resources),
+       .dev            = {
+               .platform_data  = &dma_platform_data,
+       },
+};
+
+static struct platform_device dma2_device = {
+       .name           = "sh-dma-engine",
+       .id             = 2,
+       .resource       = r8a7740_dmae2_resources,
+       .num_resources  = ARRAY_SIZE(r8a7740_dmae2_resources),
+       .dev            = {
+               .platform_data  = &dma_platform_data,
+       },
+};
+
+/* USB-DMAC */
+static const struct sh_dmae_channel r8a7740_usb_dma_channels[] = {
+       {
+               .offset = 0,
+       }, {
+               .offset = 0x20,
+       },
+};
+
+static const struct sh_dmae_slave_config r8a7740_usb_dma_slaves[] = {
+       {
+               .slave_id       = SHDMA_SLAVE_USBHS_TX,
+               .chcr           = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE),
+       }, {
+               .slave_id       = SHDMA_SLAVE_USBHS_RX,
+               .chcr           = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE),
+       },
+};
+
+static struct sh_dmae_pdata usb_dma_platform_data = {
+       .slave          = r8a7740_usb_dma_slaves,
+       .slave_num      = ARRAY_SIZE(r8a7740_usb_dma_slaves),
+       .channel        = r8a7740_usb_dma_channels,
+       .channel_num    = ARRAY_SIZE(r8a7740_usb_dma_channels),
+       .ts_low_shift   = USBTS_LOW_SHIFT,
+       .ts_low_mask    = USBTS_LOW_BIT << USBTS_LOW_SHIFT,
+       .ts_high_shift  = USBTS_HI_SHIFT,
+       .ts_high_mask   = USBTS_HI_BIT << USBTS_HI_SHIFT,
+       .ts_shift       = dma_usbts_shift,
+       .ts_shift_num   = ARRAY_SIZE(dma_usbts_shift),
+       .dmaor_init     = DMAOR_DME,
+       .chcr_offset    = 0x14,
+       .chcr_ie_bit    = 1 << 5,
+       .dmaor_is_32bit = 1,
+       .needs_tend_set = 1,
+       .no_dmars       = 1,
+       .slave_only     = 1,
+};
+
+static struct resource r8a7740_usb_dma_resources[] = {
+       {
+               /* Channel registers and DMAOR */
+               .start  = 0xe68a0020,
+               .end    = 0xe68a0064 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* VCR/SWR/DMICR */
+               .start  = 0xe68a0000,
+               .end    = 0xe68a0014 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* IRQ for channels */
+               .start  = evt2irq(0x0a00),
+               .end    = evt2irq(0x0a00),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device usb_dma_device = {
+       .name           = "sh-dma-engine",
+       .id             = 3,
+       .resource       = r8a7740_usb_dma_resources,
+       .num_resources  = ARRAY_SIZE(r8a7740_usb_dma_resources),
+       .dev            = {
+               .platform_data  = &usb_dma_platform_data,
+       },
+};
+
 /* I2C */
 static struct resource i2c0_resources[] = {
        [0] = {
@@ -322,8 +593,30 @@ static struct platform_device i2c1_device = {
 static struct platform_device *r8a7740_late_devices[] __initdata = {
        &i2c0_device,
        &i2c1_device,
+       &dma0_device,
+       &dma1_device,
+       &dma2_device,
+       &usb_dma_device,
 };
 
+/*
+ * r8a7740 chip has lasting errata on MERAM buffer.
+ * this is work-around for it.
+ * see
+ *     "Media RAM (MERAM)" on r8a7740 documentation
+ */
+#define MEBUFCNTR      0xFE950098
+void r8a7740_meram_workaround(void)
+{
+       void __iomem *reg;
+
+       reg = ioremap_nocache(MEBUFCNTR, 4);
+       if (reg) {
+               iowrite32(0x01600164, reg);
+               iounmap(reg);
+       }
+}
+
 #define ICCR   0x0004
 #define ICSTART        0x0070
 
@@ -380,10 +673,31 @@ void __init r8a7740_add_standard_devices(void)
        r8a7740_i2c_workaround(&i2c0_device);
        r8a7740_i2c_workaround(&i2c1_device);
 
+       /* PM domain */
+       rmobile_init_pm_domain(&r8a7740_pd_a4s);
+       rmobile_init_pm_domain(&r8a7740_pd_a3sp);
+       rmobile_init_pm_domain(&r8a7740_pd_a4lc);
+
+       rmobile_pm_add_subdomain(&r8a7740_pd_a4s, &r8a7740_pd_a3sp);
+
+       /* add devices */
        platform_add_devices(r8a7740_early_devices,
                            ARRAY_SIZE(r8a7740_early_devices));
        platform_add_devices(r8a7740_late_devices,
                             ARRAY_SIZE(r8a7740_late_devices));
+
+       /* add devices to PM domain  */
+
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif0_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif1_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif2_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif3_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif4_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif5_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif6_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif7_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scifb_device);
+       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &i2c1_device);
 }
 
 static void __init r8a7740_earlytimer_init(void)
@@ -403,3 +717,49 @@ void __init r8a7740_add_early_devices(void)
        /* override timer setup with soc-specific code */
        shmobile_timer.init = r8a7740_earlytimer_init;
 }
+
+#ifdef CONFIG_USE_OF
+
+void __init r8a7740_add_early_devices_dt(void)
+{
+       shmobile_setup_delay(800, 1, 3); /* Cortex-A9 @ 800MHz */
+
+       early_platform_add_devices(r8a7740_early_devices,
+                                  ARRAY_SIZE(r8a7740_early_devices));
+
+       /* setup early console here as well */
+       shmobile_setup_console();
+}
+
+static const struct of_dev_auxdata r8a7740_auxdata_lookup[] __initconst = {
+       { }
+};
+
+void __init r8a7740_add_standard_devices_dt(void)
+{
+       /* clocks are setup late during boot in the case of DT */
+       r8a7740_clock_init(0);
+
+       platform_add_devices(r8a7740_early_devices,
+                           ARRAY_SIZE(r8a7740_early_devices));
+
+       of_platform_populate(NULL, of_default_bus_match_table,
+                            r8a7740_auxdata_lookup, NULL);
+}
+
+static const char *r8a7740_boards_compat_dt[] __initdata = {
+       "renesas,r8a7740",
+       NULL,
+};
+
+DT_MACHINE_START(SH7372_DT, "Generic R8A7740 (Flattened Device Tree)")
+       .map_io         = r8a7740_map_io,
+       .init_early     = r8a7740_add_early_devices_dt,
+       .init_irq       = r8a7740_init_irq,
+       .handle_irq     = shmobile_handle_irq_intc,
+       .init_machine   = r8a7740_add_standard_devices_dt,
+       .timer          = &shmobile_timer,
+       .dt_compat      = r8a7740_boards_compat_dt,
+MACHINE_END
+
+#endif /* CONFIG_USE_OF */
index fafce9ce8218c440028b6083a2254c4452b1a223..838a87be1d5c31cc46a932d58f27a73f00066ca9 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/sh_timer.h>
 #include <linux/pm_domain.h>
 #include <linux/dma-mapping.h>
+#include <mach/dma-register.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/sh7372.h>
@@ -335,151 +336,126 @@ static struct platform_device iic1_device = {
 };
 
 /* DMA */
-/* Transmit sizes and respective CHCR register values */
-enum {
-       XMIT_SZ_8BIT            = 0,
-       XMIT_SZ_16BIT           = 1,
-       XMIT_SZ_32BIT           = 2,
-       XMIT_SZ_64BIT           = 7,
-       XMIT_SZ_128BIT          = 3,
-       XMIT_SZ_256BIT          = 4,
-       XMIT_SZ_512BIT          = 5,
-};
-
-/* log2(size / 8) - used to calculate number of transfers */
-#define TS_SHIFT {                     \
-       [XMIT_SZ_8BIT]          = 0,    \
-       [XMIT_SZ_16BIT]         = 1,    \
-       [XMIT_SZ_32BIT]         = 2,    \
-       [XMIT_SZ_64BIT]         = 3,    \
-       [XMIT_SZ_128BIT]        = 4,    \
-       [XMIT_SZ_256BIT]        = 5,    \
-       [XMIT_SZ_512BIT]        = 6,    \
-}
-
-#define TS_INDEX2VAL(i) ((((i) & 3) << 3) | \
-                        (((i) & 0xc) << (20 - 2)))
-
 static const struct sh_dmae_slave_config sh7372_dmae_slaves[] = {
        {
                .slave_id       = SHDMA_SLAVE_SCIF0_TX,
                .addr           = 0xe6c40020,
-               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
                .mid_rid        = 0x21,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF0_RX,
                .addr           = 0xe6c40024,
-               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
                .mid_rid        = 0x22,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF1_TX,
                .addr           = 0xe6c50020,
-               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
                .mid_rid        = 0x25,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF1_RX,
                .addr           = 0xe6c50024,
-               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
                .mid_rid        = 0x26,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF2_TX,
                .addr           = 0xe6c60020,
-               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
                .mid_rid        = 0x29,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF2_RX,
                .addr           = 0xe6c60024,
-               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
                .mid_rid        = 0x2a,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF3_TX,
                .addr           = 0xe6c70020,
-               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
                .mid_rid        = 0x2d,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF3_RX,
                .addr           = 0xe6c70024,
-               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
                .mid_rid        = 0x2e,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF4_TX,
                .addr           = 0xe6c80020,
-               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
                .mid_rid        = 0x39,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF4_RX,
                .addr           = 0xe6c80024,
-               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
                .mid_rid        = 0x3a,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF5_TX,
                .addr           = 0xe6cb0020,
-               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
                .mid_rid        = 0x35,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF5_RX,
                .addr           = 0xe6cb0024,
-               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
                .mid_rid        = 0x36,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF6_TX,
                .addr           = 0xe6c30040,
-               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
                .mid_rid        = 0x3d,
        }, {
                .slave_id       = SHDMA_SLAVE_SCIF6_RX,
                .addr           = 0xe6c30060,
-               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
                .mid_rid        = 0x3e,
        }, {
                .slave_id       = SHDMA_SLAVE_SDHI0_TX,
                .addr           = 0xe6850030,
-               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
                .mid_rid        = 0xc1,
        }, {
                .slave_id       = SHDMA_SLAVE_SDHI0_RX,
                .addr           = 0xe6850030,
-               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
                .mid_rid        = 0xc2,
        }, {
                .slave_id       = SHDMA_SLAVE_SDHI1_TX,
                .addr           = 0xe6860030,
-               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
                .mid_rid        = 0xc9,
        }, {
                .slave_id       = SHDMA_SLAVE_SDHI1_RX,
                .addr           = 0xe6860030,
-               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
                .mid_rid        = 0xca,
        }, {
                .slave_id       = SHDMA_SLAVE_SDHI2_TX,
                .addr           = 0xe6870030,
-               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
                .mid_rid        = 0xcd,
        }, {
                .slave_id       = SHDMA_SLAVE_SDHI2_RX,
                .addr           = 0xe6870030,
-               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
                .mid_rid        = 0xce,
        }, {
                .slave_id       = SHDMA_SLAVE_FSIA_TX,
                .addr           = 0xfe1f0024,
-               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+               .chcr           = CHCR_TX(XMIT_SZ_32BIT),
                .mid_rid        = 0xb1,
        }, {
                .slave_id       = SHDMA_SLAVE_FSIA_RX,
                .addr           = 0xfe1f0020,
-               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
                .mid_rid        = 0xb2,
        }, {
                .slave_id       = SHDMA_SLAVE_MMCIF_TX,
                .addr           = 0xe6bd0034,
-               .chcr           = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+               .chcr           = CHCR_TX(XMIT_SZ_32BIT),
                .mid_rid        = 0xd1,
        }, {
                .slave_id       = SHDMA_SLAVE_MMCIF_RX,
                .addr           = 0xe6bd0034,
-               .chcr           = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
                .mid_rid        = 0xd2,
        },
 };
@@ -520,19 +496,17 @@ static const struct sh_dmae_channel sh7372_dmae_channels[] = {
        }
 };
 
-static const unsigned int ts_shift[] = TS_SHIFT;
-
 static struct sh_dmae_pdata dma_platform_data = {
        .slave          = sh7372_dmae_slaves,
        .slave_num      = ARRAY_SIZE(sh7372_dmae_slaves),
        .channel        = sh7372_dmae_channels,
        .channel_num    = ARRAY_SIZE(sh7372_dmae_channels),
-       .ts_low_shift   = 3,
-       .ts_low_mask    = 0x18,
-       .ts_high_shift  = (20 - 2),     /* 2 bits for shifted low TS */
-       .ts_high_mask   = 0x00300000,
-       .ts_shift       = ts_shift,
-       .ts_shift_num   = ARRAY_SIZE(ts_shift),
+       .ts_low_shift   = TS_LOW_SHIFT,
+       .ts_low_mask    = TS_LOW_BIT << TS_LOW_SHIFT,
+       .ts_high_shift  = TS_HI_SHIFT,
+       .ts_high_mask   = TS_HI_BIT << TS_HI_SHIFT,
+       .ts_shift       = dma_ts_shift,
+       .ts_shift_num   = ARRAY_SIZE(dma_ts_shift),
        .dmaor_init     = DMAOR_DME,
        .chclr_present  = 1,
 };
@@ -654,17 +628,6 @@ static struct platform_device dma2_device = {
 /*
  * USB-DMAC
  */
-
-unsigned int usbts_shift[] = {3, 4, 5};
-
-enum {
-       XMIT_SZ_8BYTE           = 0,
-       XMIT_SZ_16BYTE          = 1,
-       XMIT_SZ_32BYTE          = 2,
-};
-
-#define USBTS_INDEX2VAL(i) (((i) & 3) << 6)
-
 static const struct sh_dmae_channel sh7372_usb_dmae_channels[] = {
        {
                .offset = 0,
@@ -677,10 +640,10 @@ static const struct sh_dmae_channel sh7372_usb_dmae_channels[] = {
 static const struct sh_dmae_slave_config sh7372_usb_dmae0_slaves[] = {
        {
                .slave_id       = SHDMA_SLAVE_USB0_TX,
-               .chcr           = USBTS_INDEX2VAL(XMIT_SZ_8BYTE),
+               .chcr           = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE),
        }, {
                .slave_id       = SHDMA_SLAVE_USB0_RX,
-               .chcr           = USBTS_INDEX2VAL(XMIT_SZ_8BYTE),
+               .chcr           = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE),
        },
 };
 
@@ -689,12 +652,12 @@ static struct sh_dmae_pdata usb_dma0_platform_data = {
        .slave_num      = ARRAY_SIZE(sh7372_usb_dmae0_slaves),
        .channel        = sh7372_usb_dmae_channels,
        .channel_num    = ARRAY_SIZE(sh7372_usb_dmae_channels),
-       .ts_low_shift   = 6,
-       .ts_low_mask    = 0xc0,
-       .ts_high_shift  = 0,
-       .ts_high_mask   = 0,
-       .ts_shift       = usbts_shift,
-       .ts_shift_num   = ARRAY_SIZE(usbts_shift),
+       .ts_low_shift   = USBTS_LOW_SHIFT,
+       .ts_low_mask    = USBTS_LOW_BIT << USBTS_LOW_SHIFT,
+       .ts_high_shift  = USBTS_HI_SHIFT,
+       .ts_high_mask   = USBTS_HI_BIT << USBTS_HI_SHIFT,
+       .ts_shift       = dma_usbts_shift,
+       .ts_shift_num   = ARRAY_SIZE(dma_usbts_shift),
        .dmaor_init     = DMAOR_DME,
        .chcr_offset    = 0x14,
        .chcr_ie_bit    = 1 << 5,
@@ -739,10 +702,10 @@ static struct platform_device usb_dma0_device = {
 static const struct sh_dmae_slave_config sh7372_usb_dmae1_slaves[] = {
        {
                .slave_id       = SHDMA_SLAVE_USB1_TX,
-               .chcr           = USBTS_INDEX2VAL(XMIT_SZ_8BYTE),
+               .chcr           = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE),
        }, {
                .slave_id       = SHDMA_SLAVE_USB1_RX,
-               .chcr           = USBTS_INDEX2VAL(XMIT_SZ_8BYTE),
+               .chcr           = USBTS_INDEX2VAL(USBTS_XMIT_SZ_8BYTE),
        },
 };
 
@@ -751,12 +714,12 @@ static struct sh_dmae_pdata usb_dma1_platform_data = {
        .slave_num      = ARRAY_SIZE(sh7372_usb_dmae1_slaves),
        .channel        = sh7372_usb_dmae_channels,
        .channel_num    = ARRAY_SIZE(sh7372_usb_dmae_channels),
-       .ts_low_shift   = 6,
-       .ts_low_mask    = 0xc0,
-       .ts_high_shift  = 0,
-       .ts_high_mask   = 0,
-       .ts_shift       = usbts_shift,
-       .ts_shift_num   = ARRAY_SIZE(usbts_shift),
+       .ts_low_shift   = USBTS_LOW_SHIFT,
+       .ts_low_mask    = USBTS_LOW_BIT << USBTS_LOW_SHIFT,
+       .ts_high_shift  = USBTS_HI_SHIFT,
+       .ts_high_mask   = USBTS_HI_BIT << USBTS_HI_SHIFT,
+       .ts_shift       = dma_usbts_shift,
+       .ts_shift_num   = ARRAY_SIZE(dma_usbts_shift),
        .dmaor_init     = DMAOR_DME,
        .chcr_offset    = 0x14,
        .chcr_ie_bit    = 1 << 5,
@@ -1038,21 +1001,21 @@ static struct platform_device *sh7372_late_devices[] __initdata = {
 
 void __init sh7372_add_standard_devices(void)
 {
-       sh7372_init_pm_domain(&sh7372_a4lc);
-       sh7372_init_pm_domain(&sh7372_a4mp);
-       sh7372_init_pm_domain(&sh7372_d4);
-       sh7372_init_pm_domain(&sh7372_a4r);
-       sh7372_init_pm_domain(&sh7372_a3rv);
-       sh7372_init_pm_domain(&sh7372_a3ri);
-       sh7372_init_pm_domain(&sh7372_a4s);
-       sh7372_init_pm_domain(&sh7372_a3sp);
-       sh7372_init_pm_domain(&sh7372_a3sg);
-
-       sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv);
-       sh7372_pm_add_subdomain(&sh7372_a4r, &sh7372_a4lc);
-
-       sh7372_pm_add_subdomain(&sh7372_a4s, &sh7372_a3sg);
-       sh7372_pm_add_subdomain(&sh7372_a4s, &sh7372_a3sp);
+       rmobile_init_pm_domain(&sh7372_pd_a4lc);
+       rmobile_init_pm_domain(&sh7372_pd_a4mp);
+       rmobile_init_pm_domain(&sh7372_pd_d4);
+       rmobile_init_pm_domain(&sh7372_pd_a4r);
+       rmobile_init_pm_domain(&sh7372_pd_a3rv);
+       rmobile_init_pm_domain(&sh7372_pd_a3ri);
+       rmobile_init_pm_domain(&sh7372_pd_a4s);
+       rmobile_init_pm_domain(&sh7372_pd_a3sp);
+       rmobile_init_pm_domain(&sh7372_pd_a3sg);
+
+       rmobile_pm_add_subdomain(&sh7372_pd_a4lc, &sh7372_pd_a3rv);
+       rmobile_pm_add_subdomain(&sh7372_pd_a4r, &sh7372_pd_a4lc);
+
+       rmobile_pm_add_subdomain(&sh7372_pd_a4s, &sh7372_pd_a3sg);
+       rmobile_pm_add_subdomain(&sh7372_pd_a4s, &sh7372_pd_a3sp);
 
        platform_add_devices(sh7372_early_devices,
                            ARRAY_SIZE(sh7372_early_devices));
@@ -1060,30 +1023,30 @@ void __init sh7372_add_standard_devices(void)
        platform_add_devices(sh7372_late_devices,
                            ARRAY_SIZE(sh7372_late_devices));
 
-       sh7372_add_device_to_domain(&sh7372_a3rv, &vpu_device);
-       sh7372_add_device_to_domain(&sh7372_a4mp, &spu0_device);
-       sh7372_add_device_to_domain(&sh7372_a4mp, &spu1_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &scif0_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &scif1_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &scif2_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &scif3_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &scif4_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &scif5_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &scif6_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &iic1_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &dma0_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &dma1_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &dma2_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma0_device);
-       sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma1_device);
-       sh7372_add_device_to_domain(&sh7372_a4r, &iic0_device);
-       sh7372_add_device_to_domain(&sh7372_a4r, &veu0_device);
-       sh7372_add_device_to_domain(&sh7372_a4r, &veu1_device);
-       sh7372_add_device_to_domain(&sh7372_a4r, &veu2_device);
-       sh7372_add_device_to_domain(&sh7372_a4r, &veu3_device);
-       sh7372_add_device_to_domain(&sh7372_a4r, &jpu_device);
-       sh7372_add_device_to_domain(&sh7372_a4r, &tmu00_device);
-       sh7372_add_device_to_domain(&sh7372_a4r, &tmu01_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3rv, &vpu_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4mp, &spu0_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4mp, &spu1_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif0_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif1_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif2_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif3_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif4_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif5_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif6_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &iic1_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &dma0_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &dma1_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &dma2_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usb_dma0_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usb_dma1_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4r, &iic0_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu0_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu1_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu2_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu3_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4r, &jpu_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4r, &tmu00_device);
+       rmobile_add_device_to_domain(&sh7372_pd_a4r, &tmu01_device);
 }
 
 static void __init sh7372_earlytimer_init(void)
index d576a6abbade8338a33eb8e39d290e29d57e302d..855b1506caf88b209187ed88d8808968e5f6bf40 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/of_platform.h>
 #include <linux/uio_driver.h>
 #include <linux/delay.h>
 #include <linux/input.h>
@@ -500,3 +501,49 @@ void __init sh7377_add_early_devices(void)
        /* override timer setup with soc-specific code */
        shmobile_timer.init = sh7377_earlytimer_init;
 }
+
+#ifdef CONFIG_USE_OF
+
+void __init sh7377_add_early_devices_dt(void)
+{
+       shmobile_setup_delay(600, 1, 3); /* Cortex-A8 @ 600MHz */
+
+       early_platform_add_devices(sh7377_early_devices,
+                                  ARRAY_SIZE(sh7377_early_devices));
+
+       /* setup early console here as well */
+       shmobile_setup_console();
+}
+
+static const struct of_dev_auxdata sh7377_auxdata_lookup[] __initconst = {
+       { }
+};
+
+void __init sh7377_add_standard_devices_dt(void)
+{
+       /* clocks are setup late during boot in the case of DT */
+       sh7377_clock_init();
+
+       platform_add_devices(sh7377_early_devices,
+                           ARRAY_SIZE(sh7377_early_devices));
+
+       of_platform_populate(NULL, of_default_bus_match_table,
+                            sh7377_auxdata_lookup, NULL);
+}
+
+static const char *sh7377_boards_compat_dt[] __initdata = {
+       "renesas,sh7377",
+       NULL,
+};
+
+DT_MACHINE_START(SH7377_DT, "Generic SH7377 (Flattened Device Tree)")
+       .map_io         = sh7377_map_io,
+       .init_early     = sh7377_add_early_devices_dt,
+       .init_irq       = sh7377_init_irq,
+       .handle_irq     = shmobile_handle_irq_intc,
+       .init_machine   = sh7377_add_standard_devices_dt,
+       .timer          = &shmobile_timer,
+       .dt_compat      = sh7377_boards_compat_dt,
+MACHINE_END
+
+#endif /* CONFIG_USE_OF */
index 04a0dfe754934c32c17d1d7a565201504bc520c1..d230af656fc9c57418906e7ce3af785b7117ffc1 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
+#include <mach/dma-register.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/sh73a0.h>
@@ -415,32 +416,6 @@ static struct platform_device i2c4_device = {
        .num_resources  = ARRAY_SIZE(i2c4_resources),
 };
 
-/* Transmit sizes and respective CHCR register values */
-enum {
-       XMIT_SZ_8BIT            = 0,
-       XMIT_SZ_16BIT           = 1,
-       XMIT_SZ_32BIT           = 2,
-       XMIT_SZ_64BIT           = 7,
-       XMIT_SZ_128BIT          = 3,
-       XMIT_SZ_256BIT          = 4,
-       XMIT_SZ_512BIT          = 5,
-};
-
-/* log2(size / 8) - used to calculate number of transfers */
-#define TS_SHIFT {                     \
-       [XMIT_SZ_8BIT]          = 0,    \
-       [XMIT_SZ_16BIT]         = 1,    \
-       [XMIT_SZ_32BIT]         = 2,    \
-       [XMIT_SZ_64BIT]         = 3,    \
-       [XMIT_SZ_128BIT]        = 4,    \
-       [XMIT_SZ_256BIT]        = 5,    \
-       [XMIT_SZ_512BIT]        = 6,    \
-}
-
-#define TS_INDEX2VAL(i) ((((i) & 3) << 3) | (((i) & 0xc) << (20 - 2)))
-#define CHCR_TX(xmit_sz) (DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL((xmit_sz)))
-#define CHCR_RX(xmit_sz) (DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL((xmit_sz)))
-
 static const struct sh_dmae_slave_config sh73a0_dmae_slaves[] = {
        {
                .slave_id       = SHDMA_SLAVE_SCIF0_TX,
@@ -604,19 +579,17 @@ static const struct sh_dmae_channel sh73a0_dmae_channels[] = {
        DMAE_CHANNEL(0x8980),
 };
 
-static const unsigned int ts_shift[] = TS_SHIFT;
-
 static struct sh_dmae_pdata sh73a0_dmae_platform_data = {
        .slave          = sh73a0_dmae_slaves,
        .slave_num      = ARRAY_SIZE(sh73a0_dmae_slaves),
        .channel        = sh73a0_dmae_channels,
        .channel_num    = ARRAY_SIZE(sh73a0_dmae_channels),
-       .ts_low_shift   = 3,
-       .ts_low_mask    = 0x18,
-       .ts_high_shift  = (20 - 2),     /* 2 bits for shifted low TS */
-       .ts_high_mask   = 0x00300000,
-       .ts_shift       = ts_shift,
-       .ts_shift_num   = ARRAY_SIZE(ts_shift),
+       .ts_low_shift   = TS_LOW_SHIFT,
+       .ts_low_mask    = TS_LOW_BIT << TS_LOW_SHIFT,
+       .ts_high_shift  = TS_HI_SHIFT,
+       .ts_high_mask   = TS_HI_BIT << TS_HI_SHIFT,
+       .ts_shift       = dma_ts_shift,
+       .ts_shift_num   = ARRAY_SIZE(dma_ts_shift),
        .dmaor_init     = DMAOR_DME,
 };
 
@@ -651,6 +624,116 @@ static struct platform_device dma0_device = {
        },
 };
 
+/* MPDMAC */
+static const struct sh_dmae_slave_config sh73a0_mpdma_slaves[] = {
+       {
+               .slave_id       = SHDMA_SLAVE_FSI2A_RX,
+               .addr           = 0xec230020,
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xd6, /* CHECK ME */
+       }, {
+               .slave_id       = SHDMA_SLAVE_FSI2A_TX,
+               .addr           = 0xec230024,
+               .chcr           = CHCR_TX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xd5, /* CHECK ME */
+       }, {
+               .slave_id       = SHDMA_SLAVE_FSI2C_RX,
+               .addr           = 0xec230060,
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xda, /* CHECK ME */
+       }, {
+               .slave_id       = SHDMA_SLAVE_FSI2C_TX,
+               .addr           = 0xec230064,
+               .chcr           = CHCR_TX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xd9, /* CHECK ME */
+       }, {
+               .slave_id       = SHDMA_SLAVE_FSI2B_RX,
+               .addr           = 0xec240020,
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
+               .mid_rid        = 0x8e, /* CHECK ME */
+       }, {
+               .slave_id       = SHDMA_SLAVE_FSI2B_TX,
+               .addr           = 0xec240024,
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
+               .mid_rid        = 0x8d, /* CHECK ME */
+       }, {
+               .slave_id       = SHDMA_SLAVE_FSI2D_RX,
+               .addr           =  0xec240060,
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
+               .mid_rid        = 0x9a, /* CHECK ME */
+       },
+};
+
+#define MPDMA_CHANNEL(a, b, c)                 \
+{                                              \
+       .offset         = a,                    \
+       .dmars          = b,                    \
+       .dmars_bit      = c,                    \
+       .chclr_offset   = (0x220 - 0x20) + a    \
+}
+
+static const struct sh_dmae_channel sh73a0_mpdma_channels[] = {
+       MPDMA_CHANNEL(0x00, 0, 0),
+       MPDMA_CHANNEL(0x10, 0, 8),
+       MPDMA_CHANNEL(0x20, 4, 0),
+       MPDMA_CHANNEL(0x30, 4, 8),
+       MPDMA_CHANNEL(0x50, 8, 0),
+       MPDMA_CHANNEL(0x70, 8, 8),
+};
+
+static struct sh_dmae_pdata sh73a0_mpdma_platform_data = {
+       .slave          = sh73a0_mpdma_slaves,
+       .slave_num      = ARRAY_SIZE(sh73a0_mpdma_slaves),
+       .channel        = sh73a0_mpdma_channels,
+       .channel_num    = ARRAY_SIZE(sh73a0_mpdma_channels),
+       .ts_low_shift   = TS_LOW_SHIFT,
+       .ts_low_mask    = TS_LOW_BIT << TS_LOW_SHIFT,
+       .ts_high_shift  = TS_HI_SHIFT,
+       .ts_high_mask   = TS_HI_BIT << TS_HI_SHIFT,
+       .ts_shift       = dma_ts_shift,
+       .ts_shift_num   = ARRAY_SIZE(dma_ts_shift),
+       .dmaor_init     = DMAOR_DME,
+       .chclr_present  = 1,
+};
+
+/* Resource order important! */
+static struct resource sh73a0_mpdma_resources[] = {
+       {
+               /* Channel registers and DMAOR */
+               .start  = 0xec618020,
+               .end    = 0xec61828f,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* DMARSx */
+               .start  = 0xec619000,
+               .end    = 0xec61900b,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "error_irq",
+               .start  = gic_spi(181),
+               .end    = gic_spi(181),
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               /* IRQ for channels 0-5 */
+               .start  = gic_spi(175),
+               .end    = gic_spi(180),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mpdma0_device = {
+       .name           = "sh-dma-engine",
+       .id             = 1,
+       .resource       = sh73a0_mpdma_resources,
+       .num_resources  = ARRAY_SIZE(sh73a0_mpdma_resources),
+       .dev            = {
+               .platform_data  = &sh73a0_mpdma_platform_data,
+       },
+};
+
 static struct platform_device *sh73a0_early_devices[] __initdata = {
        &scif0_device,
        &scif1_device,
@@ -673,6 +756,7 @@ static struct platform_device *sh73a0_late_devices[] __initdata = {
        &i2c3_device,
        &i2c4_device,
        &dma0_device,
+       &mpdma0_device,
 };
 
 #define SRCR2          0xe61580b0
index d0de9c1192f78eae03b70a8c9d0c7b72e4bc4d0c..c0999633a9ab24054a2c5e2cc9d526c020320b8c 100644 (file)
@@ -64,7 +64,8 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
                       &tegra_ehci2_pdata),
        OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2",
                       &tegra_ehci3_pdata),
-       OF_DEV_AUXDATA("nvidia,tegra20-apbdma", 0x6000a000, "tegra-apbdma", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-apbdma", TEGRA_APB_DMA_BASE, "tegra-apbdma", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL),
        {}
 };
 
index ee48214bfd898ea86f2084dba182e85df96bbc58..53bf60f1158044bf6ce12a3d05972f02b17bdfb1 100644 (file)
@@ -33,6 +33,8 @@
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
 
+#include <mach/iomap.h>
+
 #include "board.h"
 #include "clock.h"
 
@@ -48,6 +50,7 @@ struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL),
        OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL),
        OF_DEV_AUXDATA("nvidia,tegra30-apbdma", 0x6000a000, "tegra-apbdma", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra30-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL),
        {}
 };
 
index a310222951da9f284c2e6bd2713792761a9b3e08..8674a890fd1c7071ae2efce55a3a7c888a97c091 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/i2c.h>
+#include <linux/platform_data/i2c-nomadik.h>
 #include <linux/gpio.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/pl022.h>
@@ -40,7 +41,6 @@
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
 
-#include <plat/i2c.h>
 #include <plat/ste_dma40.h>
 #include <plat/gpio-nomadik.h>
 
@@ -211,24 +211,6 @@ static struct ab8500_platform_data ab8500_platdata = {
        .codec          = &ab8500_codec_pdata,
 };
 
-static struct resource ab8500_resources[] = {
-       [0] = {
-               .start  = IRQ_DB8500_AB8500,
-               .end    = IRQ_DB8500_AB8500,
-               .flags  = IORESOURCE_IRQ
-       }
-};
-
-struct platform_device ab8500_device = {
-       .name = "ab8500-core",
-       .id = 0,
-       .dev = {
-               .platform_data = &ab8500_platdata,
-       },
-       .num_resources = 1,
-       .resource = ab8500_resources,
-};
-
 /*
  * TPS61052
  */
@@ -443,7 +425,6 @@ static struct hash_platform_data u8500_hash1_platform_data = {
 /* add any platform devices here - TODO */
 static struct platform_device *mop500_platform_devs[] __initdata = {
        &mop500_gpio_keys_device,
-       &ab8500_device,
 };
 
 #ifdef CONFIG_STE_DMA40
@@ -605,7 +586,6 @@ static struct platform_device *snowball_platform_devs[] __initdata = {
        &snowball_led_dev,
        &snowball_key_dev,
        &snowball_sbnet_dev,
-       &ab8500_device,
 };
 
 static void __init mop500_init_machine(void)
@@ -617,9 +597,8 @@ static void __init mop500_init_machine(void)
        mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
 
        mop500_pinmaps_init();
-       parent = u8500_init_devices();
+       parent = u8500_init_devices(&ab8500_platdata);
 
-       /* FIXME: parent of ab8500 should be prcmu */
        for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
                mop500_platform_devs[i]->dev.parent = parent;
 
@@ -652,7 +631,7 @@ static void __init snowball_init_machine(void)
        int i;
 
        snowball_pinmaps_init();
-       parent = u8500_init_devices();
+       parent = u8500_init_devices(&ab8500_platdata);
 
        for (i = 0; i < ARRAY_SIZE(snowball_platform_devs); i++)
                snowball_platform_devs[i]->dev.parent = parent;
@@ -684,7 +663,7 @@ static void __init hrefv60_init_machine(void)
        mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO;
 
        hrefv60_pinmaps_init();
-       parent = u8500_init_devices();
+       parent = u8500_init_devices(&ab8500_platdata);
 
        for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
                mop500_platform_devs[i]->dev.parent = parent;
@@ -785,9 +764,6 @@ static const struct of_device_id u8500_local_bus_nodes[] = {
        /* only create devices below soc node */
        { .compatible = "stericsson,db8500", },
        { .compatible = "stericsson,db8500-prcmu", },
-       { .compatible = "stericsson,db8500-prcmu-regulator", },
-       { .compatible = "stericsson,ab8500", },
-       { .compatible = "stericsson,ab8500-regulator", },
        { .compatible = "simple-bus"},
        { },
 };
index c8dd94f606dc2d2db89ebf6a3273167d94773d3c..db3c52d56ca46ad54bddbcaaa2f48d7c64f025a6 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/mfd/abx500/ab8500.h>
 
 #include <asm/mach/map.h>
 #include <asm/pmu.h>
@@ -115,7 +116,7 @@ static irqreturn_t db8500_pmu_handler(int irq, void *dev, irq_handler_t handler)
        return ret;
 }
 
-static struct arm_pmu_platdata db8500_pmu_platdata = {
+struct arm_pmu_platdata db8500_pmu_platdata = {
        .handle_irq             = db8500_pmu_handler,
 };
 
@@ -206,7 +207,7 @@ static struct device * __init db8500_soc_device_init(void)
 /*
  * This function is called from the board init
  */
-struct device * __init u8500_init_devices(void)
+struct device * __init u8500_init_devices(struct ab8500_platform_data *ab8500)
 {
        struct device *parent;
        int i;
@@ -223,6 +224,8 @@ struct device * __init u8500_init_devices(void)
        for (i = 0; i < ARRAY_SIZE(platform_devs); i++)
                platform_devs[i]->dev.parent = parent;
 
+       db8500_prcmu_device.dev.platform_data = ab8500;
+
        platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
 
        return parent;
index 6e47065602669a3a4c720417137f768763c13363..ecdd8386cffb8fc4a6f16cbc811eba854be41619 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/sys_soc.h>
 #include <linux/amba/bus.h>
-#include <plat/i2c.h>
+#include <linux/platform_data/i2c-nomadik.h>
 #include <mach/crypto-ux500.h>
 
 struct spi_master_cntlr;
@@ -56,27 +56,15 @@ dbx500_add_uart(struct device *parent, const char *name, resource_size_t base,
 
 struct nmk_i2c_controller;
 
-static inline struct platform_device *
+static inline struct amba_device *
 dbx500_add_i2c(struct device *parent, int id, resource_size_t base, int irq,
               struct nmk_i2c_controller *data)
 {
-       struct resource res[] = {
-               DEFINE_RES_MEM(base, SZ_4K),
-               DEFINE_RES_IRQ(irq),
-       };
+       /* Conjure a name similar to what the platform device used to have */
+       char name[16];
 
-       struct platform_device_info pdevinfo = {
-               .parent = parent,
-               .name = "nmk-i2c",
-               .id = id,
-               .res = res,
-               .num_res = ARRAY_SIZE(res),
-               .data = data,
-               .size_data = sizeof(*data),
-               .dma_mask = DMA_BIT_MASK(32),
-       };
-
-       return platform_device_register_full(&pdevinfo);
+       snprintf(name, sizeof(name), "nmk-i2c.%d", id);
+       return amba_apb_device_add(parent, name, base, SZ_4K, irq, 0, data, 0);
 }
 
 static inline struct amba_device *
index 8b7ed82a286665961f04d548a0ab1137027fc7d8..7914e5eaa9c775a913d494adc05f8094103a5dee 100644 (file)
 
 #include <asm/mach/time.h>
 #include <linux/init.h>
+#include <linux/mfd/abx500/ab8500.h>
 
 void __init ux500_map_io(void);
 extern void __init u8500_map_io(void);
 
-extern struct device * __init u8500_init_devices(void);
+extern struct device * __init u8500_init_devices(struct ab8500_platform_data *ab8500);
 
 extern void __init ux500_init_irq(void);
 extern void __init ux500_init_late(void);
index 54e69973f39b7344ca0e7ccdb01b2a1be696c907..7ce51767c99c3843091a86fc06b1660b84fd9f3a 100644 (file)
@@ -5,5 +5,3 @@ obj-$(CONFIG_VTWM_VERSION_WM8505) += devices-wm8505.o
 
 obj-$(CONFIG_MACH_BV07) += bv07.o
 obj-$(CONFIG_MACH_WM8505_7IN_NETBOOK) += wm8505_7in.o
-
-obj-$(CONFIG_HAVE_PWM) += pwm.o
diff --git a/arch/arm/mach-vt8500/pwm.c b/arch/arm/mach-vt8500/pwm.c
deleted file mode 100644 (file)
index 8ad825e..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * arch/arm/mach-vt8500/pwm.c
- *
- *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/pwm.h>
-#include <linux/delay.h>
-
-#include <asm/div64.h>
-
-#define VT8500_NR_PWMS 4
-
-static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_list);
-
-struct pwm_device {
-       struct list_head        node;
-       struct platform_device  *pdev;
-
-       const char      *label;
-
-       void __iomem    *regbase;
-
-       unsigned int    use_count;
-       unsigned int    pwm_id;
-};
-
-#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
-static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask)
-{
-       int loops = msecs_to_loops(10);
-       while ((readb(reg) & bitmask) && --loops)
-               cpu_relax();
-
-       if (unlikely(!loops))
-               pr_warning("Waiting for status bits 0x%x to clear timed out\n",
-                          bitmask);
-}
-
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-       unsigned long long c;
-       unsigned long period_cycles, prescale, pv, dc;
-
-       if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
-               return -EINVAL;
-
-       c = 25000000/2; /* wild guess --- need to implement clocks */
-       c = c * period_ns;
-       do_div(c, 1000000000);
-       period_cycles = c;
-
-       if (period_cycles < 1)
-               period_cycles = 1;
-       prescale = (period_cycles - 1) / 4096;
-       pv = period_cycles / (prescale + 1) - 1;
-       if (pv > 4095)
-               pv = 4095;
-
-       if (prescale > 1023)
-               return -EINVAL;
-
-       c = (unsigned long long)pv * duty_ns;
-       do_div(c, period_ns);
-       dc = c;
-
-       pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 1));
-       writel(prescale, pwm->regbase + 0x4 + (pwm->pwm_id << 4));
-
-       pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 2));
-       writel(pv, pwm->regbase + 0x8 + (pwm->pwm_id << 4));
-
-       pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 3));
-       writel(dc, pwm->regbase + 0xc + (pwm->pwm_id << 4));
-
-       return 0;
-}
-EXPORT_SYMBOL(pwm_config);
-
-int pwm_enable(struct pwm_device *pwm)
-{
-       pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0));
-       writel(5, pwm->regbase + (pwm->pwm_id << 4));
-       return 0;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
-       pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0));
-       writel(0, pwm->regbase + (pwm->pwm_id << 4));
-}
-EXPORT_SYMBOL(pwm_disable);
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-       struct pwm_device *pwm;
-       int found = 0;
-
-       mutex_lock(&pwm_lock);
-
-       list_for_each_entry(pwm, &pwm_list, node) {
-               if (pwm->pwm_id == pwm_id) {
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (found) {
-               if (pwm->use_count == 0) {
-                       pwm->use_count++;
-                       pwm->label = label;
-               } else {
-                       pwm = ERR_PTR(-EBUSY);
-               }
-       } else {
-               pwm = ERR_PTR(-ENOENT);
-       }
-
-       mutex_unlock(&pwm_lock);
-       return pwm;
-}
-EXPORT_SYMBOL(pwm_request);
-
-void pwm_free(struct pwm_device *pwm)
-{
-       mutex_lock(&pwm_lock);
-
-       if (pwm->use_count) {
-               pwm->use_count--;
-               pwm->label = NULL;
-       } else {
-               pr_warning("PWM device already freed\n");
-       }
-
-       mutex_unlock(&pwm_lock);
-}
-EXPORT_SYMBOL(pwm_free);
-
-static inline void __add_pwm(struct pwm_device *pwm)
-{
-       mutex_lock(&pwm_lock);
-       list_add_tail(&pwm->node, &pwm_list);
-       mutex_unlock(&pwm_lock);
-}
-
-static int __devinit pwm_probe(struct platform_device *pdev)
-{
-       struct pwm_device *pwms;
-       struct resource *r;
-       int ret = 0;
-       int i;
-
-       pwms = kzalloc(sizeof(struct pwm_device) * VT8500_NR_PWMS, GFP_KERNEL);
-       if (pwms == NULL) {
-               dev_err(&pdev->dev, "failed to allocate memory\n");
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < VT8500_NR_PWMS; i++) {
-               pwms[i].use_count = 0;
-               pwms[i].pwm_id = i;
-               pwms[i].pdev = pdev;
-       }
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "no memory resource defined\n");
-               ret = -ENODEV;
-               goto err_free;
-       }
-
-       r = request_mem_region(r->start, resource_size(r), pdev->name);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "failed to request memory resource\n");
-               ret = -EBUSY;
-               goto err_free;
-       }
-
-       pwms[0].regbase = ioremap(r->start, resource_size(r));
-       if (pwms[0].regbase == NULL) {
-               dev_err(&pdev->dev, "failed to ioremap() registers\n");
-               ret = -ENODEV;
-               goto err_free_mem;
-       }
-
-       for (i = 1; i < VT8500_NR_PWMS; i++)
-               pwms[i].regbase = pwms[0].regbase;
-
-       for (i = 0; i < VT8500_NR_PWMS; i++)
-               __add_pwm(&pwms[i]);
-
-       platform_set_drvdata(pdev, pwms);
-       return 0;
-
-err_free_mem:
-       release_mem_region(r->start, resource_size(r));
-err_free:
-       kfree(pwms);
-       return ret;
-}
-
-static int __devexit pwm_remove(struct platform_device *pdev)
-{
-       struct pwm_device *pwms;
-       struct resource *r;
-       int i;
-
-       pwms = platform_get_drvdata(pdev);
-       if (pwms == NULL)
-               return -ENODEV;
-
-       mutex_lock(&pwm_lock);
-
-       for (i = 0; i < VT8500_NR_PWMS; i++)
-               list_del(&pwms[i].node);
-       mutex_unlock(&pwm_lock);
-
-       iounmap(pwms[0].regbase);
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(r->start, resource_size(r));
-
-       kfree(pwms);
-       return 0;
-}
-
-static struct platform_driver pwm_driver = {
-       .driver         = {
-               .name   = "vt8500-pwm",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = pwm_probe,
-       .remove         = __devexit_p(pwm_remove),
-};
-
-static int __init pwm_init(void)
-{
-       return platform_driver_register(&pwm_driver);
-}
-arch_initcall(pwm_init);
-
-static void __exit pwm_exit(void)
-{
-       platform_driver_unregister(&pwm_driver);
-}
-module_exit(pwm_exit);
-
-MODULE_LICENSE("GPL");
index 5cfc989940761f0a8aa317b3bc37270d40835178..c2cdf6500f75dc5a1ab5a688ea305099e8d30057 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/memblock.h>
 #include <linux/slab.h>
 #include <linux/iommu.h>
+#include <linux/io.h>
 #include <linux/vmalloc.h>
 #include <linux/sizes.h>
 
@@ -72,7 +73,7 @@ static dma_addr_t arm_dma_map_page(struct device *dev, struct page *page,
             unsigned long offset, size_t size, enum dma_data_direction dir,
             struct dma_attrs *attrs)
 {
-       if (!arch_is_coherent())
+       if (!arch_is_coherent() && !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
                __dma_page_cpu_to_dev(page, offset, size, dir);
        return pfn_to_dma(dev, page_to_pfn(page)) + offset;
 }
@@ -95,7 +96,7 @@ static void arm_dma_unmap_page(struct device *dev, dma_addr_t handle,
                size_t size, enum dma_data_direction dir,
                struct dma_attrs *attrs)
 {
-       if (!arch_is_coherent())
+       if (!arch_is_coherent() && !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
                __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)),
                                      handle & ~PAGE_MASK, size, dir);
 }
@@ -124,6 +125,7 @@ struct dma_map_ops arm_dma_ops = {
        .alloc                  = arm_dma_alloc,
        .free                   = arm_dma_free,
        .mmap                   = arm_dma_mmap,
+       .get_sgtable            = arm_dma_get_sgtable,
        .map_page               = arm_dma_map_page,
        .unmap_page             = arm_dma_unmap_page,
        .map_sg                 = arm_dma_map_sg,
@@ -217,115 +219,70 @@ static void __dma_free_buffer(struct page *page, size_t size)
 }
 
 #ifdef CONFIG_MMU
+#ifdef CONFIG_HUGETLB_PAGE
+#error ARM Coherent DMA allocator does not (yet) support huge TLB
+#endif
 
-#define CONSISTENT_OFFSET(x)   (((unsigned long)(x) - consistent_base) >> PAGE_SHIFT)
-#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - consistent_base) >> PMD_SHIFT)
-
-/*
- * These are the page tables (2MB each) covering uncached, DMA consistent allocations
- */
-static pte_t **consistent_pte;
-
-#define DEFAULT_CONSISTENT_DMA_SIZE SZ_2M
+static void *__alloc_from_contiguous(struct device *dev, size_t size,
+                                    pgprot_t prot, struct page **ret_page);
 
-static unsigned long consistent_base = CONSISTENT_END - DEFAULT_CONSISTENT_DMA_SIZE;
+static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
+                                pgprot_t prot, struct page **ret_page,
+                                const void *caller);
 
-void __init init_consistent_dma_size(unsigned long size)
+static void *
+__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
+       const void *caller)
 {
-       unsigned long base = CONSISTENT_END - ALIGN(size, SZ_2M);
+       struct vm_struct *area;
+       unsigned long addr;
 
-       BUG_ON(consistent_pte); /* Check we're called before DMA region init */
-       BUG_ON(base < VMALLOC_END);
+       /*
+        * DMA allocation can be mapped to user space, so lets
+        * set VM_USERMAP flags too.
+        */
+       area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
+                                 caller);
+       if (!area)
+               return NULL;
+       addr = (unsigned long)area->addr;
+       area->phys_addr = __pfn_to_phys(page_to_pfn(page));
 
-       /* Grow region to accommodate specified size  */
-       if (base < consistent_base)
-               consistent_base = base;
+       if (ioremap_page_range(addr, addr + size, area->phys_addr, prot)) {
+               vunmap((void *)addr);
+               return NULL;
+       }
+       return (void *)addr;
 }
 
-#include "vmregion.h"
-
-static struct arm_vmregion_head consistent_head = {
-       .vm_lock        = __SPIN_LOCK_UNLOCKED(&consistent_head.vm_lock),
-       .vm_list        = LIST_HEAD_INIT(consistent_head.vm_list),
-       .vm_end         = CONSISTENT_END,
-};
-
-#ifdef CONFIG_HUGETLB_PAGE
-#error ARM Coherent DMA allocator does not (yet) support huge TLB
-#endif
-
-/*
- * Initialise the consistent memory allocation.
- */
-static int __init consistent_init(void)
+static void __dma_free_remap(void *cpu_addr, size_t size)
 {
-       int ret = 0;
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *pte;
-       int i = 0;
-       unsigned long base = consistent_base;
-       unsigned long num_ptes = (CONSISTENT_END - base) >> PMD_SHIFT;
-
-       if (IS_ENABLED(CONFIG_CMA) && !IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
-               return 0;
-
-       consistent_pte = kmalloc(num_ptes * sizeof(pte_t), GFP_KERNEL);
-       if (!consistent_pte) {
-               pr_err("%s: no memory\n", __func__);
-               return -ENOMEM;
+       unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP;
+       struct vm_struct *area = find_vm_area(cpu_addr);
+       if (!area || (area->flags & flags) != flags) {
+               WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
+               return;
        }
-
-       pr_debug("DMA memory: 0x%08lx - 0x%08lx:\n", base, CONSISTENT_END);
-       consistent_head.vm_start = base;
-
-       do {
-               pgd = pgd_offset(&init_mm, base);
-
-               pud = pud_alloc(&init_mm, pgd, base);
-               if (!pud) {
-                       pr_err("%s: no pud tables\n", __func__);
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               pmd = pmd_alloc(&init_mm, pud, base);
-               if (!pmd) {
-                       pr_err("%s: no pmd tables\n", __func__);
-                       ret = -ENOMEM;
-                       break;
-               }
-               WARN_ON(!pmd_none(*pmd));
-
-               pte = pte_alloc_kernel(pmd, base);
-               if (!pte) {
-                       pr_err("%s: no pte tables\n", __func__);
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               consistent_pte[i++] = pte;
-               base += PMD_SIZE;
-       } while (base < CONSISTENT_END);
-
-       return ret;
+       unmap_kernel_range((unsigned long)cpu_addr, size);
+       vunmap(cpu_addr);
 }
-core_initcall(consistent_init);
 
-static void *__alloc_from_contiguous(struct device *dev, size_t size,
-                                    pgprot_t prot, struct page **ret_page);
-
-static struct arm_vmregion_head coherent_head = {
-       .vm_lock        = __SPIN_LOCK_UNLOCKED(&coherent_head.vm_lock),
-       .vm_list        = LIST_HEAD_INIT(coherent_head.vm_list),
+struct dma_pool {
+       size_t size;
+       spinlock_t lock;
+       unsigned long *bitmap;
+       unsigned long nr_pages;
+       void *vaddr;
+       struct page *page;
 };
 
-static size_t coherent_pool_size = DEFAULT_CONSISTENT_DMA_SIZE / 8;
+static struct dma_pool atomic_pool = {
+       .size = SZ_256K,
+};
 
 static int __init early_coherent_pool(char *p)
 {
-       coherent_pool_size = memparse(p, &p);
+       atomic_pool.size = memparse(p, &p);
        return 0;
 }
 early_param("coherent_pool", early_coherent_pool);
@@ -333,32 +290,45 @@ early_param("coherent_pool", early_coherent_pool);
 /*
  * Initialise the coherent pool for atomic allocations.
  */
-static int __init coherent_init(void)
+static int __init atomic_pool_init(void)
 {
+       struct dma_pool *pool = &atomic_pool;
        pgprot_t prot = pgprot_dmacoherent(pgprot_kernel);
-       size_t size = coherent_pool_size;
+       unsigned long nr_pages = pool->size >> PAGE_SHIFT;
+       unsigned long *bitmap;
        struct page *page;
        void *ptr;
+       int bitmap_size = BITS_TO_LONGS(nr_pages) * sizeof(long);
 
-       if (!IS_ENABLED(CONFIG_CMA))
-               return 0;
+       bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+       if (!bitmap)
+               goto no_bitmap;
 
-       ptr = __alloc_from_contiguous(NULL, size, prot, &page);
+       if (IS_ENABLED(CONFIG_CMA))
+               ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page);
+       else
+               ptr = __alloc_remap_buffer(NULL, pool->size, GFP_KERNEL, prot,
+                                          &page, NULL);
        if (ptr) {
-               coherent_head.vm_start = (unsigned long) ptr;
-               coherent_head.vm_end = (unsigned long) ptr + size;
-               printk(KERN_INFO "DMA: preallocated %u KiB pool for atomic coherent allocations\n",
-                      (unsigned)size / 1024);
+               spin_lock_init(&pool->lock);
+               pool->vaddr = ptr;
+               pool->page = page;
+               pool->bitmap = bitmap;
+               pool->nr_pages = nr_pages;
+               pr_info("DMA: preallocated %u KiB pool for atomic coherent allocations\n",
+                      (unsigned)pool->size / 1024);
                return 0;
        }
-       printk(KERN_ERR "DMA: failed to allocate %u KiB pool for atomic coherent allocation\n",
-              (unsigned)size / 1024);
+       kfree(bitmap);
+no_bitmap:
+       pr_err("DMA: failed to allocate %u KiB pool for atomic coherent allocation\n",
+              (unsigned)pool->size / 1024);
        return -ENOMEM;
 }
 /*
  * CMA is activated by core_initcall, so we must be called after it.
  */
-postcore_initcall(coherent_init);
+postcore_initcall(atomic_pool_init);
 
 struct dma_contig_early_reserve {
        phys_addr_t base;
@@ -406,112 +376,6 @@ void __init dma_contiguous_remap(void)
        }
 }
 
-static void *
-__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
-       const void *caller)
-{
-       struct arm_vmregion *c;
-       size_t align;
-       int bit;
-
-       if (!consistent_pte) {
-               pr_err("%s: not initialised\n", __func__);
-               dump_stack();
-               return NULL;
-       }
-
-       /*
-        * Align the virtual region allocation - maximum alignment is
-        * a section size, minimum is a page size.  This helps reduce
-        * fragmentation of the DMA space, and also prevents allocations
-        * smaller than a section from crossing a section boundary.
-        */
-       bit = fls(size - 1);
-       if (bit > SECTION_SHIFT)
-               bit = SECTION_SHIFT;
-       align = 1 << bit;
-
-       /*
-        * Allocate a virtual address in the consistent mapping region.
-        */
-       c = arm_vmregion_alloc(&consistent_head, align, size,
-                           gfp & ~(__GFP_DMA | __GFP_HIGHMEM), caller);
-       if (c) {
-               pte_t *pte;
-               int idx = CONSISTENT_PTE_INDEX(c->vm_start);
-               u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
-
-               pte = consistent_pte[idx] + off;
-               c->priv = page;
-
-               do {
-                       BUG_ON(!pte_none(*pte));
-
-                       set_pte_ext(pte, mk_pte(page, prot), 0);
-                       page++;
-                       pte++;
-                       off++;
-                       if (off >= PTRS_PER_PTE) {
-                               off = 0;
-                               pte = consistent_pte[++idx];
-                       }
-               } while (size -= PAGE_SIZE);
-
-               dsb();
-
-               return (void *)c->vm_start;
-       }
-       return NULL;
-}
-
-static void __dma_free_remap(void *cpu_addr, size_t size)
-{
-       struct arm_vmregion *c;
-       unsigned long addr;
-       pte_t *ptep;
-       int idx;
-       u32 off;
-
-       c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr);
-       if (!c) {
-               pr_err("%s: trying to free invalid coherent area: %p\n",
-                      __func__, cpu_addr);
-               dump_stack();
-               return;
-       }
-
-       if ((c->vm_end - c->vm_start) != size) {
-               pr_err("%s: freeing wrong coherent size (%ld != %d)\n",
-                      __func__, c->vm_end - c->vm_start, size);
-               dump_stack();
-               size = c->vm_end - c->vm_start;
-       }
-
-       idx = CONSISTENT_PTE_INDEX(c->vm_start);
-       off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
-       ptep = consistent_pte[idx] + off;
-       addr = c->vm_start;
-       do {
-               pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
-
-               ptep++;
-               addr += PAGE_SIZE;
-               off++;
-               if (off >= PTRS_PER_PTE) {
-                       off = 0;
-                       ptep = consistent_pte[++idx];
-               }
-
-               if (pte_none(pte) || !pte_present(pte))
-                       pr_crit("%s: bad page in kernel page table\n",
-                               __func__);
-       } while (size -= PAGE_SIZE);
-
-       flush_tlb_kernel_range(c->vm_start, c->vm_end);
-
-       arm_vmregion_free(&consistent_head, c);
-}
-
 static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr,
                            void *data)
 {
@@ -552,16 +416,17 @@ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
        return ptr;
 }
 
-static void *__alloc_from_pool(struct device *dev, size_t size,
-                              struct page **ret_page, const void *caller)
+static void *__alloc_from_pool(size_t size, struct page **ret_page)
 {
-       struct arm_vmregion *c;
+       struct dma_pool *pool = &atomic_pool;
+       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       unsigned int pageno;
+       unsigned long flags;
+       void *ptr = NULL;
        size_t align;
 
-       if (!coherent_head.vm_start) {
-               printk(KERN_ERR "%s: coherent pool not initialised!\n",
-                      __func__);
-               dump_stack();
+       if (!pool->vaddr) {
+               WARN(1, "coherent pool not initialised!\n");
                return NULL;
        }
 
@@ -571,35 +436,41 @@ static void *__alloc_from_pool(struct device *dev, size_t size,
         * size. This helps reduce fragmentation of the DMA space.
         */
        align = PAGE_SIZE << get_order(size);
-       c = arm_vmregion_alloc(&coherent_head, align, size, 0, caller);
-       if (c) {
-               void *ptr = (void *)c->vm_start;
-               struct page *page = virt_to_page(ptr);
-               *ret_page = page;
-               return ptr;
+
+       spin_lock_irqsave(&pool->lock, flags);
+       pageno = bitmap_find_next_zero_area(pool->bitmap, pool->nr_pages,
+                                           0, count, (1 << align) - 1);
+       if (pageno < pool->nr_pages) {
+               bitmap_set(pool->bitmap, pageno, count);
+               ptr = pool->vaddr + PAGE_SIZE * pageno;
+               *ret_page = pool->page + pageno;
        }
-       return NULL;
+       spin_unlock_irqrestore(&pool->lock, flags);
+
+       return ptr;
 }
 
-static int __free_from_pool(void *cpu_addr, size_t size)
+static int __free_from_pool(void *start, size_t size)
 {
-       unsigned long start = (unsigned long)cpu_addr;
-       unsigned long end = start + size;
-       struct arm_vmregion *c;
+       struct dma_pool *pool = &atomic_pool;
+       unsigned long pageno, count;
+       unsigned long flags;
 
-       if (start < coherent_head.vm_start || end > coherent_head.vm_end)
+       if (start < pool->vaddr || start > pool->vaddr + pool->size)
                return 0;
 
-       c = arm_vmregion_find_remove(&coherent_head, (unsigned long)start);
-
-       if ((c->vm_end - c->vm_start) != size) {
-               printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
-                      __func__, c->vm_end - c->vm_start, size);
-               dump_stack();
-               size = c->vm_end - c->vm_start;
+       if (start + size > pool->vaddr + pool->size) {
+               WARN(1, "freeing wrong coherent size from pool\n");
+               return 0;
        }
 
-       arm_vmregion_free(&coherent_head, c);
+       pageno = (start - pool->vaddr) >> PAGE_SHIFT;
+       count = size >> PAGE_SHIFT;
+
+       spin_lock_irqsave(&pool->lock, flags);
+       bitmap_clear(pool->bitmap, pageno, count);
+       spin_unlock_irqrestore(&pool->lock, flags);
+
        return 1;
 }
 
@@ -644,7 +515,7 @@ static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot)
 
 #define __get_dma_pgprot(attrs, prot)  __pgprot(0)
 #define __alloc_remap_buffer(dev, size, gfp, prot, ret, c)     NULL
-#define __alloc_from_pool(dev, size, ret_page, c)              NULL
+#define __alloc_from_pool(size, ret_page)                      NULL
 #define __alloc_from_contiguous(dev, size, prot, ret)          NULL
 #define __free_from_pool(cpu_addr, size)                       0
 #define __free_from_contiguous(dev, page, size)                        do { } while (0)
@@ -702,10 +573,10 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
 
        if (arch_is_coherent() || nommu())
                addr = __alloc_simple_buffer(dev, size, gfp, &page);
+       else if (gfp & GFP_ATOMIC)
+               addr = __alloc_from_pool(size, &page);
        else if (!IS_ENABLED(CONFIG_CMA))
                addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller);
-       else if (gfp & GFP_ATOMIC)
-               addr = __alloc_from_pool(dev, size, &page, caller);
        else
                addr = __alloc_from_contiguous(dev, size, prot, &page);
 
@@ -741,16 +612,22 @@ int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
 {
        int ret = -ENXIO;
 #ifdef CONFIG_MMU
+       unsigned long nr_vma_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+       unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
        unsigned long pfn = dma_to_pfn(dev, dma_addr);
+       unsigned long off = vma->vm_pgoff;
+
        vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
 
        if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;
 
-       ret = remap_pfn_range(vma, vma->vm_start,
-                             pfn + vma->vm_pgoff,
-                             vma->vm_end - vma->vm_start,
-                             vma->vm_page_prot);
+       if (off < nr_pages && nr_vma_pages <= (nr_pages - off)) {
+               ret = remap_pfn_range(vma, vma->vm_start,
+                                     pfn + off,
+                                     vma->vm_end - vma->vm_start,
+                                     vma->vm_page_prot);
+       }
 #endif /* CONFIG_MMU */
 
        return ret;
@@ -785,6 +662,21 @@ void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
        }
 }
 
+int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
+                void *cpu_addr, dma_addr_t handle, size_t size,
+                struct dma_attrs *attrs)
+{
+       struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
+       int ret;
+
+       ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
+       if (unlikely(ret))
+               return ret;
+
+       sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
+       return 0;
+}
+
 static void dma_cache_maint_page(struct page *page, unsigned long offset,
        size_t size, enum dma_data_direction dir,
        void (*op)(const void *, size_t, int))
@@ -998,9 +890,6 @@ static int arm_dma_set_mask(struct device *dev, u64 dma_mask)
 
 static int __init dma_debug_do_init(void)
 {
-#ifdef CONFIG_MMU
-       arm_vmregion_create_proc("dma-mappings", &consistent_head);
-#endif
        dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
        return 0;
 }
@@ -1088,7 +977,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t
 
        return pages;
 error:
-       while (--i)
+       while (i--)
                if (pages[i])
                        __free_pages(pages[i], 0);
        if (array_size <= PAGE_SIZE)
@@ -1117,61 +1006,32 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t s
  * Create a CPU mapping for a specified pages
  */
 static void *
-__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot)
+__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot,
+                   const void *caller)
 {
-       struct arm_vmregion *c;
-       size_t align;
-       size_t count = size >> PAGE_SHIFT;
-       int bit;
+       unsigned int i, nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       struct vm_struct *area;
+       unsigned long p;
 
-       if (!consistent_pte[0]) {
-               pr_err("%s: not initialised\n", __func__);
-               dump_stack();
+       area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
+                                 caller);
+       if (!area)
                return NULL;
-       }
-
-       /*
-        * Align the virtual region allocation - maximum alignment is
-        * a section size, minimum is a page size.  This helps reduce
-        * fragmentation of the DMA space, and also prevents allocations
-        * smaller than a section from crossing a section boundary.
-        */
-       bit = fls(size - 1);
-       if (bit > SECTION_SHIFT)
-               bit = SECTION_SHIFT;
-       align = 1 << bit;
-
-       /*
-        * Allocate a virtual address in the consistent mapping region.
-        */
-       c = arm_vmregion_alloc(&consistent_head, align, size,
-                           gfp & ~(__GFP_DMA | __GFP_HIGHMEM), NULL);
-       if (c) {
-               pte_t *pte;
-               int idx = CONSISTENT_PTE_INDEX(c->vm_start);
-               int i = 0;
-               u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
-
-               pte = consistent_pte[idx] + off;
-               c->priv = pages;
-
-               do {
-                       BUG_ON(!pte_none(*pte));
-
-                       set_pte_ext(pte, mk_pte(pages[i], prot), 0);
-                       pte++;
-                       off++;
-                       i++;
-                       if (off >= PTRS_PER_PTE) {
-                               off = 0;
-                               pte = consistent_pte[++idx];
-                       }
-               } while (i < count);
 
-               dsb();
+       area->pages = pages;
+       area->nr_pages = nr_pages;
+       p = (unsigned long)area->addr;
 
-               return (void *)c->vm_start;
+       for (i = 0; i < nr_pages; i++) {
+               phys_addr_t phys = __pfn_to_phys(page_to_pfn(pages[i]));
+               if (ioremap_page_range(p, p + PAGE_SIZE, phys, prot))
+                       goto err;
+               p += PAGE_SIZE;
        }
+       return area->addr;
+err:
+       unmap_kernel_range((unsigned long)area->addr, size);
+       vunmap(area->addr);
        return NULL;
 }
 
@@ -1230,6 +1090,19 @@ static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t si
        return 0;
 }
 
+static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs)
+{
+       struct vm_struct *area;
+
+       if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
+               return cpu_addr;
+
+       area = find_vm_area(cpu_addr);
+       if (area && (area->flags & VM_ARM_DMA_CONSISTENT))
+               return area->pages;
+       return NULL;
+}
+
 static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
            dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
 {
@@ -1248,7 +1121,11 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
        if (*handle == DMA_ERROR_CODE)
                goto err_buffer;
 
-       addr = __iommu_alloc_remap(pages, size, gfp, prot);
+       if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
+               return pages;
+
+       addr = __iommu_alloc_remap(pages, size, gfp, prot,
+                                  __builtin_return_address(0));
        if (!addr)
                goto err_mapping;
 
@@ -1265,31 +1142,25 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
                    void *cpu_addr, dma_addr_t dma_addr, size_t size,
                    struct dma_attrs *attrs)
 {
-       struct arm_vmregion *c;
+       unsigned long uaddr = vma->vm_start;
+       unsigned long usize = vma->vm_end - vma->vm_start;
+       struct page **pages = __iommu_get_pages(cpu_addr, attrs);
 
        vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
-       c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
-
-       if (c) {
-               struct page **pages = c->priv;
-
-               unsigned long uaddr = vma->vm_start;
-               unsigned long usize = vma->vm_end - vma->vm_start;
-               int i = 0;
 
-               do {
-                       int ret;
+       if (!pages)
+               return -ENXIO;
 
-                       ret = vm_insert_page(vma, uaddr, pages[i++]);
-                       if (ret) {
-                               pr_err("Remapping memory, error: %d\n", ret);
-                               return ret;
-                       }
+       do {
+               int ret = vm_insert_page(vma, uaddr, *pages++);
+               if (ret) {
+                       pr_err("Remapping memory failed: %d\n", ret);
+                       return ret;
+               }
+               uaddr += PAGE_SIZE;
+               usize -= PAGE_SIZE;
+       } while (usize > 0);
 
-                       uaddr += PAGE_SIZE;
-                       usize -= PAGE_SIZE;
-               } while (usize > 0);
-       }
        return 0;
 }
 
@@ -1300,16 +1171,35 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
 void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
                          dma_addr_t handle, struct dma_attrs *attrs)
 {
-       struct arm_vmregion *c;
+       struct page **pages = __iommu_get_pages(cpu_addr, attrs);
        size = PAGE_ALIGN(size);
 
-       c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
-       if (c) {
-               struct page **pages = c->priv;
-               __dma_free_remap(cpu_addr, size);
-               __iommu_remove_mapping(dev, handle, size);
-               __iommu_free_buffer(dev, pages, size);
+       if (!pages) {
+               WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
+               return;
        }
+
+       if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) {
+               unmap_kernel_range((unsigned long)cpu_addr, size);
+               vunmap(cpu_addr);
+       }
+
+       __iommu_remove_mapping(dev, handle, size);
+       __iommu_free_buffer(dev, pages, size);
+}
+
+static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
+                                void *cpu_addr, dma_addr_t dma_addr,
+                                size_t size, struct dma_attrs *attrs)
+{
+       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       struct page **pages = __iommu_get_pages(cpu_addr, attrs);
+
+       if (!pages)
+               return -ENXIO;
+
+       return sg_alloc_table_from_pages(sgt, pages, count, 0, size,
+                                        GFP_KERNEL);
 }
 
 /*
@@ -1317,7 +1207,7 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
  */
 static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
                          size_t size, dma_addr_t *handle,
-                         enum dma_data_direction dir)
+                         enum dma_data_direction dir, struct dma_attrs *attrs)
 {
        struct dma_iommu_mapping *mapping = dev->archdata.mapping;
        dma_addr_t iova, iova_base;
@@ -1336,7 +1226,8 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
                phys_addr_t phys = page_to_phys(sg_page(s));
                unsigned int len = PAGE_ALIGN(s->offset + s->length);
 
-               if (!arch_is_coherent())
+               if (!arch_is_coherent() &&
+                   !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
                        __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
 
                ret = iommu_map(mapping->domain, iova, phys, len, 0);
@@ -1383,7 +1274,7 @@ int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 
                if (s->offset || (size & ~PAGE_MASK) || size + s->length > max) {
                        if (__map_sg_chunk(dev, start, size, &dma->dma_address,
-                           dir) < 0)
+                           dir, attrs) < 0)
                                goto bad_mapping;
 
                        dma->dma_address += offset;
@@ -1396,7 +1287,7 @@ int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
                }
                size += s->length;
        }
-       if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir) < 0)
+       if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir, attrs) < 0)
                goto bad_mapping;
 
        dma->dma_address += offset;
@@ -1430,7 +1321,8 @@ void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
                if (sg_dma_len(s))
                        __iommu_remove_mapping(dev, sg_dma_address(s),
                                               sg_dma_len(s));
-               if (!arch_is_coherent())
+               if (!arch_is_coherent() &&
+                   !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
                        __dma_page_dev_to_cpu(sg_page(s), s->offset,
                                              s->length, dir);
        }
@@ -1492,7 +1384,7 @@ static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
        dma_addr_t dma_addr;
        int ret, len = PAGE_ALIGN(size + offset);
 
-       if (!arch_is_coherent())
+       if (!arch_is_coherent() && !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
                __dma_page_cpu_to_dev(page, offset, size, dir);
 
        dma_addr = __alloc_iova(mapping, len);
@@ -1531,7 +1423,7 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
        if (!iova)
                return;
 
-       if (!arch_is_coherent())
+       if (!arch_is_coherent() && !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
                __dma_page_dev_to_cpu(page, offset, size, dir);
 
        iommu_unmap(mapping->domain, iova, len);
@@ -1571,6 +1463,7 @@ struct dma_map_ops iommu_ops = {
        .alloc          = arm_iommu_alloc_attrs,
        .free           = arm_iommu_free_attrs,
        .mmap           = arm_iommu_mmap_attrs,
+       .get_sgtable    = arm_iommu_get_sgtable,
 
        .map_page               = arm_iommu_map_page,
        .unmap_page             = arm_iommu_unmap_page,
index 2e8a1efdf7b85f3443294b396ec5673496dd635d..6776160618ef0ede79d07b4f6a0873c30df2a1d0 100644 (file)
@@ -59,6 +59,9 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page
 #define VM_ARM_MTYPE(mt)               ((mt) << 20)
 #define VM_ARM_MTYPE_MASK      (0x1f << 20)
 
+/* consistent regions used by dma_alloc_attrs() */
+#define VM_ARM_DMA_CONSISTENT  0x20000000
+
 #endif
 
 #ifdef CONFIG_ZONE_DMA
index c722f9ce691827e8924674119b75708ba7ea6428..baf9064c0844bcafef399f943209a570dc34ceec 100644 (file)
@@ -47,12 +47,6 @@ config MXC_TZIC
 config MXC_AVIC
        bool
 
-config MXC_PWM
-       tristate "Enable PWM driver"
-       select HAVE_PWM
-       help
-         Enable support for the i.MX PWM controller(s).
-
 config MXC_DEBUG_BOARD
        bool "Enable MXC debug board(for 3-stack)"
        help
index 63b064b5c1d55148c1c5fa226a6173aafbb3a23f..6ac72003115088fbade50e658ae438b18c0a1610 100644 (file)
@@ -11,7 +11,6 @@ obj-$(CONFIG_MXC_AVIC) += avic.o
 obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
 obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
 obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o
-obj-$(CONFIG_MXC_PWM)  += pwm.o
 obj-$(CONFIG_MXC_ULPI) += ulpi.o
 obj-$(CONFIG_MXC_USE_EPIT) += epit.o
 obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
index 375cdd0cf876b114f9e9e6fcbd7751cbc5fddf01..8289d915e615855c9b5628b6503d3c13616045db 100644 (file)
@@ -15,7 +15,7 @@
  *
  **/
 struct imxi2c_platform_data {
-       int bitrate;
+       u32 bitrate;
 };
 
 #endif /* __ASM_ARCH_I2C_H_ */
index f302d048392db9df129f7b5e025a007e28f11419..af8e484001e54c212ea89e8e16907d374bb46568 100644 (file)
@@ -8,5 +8,4 @@ obj-$(CONFIG_PXA3xx)            += mfp.o
 obj-$(CONFIG_PXA95x)           += mfp.o
 obj-$(CONFIG_ARCH_MMP)         += mfp.o
 
-obj-$(CONFIG_HAVE_PWM)         += pwm.o
 obj-$(CONFIG_PXA_SSP)          += ssp.o
diff --git a/arch/arm/plat-pxa/pwm.c b/arch/arm/plat-pxa/pwm.c
deleted file mode 100644 (file)
index ef32686..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/pwm.c
- *
- * simple driver for PWM (Pulse Width Modulator) controller
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 2008-02-13  initial version
- *             eric miao <eric.miao@marvell.com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/pwm.h>
-
-#include <asm/div64.h>
-
-#define HAS_SECONDARY_PWM      0x10
-#define PWM_ID_BASE(d)         ((d) & 0xf)
-
-static const struct platform_device_id pwm_id_table[] = {
-       /*   PWM    has_secondary_pwm? */
-       { "pxa25x-pwm", 0 },
-       { "pxa27x-pwm", 0 | HAS_SECONDARY_PWM },
-       { "pxa168-pwm", 1 },
-       { "pxa910-pwm", 1 },
-       { },
-};
-MODULE_DEVICE_TABLE(platform, pwm_id_table);
-
-/* PWM registers and bits definitions */
-#define PWMCR          (0x00)
-#define PWMDCR         (0x04)
-#define PWMPCR         (0x08)
-
-#define PWMCR_SD       (1 << 6)
-#define PWMDCR_FD      (1 << 10)
-
-struct pwm_device {
-       struct list_head        node;
-       struct pwm_device       *secondary;
-       struct platform_device  *pdev;
-
-       const char      *label;
-       struct clk      *clk;
-       int             clk_enabled;
-       void __iomem    *mmio_base;
-
-       unsigned int    use_count;
-       unsigned int    pwm_id;
-};
-
-/*
- * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
- * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
- */
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-       unsigned long long c;
-       unsigned long period_cycles, prescale, pv, dc;
-
-       if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
-               return -EINVAL;
-
-       c = clk_get_rate(pwm->clk);
-       c = c * period_ns;
-       do_div(c, 1000000000);
-       period_cycles = c;
-
-       if (period_cycles < 1)
-               period_cycles = 1;
-       prescale = (period_cycles - 1) / 1024;
-       pv = period_cycles / (prescale + 1) - 1;
-
-       if (prescale > 63)
-               return -EINVAL;
-
-       if (duty_ns == period_ns)
-               dc = PWMDCR_FD;
-       else
-               dc = (pv + 1) * duty_ns / period_ns;
-
-       /* NOTE: the clock to PWM has to be enabled first
-        * before writing to the registers
-        */
-       clk_enable(pwm->clk);
-       __raw_writel(prescale, pwm->mmio_base + PWMCR);
-       __raw_writel(dc, pwm->mmio_base + PWMDCR);
-       __raw_writel(pv, pwm->mmio_base + PWMPCR);
-       clk_disable(pwm->clk);
-
-       return 0;
-}
-EXPORT_SYMBOL(pwm_config);
-
-int pwm_enable(struct pwm_device *pwm)
-{
-       int rc = 0;
-
-       if (!pwm->clk_enabled) {
-               rc = clk_enable(pwm->clk);
-               if (!rc)
-                       pwm->clk_enabled = 1;
-       }
-       return rc;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
-       if (pwm->clk_enabled) {
-               clk_disable(pwm->clk);
-               pwm->clk_enabled = 0;
-       }
-}
-EXPORT_SYMBOL(pwm_disable);
-
-static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_list);
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-       struct pwm_device *pwm;
-       int found = 0;
-
-       mutex_lock(&pwm_lock);
-
-       list_for_each_entry(pwm, &pwm_list, node) {
-               if (pwm->pwm_id == pwm_id) {
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (found) {
-               if (pwm->use_count == 0) {
-                       pwm->use_count++;
-                       pwm->label = label;
-               } else
-                       pwm = ERR_PTR(-EBUSY);
-       } else
-               pwm = ERR_PTR(-ENOENT);
-
-       mutex_unlock(&pwm_lock);
-       return pwm;
-}
-EXPORT_SYMBOL(pwm_request);
-
-void pwm_free(struct pwm_device *pwm)
-{
-       mutex_lock(&pwm_lock);
-
-       if (pwm->use_count) {
-               pwm->use_count--;
-               pwm->label = NULL;
-       } else
-               pr_warning("PWM device already freed\n");
-
-       mutex_unlock(&pwm_lock);
-}
-EXPORT_SYMBOL(pwm_free);
-
-static inline void __add_pwm(struct pwm_device *pwm)
-{
-       mutex_lock(&pwm_lock);
-       list_add_tail(&pwm->node, &pwm_list);
-       mutex_unlock(&pwm_lock);
-}
-
-static int __devinit pwm_probe(struct platform_device *pdev)
-{
-       const struct platform_device_id *id = platform_get_device_id(pdev);
-       struct pwm_device *pwm, *secondary = NULL;
-       struct resource *r;
-       int ret = 0;
-
-       pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
-       if (pwm == NULL) {
-               dev_err(&pdev->dev, "failed to allocate memory\n");
-               return -ENOMEM;
-       }
-
-       pwm->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(pwm->clk)) {
-               ret = PTR_ERR(pwm->clk);
-               goto err_free;
-       }
-       pwm->clk_enabled = 0;
-
-       pwm->use_count = 0;
-       pwm->pwm_id = PWM_ID_BASE(id->driver_data) + pdev->id;
-       pwm->pdev = pdev;
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "no memory resource defined\n");
-               ret = -ENODEV;
-               goto err_free_clk;
-       }
-
-       r = request_mem_region(r->start, resource_size(r), pdev->name);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "failed to request memory resource\n");
-               ret = -EBUSY;
-               goto err_free_clk;
-       }
-
-       pwm->mmio_base = ioremap(r->start, resource_size(r));
-       if (pwm->mmio_base == NULL) {
-               dev_err(&pdev->dev, "failed to ioremap() registers\n");
-               ret = -ENODEV;
-               goto err_free_mem;
-       }
-
-       if (id->driver_data & HAS_SECONDARY_PWM) {
-               secondary = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
-               if (secondary == NULL) {
-                       ret = -ENOMEM;
-                       goto err_free_mem;
-               }
-
-               *secondary = *pwm;
-               pwm->secondary = secondary;
-
-               /* registers for the second PWM has offset of 0x10 */
-               secondary->mmio_base = pwm->mmio_base + 0x10;
-               secondary->pwm_id = pdev->id + 2;
-       }
-
-       __add_pwm(pwm);
-       if (secondary)
-               __add_pwm(secondary);
-
-       platform_set_drvdata(pdev, pwm);
-       return 0;
-
-err_free_mem:
-       release_mem_region(r->start, resource_size(r));
-err_free_clk:
-       clk_put(pwm->clk);
-err_free:
-       kfree(pwm);
-       return ret;
-}
-
-static int __devexit pwm_remove(struct platform_device *pdev)
-{
-       struct pwm_device *pwm;
-       struct resource *r;
-
-       pwm = platform_get_drvdata(pdev);
-       if (pwm == NULL)
-               return -ENODEV;
-
-       mutex_lock(&pwm_lock);
-
-       if (pwm->secondary) {
-               list_del(&pwm->secondary->node);
-               kfree(pwm->secondary);
-       }
-
-       list_del(&pwm->node);
-       mutex_unlock(&pwm_lock);
-
-       iounmap(pwm->mmio_base);
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(r->start, resource_size(r));
-
-       clk_put(pwm->clk);
-       kfree(pwm);
-       return 0;
-}
-
-static struct platform_driver pwm_driver = {
-       .driver         = {
-               .name   = "pxa25x-pwm",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = pwm_probe,
-       .remove         = __devexit_p(pwm_remove),
-       .id_table       = pwm_id_table,
-};
-
-static int __init pwm_init(void)
-{
-       return platform_driver_register(&pwm_driver);
-}
-arch_initcall(pwm_init);
-
-static void __exit pwm_exit(void)
-{
-       platform_driver_unregister(&pwm_driver);
-}
-module_exit(pwm_exit);
-
-MODULE_LICENSE("GPL v2");
index b78717496677fae8e17ba77392785aeea90e9ffd..9e40e8d007404b9f9533c56ad9ebc626c9870116 100644 (file)
@@ -59,7 +59,3 @@ obj-$(CONFIG_SAMSUNG_WAKEMASK)        += wakeup-mask.o
 
 obj-$(CONFIG_S5P_PM)           += s5p-pm.o s5p-irq-pm.o
 obj-$(CONFIG_S5P_SLEEP)                += s5p-sleep.o
-
-# PWM support
-
-obj-$(CONFIG_HAVE_PWM)         += pwm.o
index 2d30c7f6edd32ddd5b93e6b8356ae679ce983041..d50f0e486cf2b322b6e8eff1baa7c73272e66c70 100644 (file)
@@ -16,6 +16,7 @@
  */
 #include <asm/thread_info.h>
 #include <asm/vfpmacros.h>
+#include <linux/kern_levels.h>
 #include "../kernel/entry-header.S"
 
        .macro  DBGSTR, str
@@ -24,7 +25,7 @@
        add     r0, pc, #4
        bl      printk
        b       1f
-       .asciz  "<7>VFP: \str\n"
+       .asciz  KERN_DEBUG "VFP: \str\n"
        .balign 4
 1:     ldmfd   sp!, {r0-r3, ip, lr}
 #endif
@@ -37,7 +38,7 @@
        add     r0, pc, #4
        bl      printk
        b       1f
-       .asciz  "<7>VFP: \str\n"
+       .asciz  KERN_DEBUG "VFP: \str\n"
        .balign 4
 1:     ldmfd   sp!, {r0-r3, ip, lr}
 #endif
@@ -52,7 +53,7 @@
        add     r0, pc, #4
        bl      printk
        b       1f
-       .asciz  "<7>VFP: \str\n"
+       .asciz  KERN_DEBUG "VFP: \str\n"
        .balign 4
 1:     ldmfd   sp!, {r0-r3, ip, lr}
 #endif
index 71d38c76726cbb7acfd525dc78889724af31e07f..5ade51c8a87fbf5cd99d319ddbe55feef8fbe6c7 100644 (file)
@@ -12,6 +12,7 @@ config AVR32
        select HARDIRQS_SW_RESEND
        select GENERIC_IRQ_SHOW
        select ARCH_HAVE_CUSTOM_GPIO_H
+       select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select GENERIC_CLOCKEVENTS
        help
index dc5263321480edf35264d7fb0e0ac65da679823f..6c80aba7bf961afe82f42eba5969b5592eba8fec 100644 (file)
@@ -97,7 +97,7 @@ static struct atmel_nand_data atstk1006_nand_data __initdata = {
        .enable_pin     = GPIO_PIN_PB(29),
        .ecc_mode       = NAND_ECC_SOFT,
        .parts          = nand_partitions,
-       .num_parts      = ARRAY_SIZE(num_partitions),
+       .num_parts      = ARRAY_SIZE(nand_partitions),
 };
 #endif
 
index f714544e5560ce2fd0033f63b22480a0eef440d1..1358e366f4be93bff867b9b54cd68d713d2ec3f0 100644 (file)
 /* SMP stuff */
 #define __IGNORE_getcpu
 
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
index f7040a1e399f0acd24a0cd51a17940e5ca73dfc8..b92e60958617eb25ff90481989f494c3625f5a98 100644 (file)
@@ -61,10 +61,10 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
        const struct exception_table_entry *fixup;
        unsigned long address;
        unsigned long page;
-       int writeaccess;
        long signr;
        int code;
        int fault;
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        if (notify_page_fault(regs, ecr))
                return;
@@ -86,6 +86,7 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
 
        local_irq_enable();
 
+retry:
        down_read(&mm->mmap_sem);
 
        vma = find_vma(mm, address);
@@ -104,7 +105,6 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
         */
 good_area:
        code = SEGV_ACCERR;
-       writeaccess = 0;
 
        switch (ecr) {
        case ECR_PROTECTION_X:
@@ -121,7 +121,7 @@ good_area:
        case ECR_TLB_MISS_W:
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
-               writeaccess = 1;
+               flags |= FAULT_FLAG_WRITE;
                break;
        default:
                panic("Unhandled case %lu in do_page_fault!", ecr);
@@ -132,7 +132,11 @@ good_area:
         * sure we exit gracefully rather than endlessly redo the
         * fault.
         */
-       fault = handle_mm_fault(mm, vma, address, writeaccess ? FAULT_FLAG_WRITE : 0);
+       fault = handle_mm_fault(mm, vma, address, flags);
+
+       if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+               return;
+
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
@@ -140,10 +144,23 @@ good_area:
                        goto do_sigbus;
                BUG();
        }
-       if (fault & VM_FAULT_MAJOR)
-               tsk->maj_flt++;
-       else
-               tsk->min_flt++;
+
+       if (flags & FAULT_FLAG_ALLOW_RETRY) {
+               if (fault & VM_FAULT_MAJOR)
+                       tsk->maj_flt++;
+               else
+                       tsk->min_flt++;
+               if (fault & VM_FAULT_RETRY) {
+                       flags &= ~FAULT_FLAG_ALLOW_RETRY;
+
+                       /*
+                        * No need to up_read(&mm->mmap_sem) as we would have
+                        * already released it in __lock_page_or_retry() in
+                        * mm/filemap.c.
+                        */
+                       goto retry;
+               }
+       }
 
        up_read(&mm->mmap_sem);
        return;
index 9b765107e15cf8a17cc4803dfabb1c9ada64b337..f34861920634d15c9de2b1149aa8562a767e64f1 100644 (file)
@@ -33,6 +33,7 @@ config BLACKFIN
        select HAVE_PERF_EVENTS
        select ARCH_HAVE_CUSTOM_GPIO_H
        select ARCH_WANT_OPTIONAL_GPIOLIB
+       select ARCH_WANT_IPC_PARSE_VERSION
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_ATOMIC64
        select GENERIC_IRQ_PROBE
@@ -1002,16 +1003,6 @@ config BFIN_GPTIMERS
          To compile this driver as a module, choose M here: the module
          will be called gptimers.
 
-config HAVE_PWM
-       tristate "Enable PWM API support"
-       depends on BFIN_GPTIMERS
-       help
-         Enable support for the Pulse Width Modulation framework (as
-         found in linux/pwm.h).
-
-         To compile this driver as a module, choose M here: the module
-         will be called pwm.
-
 choice
        prompt "Uncached DMA region"
        default DMA_UNCACHED_1M
index 3287222cba34f12889c464c5b2cb0970542dba61..5b2a0748d7d3e8b215c0d2aba4a3df3319743858 100644 (file)
 #define __IGNORE_getcpu
 
 #ifdef __KERNEL__
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
index 08e6625106be52991b79fceef5422df52f159ec5..735f24e074259b88c8cdd0005cf3ddddcd9175fe 100644 (file)
@@ -21,7 +21,6 @@ obj-$(CONFIG_FUNCTION_TRACER)        += ftrace-entry.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)  += ftrace.o
 CFLAGS_REMOVE_ftrace.o = -pg
 
-obj-$(CONFIG_HAVE_PWM)               += pwm.o
 obj-$(CONFIG_IPIPE)                  += ipipe.o
 obj-$(CONFIG_BFIN_GPTIMERS)          += gptimers.o
 obj-$(CONFIG_CPLB_INFO)              += cplbinfo.o
diff --git a/arch/blackfin/kernel/pwm.c b/arch/blackfin/kernel/pwm.c
deleted file mode 100644 (file)
index 33f5942..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Blackfin Pulse Width Modulation (PWM) core
- *
- * Copyright (c) 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/module.h>
-#include <linux/pwm.h>
-#include <linux/slab.h>
-
-#include <asm/gptimers.h>
-#include <asm/portmux.h>
-
-struct pwm_device {
-       unsigned id;
-       unsigned short pin;
-};
-
-static const unsigned short pwm_to_gptimer_per[] = {
-       P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR4, P_TMR5,
-       P_TMR6, P_TMR7, P_TMR8, P_TMR9, P_TMR10, P_TMR11,
-};
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-       struct pwm_device *pwm;
-       int ret;
-
-       /* XXX: pwm_id really should be unsigned */
-       if (pwm_id < 0)
-               return NULL;
-
-       pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
-       if (!pwm)
-               return pwm;
-
-       pwm->id = pwm_id;
-       if (pwm->id >= ARRAY_SIZE(pwm_to_gptimer_per))
-               goto err;
-
-       pwm->pin = pwm_to_gptimer_per[pwm->id];
-       ret = peripheral_request(pwm->pin, label);
-       if (ret)
-               goto err;
-
-       return pwm;
- err:
-       kfree(pwm);
-       return NULL;
-}
-EXPORT_SYMBOL(pwm_request);
-
-void pwm_free(struct pwm_device *pwm)
-{
-       peripheral_free(pwm->pin);
-       kfree(pwm);
-}
-EXPORT_SYMBOL(pwm_free);
-
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-       unsigned long period, duty;
-       unsigned long long val;
-
-       if (duty_ns < 0 || duty_ns > period_ns)
-               return -EINVAL;
-
-       val = (unsigned long long)get_sclk() * period_ns;
-       do_div(val, NSEC_PER_SEC);
-       period = val;
-
-       val = (unsigned long long)period * duty_ns;
-       do_div(val, period_ns);
-       duty = period - val;
-
-       if (duty >= period)
-               duty = period - 1;
-
-       set_gptimer_config(pwm->id, TIMER_MODE_PWM | TIMER_PERIOD_CNT);
-       set_gptimer_pwidth(pwm->id, duty);
-       set_gptimer_period(pwm->id, period);
-
-       return 0;
-}
-EXPORT_SYMBOL(pwm_config);
-
-int pwm_enable(struct pwm_device *pwm)
-{
-       enable_gptimer(pwm->id);
-       return 0;
-}
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
-{
-       disable_gptimer(pwm->id);
-}
-EXPORT_SYMBOL(pwm_disable);
index bb344650a14f255517487a3a06342992801e8237..e92215428a37e315d0b5df9f962df8e4c8090dcc 100644 (file)
@@ -42,6 +42,7 @@ config CRIS
        select HAVE_IDE
        select GENERIC_ATOMIC64
        select HAVE_GENERIC_HARDIRQS
+       select ARCH_WANT_IPC_PARSE_VERSION
        select GENERIC_IRQ_SHOW
        select GENERIC_IOMAP
        select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32
index f921b8b0f97e6699cca03f3cd90af305dc647508..51873a446f87e870f44db25c3dcfd2d1522eb0d2 100644 (file)
 
 #include <arch/unistd.h>
 
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_OLD_STAT
 #define __ARCH_WANT_STAT64
index a685910d2d5ce562f36f8f4ae02811390600682c..971c0a19facb694706f68722645aa5101afbeea6 100644 (file)
@@ -9,6 +9,7 @@ config FRV
        select GENERIC_IRQ_SHOW
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select GENERIC_CPU_DEVICES
+       select ARCH_WANT_IPC_PARSE_VERSION
 
 config ZONE_DMA
        bool
diff --git a/arch/frv/include/asm/cpumask.h b/arch/frv/include/asm/cpumask.h
deleted file mode 100644 (file)
index d999c20..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_CPUMASK_H
-#define _ASM_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_CPUMASK_H */
index a569dff7cd590f0936fce6a4b5e03e99325b8674..67f23a311db6e3d5a55ef88b3243c7c01705b469 100644 (file)
 
 #define NR_syscalls 338
 
-#define __ARCH_WANT_IPC_PARSE_VERSION
 /* #define __ARCH_WANT_OLD_READDIR */
 #define __ARCH_WANT_OLD_STAT
 #define __ARCH_WANT_STAT64
index 4531c830d20b708b6dce2ce6bf736dabdf14c4de..f0e52943f9238b17b075d6049f313be4365170c2 100644 (file)
  */
 
 #include <linux/linkage.h>
+#include <linux/kern_levels.h>
 #include <asm/unistd.h>
 
 #define CLONE_VM       0x00000100      /* set if VM shared between processes */
-#define        KERN_ERR        "<3>"
 
        .section .rodata
 kernel_thread_emsg:
index 56e890df5053605a8eb7a66514eb096d0e110b2d..5e8a0d9a09ce0035e424dc0334370607f306deb9 100644 (file)
@@ -3,6 +3,7 @@ config H8300
        default y
        select HAVE_IDE
        select HAVE_GENERIC_HARDIRQS
+       select ARCH_WANT_IPC_PARSE_VERSION
        select GENERIC_IRQ_SHOW
        select GENERIC_CPU_DEVICES
 
index 718511303b4e15d3ddbfbeb7b6c48c1b3a48f0bb..5cd882801d7980ae47455febe80b30a8cd4b27b0 100644 (file)
 
 #define NR_syscalls 321
 
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_OLD_STAT
 #define __ARCH_WANT_STAT64
index 9aa17f1917eaebd9612e2f09e0b9d59b76426b7d..06906427c0ac238484af385b31386f0f09ff3ad5 100644 (file)
@@ -7,7 +7,6 @@ header-y += user.h
 generic-y += auxvec.h
 generic-y += bug.h
 generic-y += bugs.h
-generic-y += cpumask.h
 generic-y += cputime.h
 generic-y += current.h
 generic-y += device.h
@@ -23,7 +22,6 @@ generic-y += ioctl.h
 generic-y += ioctls.h
 generic-y += iomap.h
 generic-y += ipcbuf.h
-generic-y += ipc.h
 generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
index 8186ec5ea15168a31a1a876b8a7b52ec7c8f4616..310cf5781fad2438a6ab24845724364bed31c7e4 100644 (file)
@@ -126,6 +126,7 @@ config AUDIT_ARCH
 
 menuconfig PARAVIRT_GUEST
        bool "Paravirtualized guest support"
+       depends on BROKEN
        help
          Say Y here to get to see options related to running Linux under
          various hypervisors.  This option alone does not add any kernel code.
@@ -138,8 +139,6 @@ config PARAVIRT
        bool "Enable paravirtualization code"
        depends on PARAVIRT_GUEST
        default y
-       bool
-       default y
        help
          This changes the kernel so it can modify itself when it is run
          under a hypervisor, potentially improving performance significantly
index 7d9116600a3615d90333ddca4f49dff356b510f1..6e6fe1839f5d57206ff5d0bc4f38b2c3a4c98f8c 100644 (file)
@@ -17,8 +17,8 @@
 #include <asm/intrinsics.h>
 
 
-#define ATOMIC_INIT(i)         ((atomic_t) { (i) })
-#define ATOMIC64_INIT(i)       ((atomic64_t) { (i) })
+#define ATOMIC_INIT(i)         { (i) }
+#define ATOMIC64_INIT(i)       { (i) }
 
 #define atomic_read(v)         (*(volatile int *)&(v)->counter)
 #define atomic64_read(v)       (*(volatile long *)&(v)->counter)
index 367d299d99384e1448e9376b1c899af149e0f599..2d1ad4b11a85a9e9e4083c67f9c30ccf921659fa 100644 (file)
@@ -120,7 +120,7 @@ extern void machvec_tlb_migrate_finish (struct mm_struct *);
 # ifdef MACHVEC_PLATFORM_HEADER
 #  include MACHVEC_PLATFORM_HEADER
 # else
-#  define platform_name                ia64_mv.name
+#  define ia64_platform_name   ia64_mv.name
 #  define platform_setup       ia64_mv.setup
 #  define platform_cpu_init    ia64_mv.cpu_init
 #  define platform_irq_init    ia64_mv.irq_init
index 8a0752f40987ebae6cdaf9ccb411bc133de43017..1f7403a2fbee03407f767a6571392b7147793684 100644 (file)
@@ -10,7 +10,7 @@ extern ia64_mv_setup_t dig_setup;
  * platform's machvec structure.  When compiling a non-generic kernel,
  * the macros are used directly.
  */
-#define platform_name          "dig"
+#define ia64_platform_name     "dig"
 #define platform_setup         dig_setup
 
 #endif /* _ASM_IA64_MACHVEC_DIG_h */
index 6ab1de5c45efe74b9e86e542f6b066578e2aa751..44308b4c3f6e4cbe0635038f2bec0fc021d9eaf0 100644 (file)
@@ -11,7 +11,7 @@ extern ia64_mv_dma_init                       pci_iommu_alloc;
  * platform's machvec structure.  When compiling a non-generic kernel,
  * the macros are used directly.
  */
-#define platform_name                          "dig_vtd"
+#define ia64_platform_name                     "dig_vtd"
 #define platform_setup                         dig_setup
 #define platform_dma_init                      pci_iommu_alloc
 
index cf72fc87fdfed8e172235d5a436a03c188148759..e757112793664d3df43ab6faf68605efb4e8bd0c 100644 (file)
@@ -11,7 +11,7 @@ extern ia64_mv_irq_init_t hpsim_irq_init;
  * platform's machvec structure.  When compiling a non-generic kernel,
  * the macros are used directly.
  */
-#define platform_name          "hpsim"
+#define ia64_platform_name     "hpsim"
 #define platform_setup         hpsim_setup
 #define platform_irq_init      hpsim_irq_init
 
index 3bd83d78a412047099be119a2fa1b3094d767f47..c74d3159e9ebcfaa3ae46e79b67d1e5c45046f6c 100644 (file)
@@ -11,7 +11,7 @@ extern ia64_mv_dma_init                       sba_dma_init;
  * platform's machvec structure.  When compiling a non-generic kernel,
  * the macros are used directly.
  */
-#define platform_name                          "hpzx1"
+#define ia64_platform_name                     "hpzx1"
 #define platform_setup                         dig_setup
 #define platform_dma_init                      sba_dma_init
 
index 1091ac39740c6c407c35bb43e8d511eea2aafb02..906ef621077448d3e6a35243078a2da7ca9f4368 100644 (file)
@@ -11,7 +11,7 @@ extern ia64_mv_dma_get_ops                    hwsw_dma_get_ops;
  * platform's machvec structure.  When compiling a non-generic kernel,
  * the macros are used directly.
  */
-#define platform_name                          "hpzx1_swiotlb"
+#define ia64_platform_name                     "hpzx1_swiotlb"
 #define platform_setup                         dig_setup
 #define platform_dma_init                      machvec_noop
 #define platform_dma_get_ops                   hwsw_dma_get_ops
index f061a30aac42c7b297434d0ec88ae0f5d348f5ee..ece9fa85be8864330b783ff37985f58370e68c43 100644 (file)
@@ -71,7 +71,7 @@ extern ia64_mv_pci_fixup_bus_t                sn_pci_fixup_bus;
  * platform's machvec structure.  When compiling a non-generic kernel,
  * the macros are used directly.
  */
-#define platform_name                  "sn2"
+#define ia64_platform_name             "sn2"
 #define platform_setup                 sn_setup
 #define platform_cpu_init              sn_cpu_init
 #define platform_irq_init              sn_irq_init
index 2931447f3813c2cf34c469614923a84b70dfcb22..2c50853f35ac0037297d0860c26ffb5ecb9b88a3 100644 (file)
@@ -20,7 +20,7 @@ extern ia64_mv_setup_t uv_setup;
  * platform's machvec structure.  When compiling a non-generic kernel,
  * the macros are used directly.
  */
-#define platform_name                  "uv"
+#define ia64_platform_name             "uv"
 #define platform_setup                 uv_setup
 
 #endif /* _ASM_IA64_MACHVEC_UV_H */
index 55f9228056cd6ef4138739ceb0812923d64d94c0..8b8bd0eb39236ee3a251068b4ec4e3e9fc3ee7e9 100644 (file)
@@ -13,7 +13,7 @@ extern ia64_mv_send_ipi_t             xen_platform_send_ipi;
  * platform's machvec structure.  When compiling a non-generic kernel,
  * the macros are used directly.
  */
-#define platform_name                          "xen"
+#define ia64_platform_name                     "xen"
 #define platform_setup                         dig_setup
 #define platform_cpu_init                      xen_cpu_init
 #define platform_irq_init                      xen_irq_init
index 832dd3789e9d02c14471730ddfbbf85d60e816da..944152a5091223798fb3427b2dc5bb56ecaef4be 100644 (file)
@@ -719,7 +719,7 @@ enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_FORCE_MWAIT,
 
 void default_idle(void);
 
-#define ia64_platform_is(x) (strcmp(x, platform_name) == 0)
+#define ia64_platform_is(x) (strcmp(x, ia64_platform_name) == 0)
 
 #endif /* !__ASSEMBLY__ */
 
index df5351e3eed7389881b3b9bf7402a3a553552cf8..e7947528aee61967523a6ff95337de2015583167 100644 (file)
@@ -23,6 +23,7 @@ config KVM
        depends on HAVE_KVM && MODULES && EXPERIMENTAL
        # for device assignment:
        depends on PCI
+       depends on BROKEN
        select PREEMPT_NOTIFIERS
        select ANON_INODES
        select HAVE_KVM_IRQCHIP
index f5959c0c1810422358f48498b29e44dcc743b4b5..eab28e314022e7c4456a2860d99eea70c22c8df0 100644 (file)
@@ -30,8 +30,8 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
        struct pci_bus *bus;
        u16 config;
 
-       if ((strcmp(platform_name, "dig") != 0)
-           && (strcmp(platform_name, "hpzx1")  != 0))
+       if ((strcmp(ia64_platform_name, "dig") != 0)
+           && (strcmp(ia64_platform_name, "hpzx1")  != 0))
                return;
        /* Maybe, this machine supports legacy memory map. */
 
index b638d5bfa14d0aa34cc546b179a284f9d3a5cbb6..49498bbb96163ec10477fac83fdd9f21f277b5cc 100644 (file)
@@ -7,6 +7,7 @@ config M32R
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_LZMA
+       select ARCH_WANT_IPC_PARSE_VERSION
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
index 3e1db561aacc0c5923f0f14f455887f421b8bc71..d5e66a480782e0c121da54bceef6e58a57d12337 100644 (file)
 
 #define NR_syscalls 326
 
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
index 1471201282605485d05fe0b0afd024988509d55c..0b0f8b8c4a266571d33fcd61900161d7961d8cea 100644 (file)
@@ -10,6 +10,7 @@ config M68K
        select GENERIC_STRNCPY_FROM_USER if MMU
        select GENERIC_STRNLEN_USER if MMU
        select FPU if MMU
+       select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
 
 config RWSEM_GENERIC_SPINLOCK
index ea0b502f845ebf69843b90c5534ab11b36fcd2b9..045cfd6a9e31b72edd428160deedd47b6078a51a 100644 (file)
 
 #define NR_syscalls            347
 
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_OLD_STAT
 #define __ARCH_WANT_STAT64
index 0bf44231aaf91c023e2f2ac1dfa03c0a34da3a24..ab9afcaa7f6a44bad81bb9d80a9c5775fcf7c4f8 100644 (file)
@@ -15,6 +15,7 @@ config MICROBLAZE
        select TRACING_SUPPORT
        select OF
        select OF_EARLY_FLATTREE
+       select ARCH_WANT_IPC_PARSE_VERSION
        select IRQ_DOMAIN
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
index d20ffbc86bebcc4b319ce1ff52117ae5c029463a..6985e6e9d826a689e6049308e663d06dcfdf070f 100644 (file)
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
-#define __ARCH_WANT_IPC_PARSE_VERSION
 /* #define __ARCH_WANT_OLD_READDIR */
 /* #define __ARCH_WANT_OLD_STAT */
 #define __ARCH_WANT_STAT64
index 5ce8029f558b17a28107d602e7e3d59712262093..d64786d5e2f361763586c0c5b26221c4b83d3121 100644 (file)
@@ -14,6 +14,7 @@ platforms += jz4740
 platforms += lantiq
 platforms += lasat
 platforms += loongson
+platforms += loongson1
 platforms += mipssim
 platforms += mti-malta
 platforms += netlogic
index b3e10fdd389866659212f947971af764b98dcf3f..e3efc06e6409bd425bbd9686b0dc6698b65536a5 100644 (file)
@@ -20,12 +20,14 @@ config MIPS
        select ARCH_BINFMT_ELF_RANDOMIZE_PIE
        select RTC_LIB if !MACH_LOONGSON
        select GENERIC_ATOMIC64 if !64BIT
+       select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select HAVE_DMA_ATTRS
        select HAVE_DMA_API_DEBUG
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
        select HAVE_ARCH_JUMP_LABEL
+       select ARCH_WANT_IPC_PARSE_VERSION
        select IRQ_FORCED_THREADING
        select HAVE_MEMBLOCK
        select HAVE_MEMBLOCK_NODE_MAP
@@ -209,6 +211,7 @@ config MACH_JZ4740
        select SYS_HAS_CPU_MIPS32_R1
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
+       select SYS_SUPPORTS_ZBOOT_UART16550
        select DMA_NONCOHERENT
        select IRQ_CPU
        select GENERIC_GPIO
@@ -264,6 +267,16 @@ config MACH_LOONGSON
          Chinese Academy of Sciences (CAS) in the People's Republic
          of China. The chief architect is Professor Weiwu Hu.
 
+config MACH_LOONGSON1
+       bool "Loongson 1 family of machines"
+       select SYS_SUPPORTS_ZBOOT
+       help
+         This enables support for the Loongson 1 based machines.
+
+         Loongson 1 is a family of 32-bit MIPS-compatible SoCs developed by
+         the ICT (Institute of Computing Technology) and the Chinese Academy
+         of Sciences.
+
 config MIPS_MALTA
        bool "MIPS Malta board"
        select ARCH_MAY_HAVE_PC_FDC
@@ -787,6 +800,8 @@ config NLM_XLR_BOARD
        select ZONE_DMA if 64BIT
        select SYNC_R4K
        select SYS_HAS_EARLY_PRINTK
+       select USB_ARCH_HAS_OHCI if USB_SUPPORT
+       select USB_ARCH_HAS_EHCI if USB_SUPPORT
        help
          Support for systems based on Netlogic XLR and XLS processors.
          Say Y here if you have a XLR or XLS based board.
@@ -799,7 +814,6 @@ config NLM_XLP_BOARD
        select SYS_HAS_CPU_XLP
        select SYS_SUPPORTS_SMP
        select HW_HAS_PCI
-       select SWAP_IO_SPACE
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_64BIT_KERNEL
        select 64BIT_PHYS_ADDR
@@ -836,6 +850,7 @@ source "arch/mips/txx9/Kconfig"
 source "arch/mips/vr41xx/Kconfig"
 source "arch/mips/cavium-octeon/Kconfig"
 source "arch/mips/loongson/Kconfig"
+source "arch/mips/loongson1/Kconfig"
 source "arch/mips/netlogic/Kconfig"
 
 endmenu
@@ -1217,6 +1232,14 @@ config CPU_LOONGSON2F
          have a similar programming interface with FPGA northbridge used in
          Loongson2E.
 
+config CPU_LOONGSON1B
+       bool "Loongson 1B"
+       depends on SYS_HAS_CPU_LOONGSON1B
+       select CPU_LOONGSON1
+       help
+         The Loongson 1B is a 32-bit SoC, which implements the MIPS32
+         release 2 instruction set.
+
 config CPU_MIPS32_R1
        bool "MIPS32 Release 1"
        depends on SYS_HAS_CPU_MIPS32_R1
@@ -1432,6 +1455,8 @@ config CPU_CAVIUM_OCTEON
        select WEAK_ORDERING
        select CPU_SUPPORTS_HIGHMEM
        select CPU_SUPPORTS_HUGEPAGES
+       select LIBFDT
+       select USE_OF
        help
          The Cavium Octeon processor is a highly integrated chip containing
          many ethernet hardware widgets for networking tasks. The processor
@@ -1544,6 +1569,14 @@ config CPU_LOONGSON2
        select CPU_SUPPORTS_64BIT_KERNEL
        select CPU_SUPPORTS_HIGHMEM
 
+config CPU_LOONGSON1
+       bool
+       select CPU_MIPS32
+       select CPU_MIPSR2
+       select CPU_HAS_PREFETCH
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select CPU_SUPPORTS_HIGHMEM
+
 config CPU_BMIPS
        bool
        select CPU_MIPS32
@@ -1562,6 +1595,9 @@ config SYS_HAS_CPU_LOONGSON2F
        select CPU_SUPPORTS_ADDRWINCFG if 64BIT
        select CPU_SUPPORTS_UNCACHED_ACCELERATED
 
+config SYS_HAS_CPU_LOONGSON1B
+       bool
+
 config SYS_HAS_CPU_MIPS32_R1
        bool
 
@@ -2366,6 +2402,8 @@ config PCI_DOMAINS
 
 source "drivers/pci/Kconfig"
 
+source "drivers/pci/pcie/Kconfig"
+
 #
 # ISA support is now enabled via select.  Too many systems still have the one
 # or other ISA chip on the board that users don't know about so don't expect
index 295f1a95f7451e2bdaa7f5e8171c5dd06622fcaf..99969484c475c7fc7366d12fa50efd495656a9b9 100644 (file)
@@ -81,10 +81,10 @@ static void mtx1_power_off(void)
 
 void __init board_setup(void)
 {
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#if IS_ENABLED(CONFIG_USB_OHCI_HCD)
        /* Enable USB power switch */
        alchemy_gpio_direction_output(204, 0);
-#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */
+#endif /* IS_ENABLED(CONFIG_USB_OHCI_HCD) */
 
        /* Initialize sys_pinfunc */
        au_writel(SYS_PF_NI2, SYS_PINFUNC);
index 95cb9113b12c8302ee9ea60e56e86af8c36da067..c0f3ce6dcb56d448bcb2184c5fdc2c61498a8d7c 100644 (file)
@@ -334,13 +334,12 @@ static void __init alchemy_setup_macs(int ctype)
        if (alchemy_get_macs(ctype) < 1)
                return;
 
-       macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
+       macres = kmemdup(au1xxx_eth0_resources[ctype],
+                        sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
        if (!macres) {
                printk(KERN_INFO "Alchemy: no memory for MAC0 resources\n");
                return;
        }
-       memcpy(macres, au1xxx_eth0_resources[ctype],
-              sizeof(struct resource) * MAC_RES_COUNT);
        au1xxx_eth0_device.resource = macres;
 
        i = prom_get_ethernet_addr(ethaddr);
@@ -356,13 +355,12 @@ static void __init alchemy_setup_macs(int ctype)
        if (alchemy_get_macs(ctype) < 2)
                return;
 
-       macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
+       macres = kmemdup(au1xxx_eth1_resources[ctype],
+                        sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
        if (!macres) {
                printk(KERN_INFO "Alchemy: no memory for MAC1 resources\n");
                return;
        }
-       memcpy(macres, au1xxx_eth1_resources[ctype],
-              sizeof(struct resource) * MAC_RES_COUNT);
        au1xxx_eth1_device.resource = macres;
 
        ethaddr[5] += 1;        /* next addr for 2nd MAC */
index 3c37fb3033640e05eb39fa21496a938634e2c38c..c9e747dd9fc229d3ee1e29a4a8f232c576ed79bb 100644 (file)
@@ -2,7 +2,7 @@
 # Alchemy Develboards
 #
 
-obj-y += prom.o bcsr.o platform.o
+obj-y += bcsr.o platform.o
 obj-$(CONFIG_PM)               += pm.o
 obj-$(CONFIG_MIPS_PB1100)      += pb1100.o
 obj-$(CONFIG_MIPS_PB1500)      += pb1500.o
index 1e83ce2e1147fb4e71bc893630849ee147530198..f2039ef2c293615470481733747b7e198d797d75 100644 (file)
@@ -90,10 +90,7 @@ static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d)
        unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT);
 
        disable_irq_nosync(irq);
-
-       for ( ; bisr; bisr &= bisr - 1)
-               generic_handle_irq(bcsr_csc_base + __ffs(bisr));
-
+       generic_handle_irq(bcsr_csc_base + __ffs(bisr));
        enable_irq(irq);
 }
 
index cff50d05ddd4136e954917509ffdbedfb6e444c6..78c77a44a31782e3752e0a00a3f95eedb2722124 100644 (file)
@@ -46,7 +46,7 @@ void __init board_setup(void)
        alchemy_gpio1_input_enable();
        udelay(100);
 
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#if IS_ENABLED(CONFIG_USB_OHCI_HCD)
        {
                u32 pin_func, sys_freqctrl, sys_clksrc;
 
@@ -93,7 +93,7 @@ void __init board_setup(void)
                pin_func |= SYS_PF_USB;
                au_writel(pin_func, SYS_PINFUNC);
        }
-#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */
+#endif /* IS_ENABLED(CONFIG_USB_OHCI_HCD) */
 
        /* Enable sys bus clock divider when IDLE state or no bus activity. */
        au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL);
index e7b807b3ec51b9ecbdb850349e0646aa14193744..232fee9420000fcc3f57bbd9eea28eb27b69be74 100644 (file)
@@ -53,7 +53,7 @@ void __init board_setup(void)
        alchemy_gpio_direction_input(201);
        alchemy_gpio_direction_input(203);
 
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+#if IS_ENABLED(CONFIG_USB_OHCI_HCD)
 
        /* Zero and disable FREQ2 */
        sys_freqctrl = au_readl(SYS_FREQCTRL0);
@@ -87,7 +87,7 @@ void __init board_setup(void)
        /* 2nd USB port is USB host */
        pin_func |= SYS_PF_USB;
        au_writel(pin_func, SYS_PINFUNC);
-#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */
+#endif /* IS_ENABLED(CONFIG_USB_OHCI_HCD) */
 
 #ifdef CONFIG_PCI
        {
index 621f70afb63a10189751b8123a6ed04b1e5c78c9..f39042e99d0d45626305a34135e4d8d0f9c01ac4 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 
+#include <asm/bootinfo.h>
 #include <asm/reboot.h>
+#include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-db1x00/bcsr.h>
 
+#include <prom.h>
+
+void __init prom_init(void)
+{
+       unsigned char *memsize_str;
+       unsigned long memsize;
+
+       prom_argc = (int)fw_arg0;
+       prom_argv = (char **)fw_arg1;
+       prom_envp = (char **)fw_arg2;
+
+       prom_init_cmdline();
+       memsize_str = prom_getenv("memsize");
+       if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
+               memsize = 64 << 20; /* all devboards have at least 64MB RAM */
+
+       add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
+void prom_putchar(unsigned char c)
+{
+#ifdef CONFIG_MIPS_DB1300
+       alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c);
+#else
+       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
+#endif
+}
+
 
 static struct platform_device db1x00_rtc_dev = {
        .name   = "rtc-au1xxx",
diff --git a/arch/mips/alchemy/devboards/prom.c b/arch/mips/alchemy/devboards/prom.c
deleted file mode 100644 (file)
index 93a2210..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Common code used by all Alchemy develboards.
- *
- * Extracted from files which had this to say:
- *
- * Copyright 2000, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/bootinfo.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <prom.h>
-
-#if defined(CONFIG_MIPS_DB1000) || \
-    defined(CONFIG_MIPS_PB1100) || \
-    defined(CONFIG_MIPS_PB1500)
-#define ALCHEMY_BOARD_DEFAULT_MEMSIZE  0x04000000
-
-#else  /* Au1550/Au1200-based develboards */
-#define ALCHEMY_BOARD_DEFAULT_MEMSIZE  0x08000000
-#endif
-
-void __init prom_init(void)
-{
-       unsigned char *memsize_str;
-       unsigned long memsize;
-
-       prom_argc = (int)fw_arg0;
-       prom_argv = (char **)fw_arg1;
-       prom_envp = (char **)fw_arg2;
-
-       prom_init_cmdline();
-       memsize_str = prom_getenv("memsize");
-       if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize))
-               memsize = ALCHEMY_BOARD_DEFAULT_MEMSIZE;
-
-       add_memory_region(0, memsize, BOOT_MEM_RAM);
-}
-
-void prom_putchar(unsigned char c)
-{
-#ifdef CONFIG_MIPS_DB1300
-       alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c);
-#else
-       alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
-#endif
-}
index 6b1b9ad8d857d01df1254657635c641a53a09148..d03e8799d1cf8c09455c60e0029f5371cf67de7c 100644 (file)
@@ -1,6 +1,10 @@
 menu "CPU support"
        depends on BCM63XX
 
+config BCM63XX_CPU_6328
+       bool "support 6328 CPU"
+       select HW_HAS_PCI
+
 config BCM63XX_CPU_6338
        bool "support 6338 CPU"
        select HW_HAS_PCI
index 6dfdc69928accdfc1d062cf9315b04f8bc28a9c2..833af72c852abdbc806362f364026a99a453a4f6 100644 (file)
@@ -1,5 +1,6 @@
 obj-y          += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \
-                  dev-dsp.o dev-enet.o dev-pcmcia.o dev-uart.o dev-wdt.o
+                  dev-dsp.o dev-enet.o dev-flash.o dev-pcmcia.o dev-rng.o \
+                  dev-spi.o dev-uart.o dev-wdt.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
 
 obj-y          += boards/
index 2f1773f3fb7a5594872ddc8b604be143f3127a38..feb05258a4d1519368a0e7f2395415a4a87e84b1 100644 (file)
@@ -11,9 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
 #include <linux/ssb/ssb.h>
 #include <asm/addrspace.h>
 #include <bcm63xx_board.h>
@@ -24,7 +21,9 @@
 #include <bcm63xx_dev_pci.h>
 #include <bcm63xx_dev_enet.h>
 #include <bcm63xx_dev_dsp.h>
+#include <bcm63xx_dev_flash.h>
 #include <bcm63xx_dev_pcmcia.h>
+#include <bcm63xx_dev_spi.h>
 #include <board_bcm963xx.h>
 
 #define PFX    "board_bcm963xx: "
@@ -33,6 +32,48 @@ static struct bcm963xx_nvram nvram;
 static unsigned int mac_addr_used;
 static struct board_info board;
 
+/*
+ * known 6328 boards
+ */
+#ifdef CONFIG_BCM63XX_CPU_6328
+static struct board_info __initdata board_96328avng = {
+       .name                           = "96328avng",
+       .expected_cpu_id                = 0x6328,
+
+       .has_uart0                      = 1,
+       .has_pci                        = 1,
+
+       .leds = {
+               {
+                       .name           = "96328avng::ppp-fail",
+                       .gpio           = 2,
+                       .active_low     = 1,
+               },
+               {
+                       .name           = "96328avng::power",
+                       .gpio           = 4,
+                       .active_low     = 1,
+                       .default_trigger = "default-on",
+               },
+               {
+                       .name           = "96328avng::power-fail",
+                       .gpio           = 8,
+                       .active_low     = 1,
+               },
+               {
+                       .name           = "96328avng::wps",
+                       .gpio           = 9,
+                       .active_low     = 1,
+               },
+               {
+                       .name           = "96328avng::ppp",
+                       .gpio           = 11,
+                       .active_low     = 1,
+               },
+       },
+};
+#endif
+
 /*
  * known 6338 boards
  */
@@ -592,6 +633,9 @@ static struct board_info __initdata board_DWVS0 = {
  * all boards
  */
 static const struct board_info __initdata *bcm963xx_boards[] = {
+#ifdef CONFIG_BCM63XX_CPU_6328
+       &board_96328avng,
+#endif
 #ifdef CONFIG_BCM63XX_CPU_6338
        &board_96338gw,
        &board_96338w,
@@ -709,9 +753,15 @@ void __init board_prom_init(void)
        char cfe_version[32];
        u32 val;
 
-       /* read base address of boot chip select (0) */
-       val = bcm_mpi_readl(MPI_CSBASE_REG(0));
-       val &= MPI_CSBASE_BASE_MASK;
+       /* read base address of boot chip select (0)
+        * 6328 does not have MPI but boots from a fixed address
+        */
+       if (BCMCPU_IS_6328())
+               val = 0x18000000;
+       else {
+               val = bcm_mpi_readl(MPI_CSBASE_REG(0));
+               val &= MPI_CSBASE_BASE_MASK;
+       }
        boot_addr = (u8 *)KSEG1ADDR(val);
 
        /* dump cfe version */
@@ -808,40 +858,6 @@ void __init board_setup(void)
                panic("unexpected CPU for bcm963xx board");
 }
 
-static struct mtd_partition mtd_partitions[] = {
-       {
-               .name           = "cfe",
-               .offset         = 0x0,
-               .size           = 0x40000,
-       }
-};
-
-static const char *bcm63xx_part_types[] = { "bcm63xxpart", NULL };
-
-static struct physmap_flash_data flash_data = {
-       .width                  = 2,
-       .nr_parts               = ARRAY_SIZE(mtd_partitions),
-       .parts                  = mtd_partitions,
-       .part_probe_types       = bcm63xx_part_types,
-};
-
-static struct resource mtd_resources[] = {
-       {
-               .start          = 0,    /* filled at runtime */
-               .end            = 0,    /* filled at runtime */
-               .flags          = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device mtd_dev = {
-       .name                   = "physmap-flash",
-       .resource               = mtd_resources,
-       .num_resources          = ARRAY_SIZE(mtd_resources),
-       .dev                    = {
-               .platform_data  = &flash_data,
-       },
-};
-
 static struct gpio_led_platform_data bcm63xx_led_data;
 
 static struct platform_device bcm63xx_gpio_leds = {
@@ -855,8 +871,6 @@ static struct platform_device bcm63xx_gpio_leds = {
  */
 int __init board_register_devices(void)
 {
-       u32 val;
-
        if (board.has_uart0)
                bcm63xx_uart_register(0);
 
@@ -890,14 +904,9 @@ int __init board_register_devices(void)
        }
 #endif
 
-       /* read base address of boot chip select (0) */
-       val = bcm_mpi_readl(MPI_CSBASE_REG(0));
-       val &= MPI_CSBASE_BASE_MASK;
-
-       mtd_resources[0].start = val;
-       mtd_resources[0].end = 0x1FFFFFFF;
+       bcm63xx_spi_register();
 
-       platform_device_register(&mtd_dev);
+       bcm63xx_flash_register();
 
        bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds);
        bcm63xx_led_data.leds = board.leds;
index 9d57c71b7b582cc9c24f664df6ae156bc9752522..1db48adb543afbc4dfa6c73e023bee83aa5d595f 100644 (file)
@@ -120,7 +120,7 @@ static void enetsw_set(struct clk *clk, int enable)
 {
        if (!BCMCPU_IS_6368())
                return;
-       bcm_hwclock_set(CKCTL_6368_ROBOSW_CLK_EN |
+       bcm_hwclock_set(CKCTL_6368_ROBOSW_EN |
                        CKCTL_6368_SWPKT_USB_EN |
                        CKCTL_6368_SWPKT_SAR_EN, enable);
        if (enable) {
@@ -163,7 +163,7 @@ static void usbh_set(struct clk *clk, int enable)
        if (BCMCPU_IS_6348())
                bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
        else if (BCMCPU_IS_6368())
-               bcm_hwclock_set(CKCTL_6368_USBH_CLK_EN, enable);
+               bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
 }
 
 static struct clk clk_usbh = {
@@ -181,9 +181,11 @@ static void spi_set(struct clk *clk, int enable)
                mask = CKCTL_6338_SPI_EN;
        else if (BCMCPU_IS_6348())
                mask = CKCTL_6348_SPI_EN;
-       else
-               /* BCMCPU_IS_6358 */
+       else if (BCMCPU_IS_6358())
                mask = CKCTL_6358_SPI_EN;
+       else
+               /* BCMCPU_IS_6368 */
+               mask = CKCTL_6368_SPI_EN;
        bcm_hwclock_set(mask, enable);
 }
 
@@ -199,7 +201,7 @@ static void xtm_set(struct clk *clk, int enable)
        if (!BCMCPU_IS_6368())
                return;
 
-       bcm_hwclock_set(CKCTL_6368_SAR_CLK_EN |
+       bcm_hwclock_set(CKCTL_6368_SAR_EN |
                        CKCTL_6368_SWPKT_SAR_EN, enable);
 
        if (enable) {
@@ -221,6 +223,18 @@ static struct clk clk_xtm = {
        .set    = xtm_set,
 };
 
+/*
+ * IPsec clock
+ */
+static void ipsec_set(struct clk *clk, int enable)
+{
+       bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable);
+}
+
+static struct clk clk_ipsec = {
+       .set    = ipsec_set,
+};
+
 /*
  * Internal peripheral clock
  */
@@ -278,6 +292,8 @@ struct clk *clk_get(struct device *dev, const char *id)
                return &clk_periph;
        if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
                return &clk_pcm;
+       if (BCMCPU_IS_6368() && !strcmp(id, "ipsec"))
+               return &clk_ipsec;
        return ERR_PTR(-ENOENT);
 }
 
index 8f0d6c7725ea278eecf0fedca355fb5e33c7e824..a7afb289b15aa03f93d6665ad55969ba97cfe6a5 100644 (file)
@@ -29,6 +29,14 @@ static u16 bcm63xx_cpu_rev;
 static unsigned int bcm63xx_cpu_freq;
 static unsigned int bcm63xx_memory_size;
 
+static const unsigned long bcm6328_regs_base[] = {
+       __GEN_CPU_REGS_TABLE(6328)
+};
+
+static const int bcm6328_irqs[] = {
+       __GEN_CPU_IRQ_TABLE(6328)
+};
+
 static const unsigned long bcm6338_regs_base[] = {
        __GEN_CPU_REGS_TABLE(6338)
 };
@@ -99,6 +107,33 @@ unsigned int bcm63xx_get_memory_size(void)
 static unsigned int detect_cpu_clock(void)
 {
        switch (bcm63xx_get_cpu_id()) {
+       case BCM6328_CPU_ID:
+       {
+               unsigned int tmp, mips_pll_fcvo;
+
+               tmp = bcm_misc_readl(MISC_STRAPBUS_6328_REG);
+               mips_pll_fcvo = (tmp & STRAPBUS_6328_FCVO_MASK)
+                               >> STRAPBUS_6328_FCVO_SHIFT;
+
+               switch (mips_pll_fcvo) {
+               case 0x12:
+               case 0x14:
+               case 0x19:
+                       return 160000000;
+               case 0x1c:
+                       return 192000000;
+               case 0x13:
+               case 0x15:
+                       return 200000000;
+               case 0x1a:
+                       return 384000000;
+               case 0x16:
+                       return 400000000;
+               default:
+                       return 320000000;
+               }
+
+       }
        case BCM6338_CPU_ID:
                /* BCM6338 has a fixed 240 Mhz frequency */
                return 240000000;
@@ -170,6 +205,9 @@ static unsigned int detect_memory_size(void)
        unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0;
        u32 val;
 
+       if (BCMCPU_IS_6328())
+               return bcm_ddr_readl(DDR_CSEND_REG) << 24;
+
        if (BCMCPU_IS_6345()) {
                val = bcm_sdram_readl(SDRAM_MBASE_REG);
                return (val * 8 * 1024 * 1024);
@@ -228,17 +266,26 @@ void __init bcm63xx_cpu_init(void)
                bcm63xx_irqs = bcm6345_irqs;
                break;
        case CPU_BMIPS4350:
-               switch (read_c0_prid() & 0xf0) {
-               case 0x10:
+               if ((read_c0_prid() & 0xf0) == 0x10) {
                        expected_cpu_id = BCM6358_CPU_ID;
                        bcm63xx_regs_base = bcm6358_regs_base;
                        bcm63xx_irqs = bcm6358_irqs;
-                       break;
-               case 0x30:
-                       expected_cpu_id = BCM6368_CPU_ID;
-                       bcm63xx_regs_base = bcm6368_regs_base;
-                       bcm63xx_irqs = bcm6368_irqs;
-                       break;
+               } else {
+                       /* all newer chips have the same chip id location */
+                       u16 chip_id = bcm_readw(BCM_6368_PERF_BASE);
+
+                       switch (chip_id) {
+                       case BCM6328_CPU_ID:
+                               expected_cpu_id = BCM6328_CPU_ID;
+                               bcm63xx_regs_base = bcm6328_regs_base;
+                               bcm63xx_irqs = bcm6328_irqs;
+                               break;
+                       case BCM6368_CPU_ID:
+                               expected_cpu_id = BCM6368_CPU_ID;
+                               bcm63xx_regs_base = bcm6368_regs_base;
+                               bcm63xx_irqs = bcm6368_irqs;
+                               break;
+                       }
                }
                break;
        }
index da46d1d3c77cf7e1fc5888e0a2d39e9ce7f24eed..5bb5b154c9bd3cb4aec195f3c1e991b6011d8e96 100644 (file)
@@ -31,7 +31,7 @@ static struct resource voip_dsp_resources[] = {
 
 static struct platform_device bcm63xx_voip_dsp_device = {
        .name           = "bcm63xx-voip-dsp",
-       .id             = 0,
+       .id             = -1,
        .num_resources  = ARRAY_SIZE(voip_dsp_resources),
        .resource       = voip_dsp_resources,
 };
diff --git a/arch/mips/bcm63xx/dev-flash.c b/arch/mips/bcm63xx/dev-flash.c
new file mode 100644 (file)
index 0000000..58371c7
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Broadcom BCM63xx flash registration
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
+ * Copyright (C) 2012 Jonas Gorski <jonas.gorski@gmail.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+
+#include <bcm63xx_cpu.h>
+#include <bcm63xx_dev_flash.h>
+#include <bcm63xx_regs.h>
+#include <bcm63xx_io.h>
+
+static struct mtd_partition mtd_partitions[] = {
+       {
+               .name           = "cfe",
+               .offset         = 0x0,
+               .size           = 0x40000,
+       }
+};
+
+static const char *bcm63xx_part_types[] = { "bcm63xxpart", NULL };
+
+static struct physmap_flash_data flash_data = {
+       .width                  = 2,
+       .parts                  = mtd_partitions,
+       .part_probe_types       = bcm63xx_part_types,
+};
+
+static struct resource mtd_resources[] = {
+       {
+               .start          = 0,    /* filled at runtime */
+               .end            = 0,    /* filled at runtime */
+               .flags          = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device mtd_dev = {
+       .name                   = "physmap-flash",
+       .resource               = mtd_resources,
+       .num_resources          = ARRAY_SIZE(mtd_resources),
+       .dev                    = {
+               .platform_data  = &flash_data,
+       },
+};
+
+static int __init bcm63xx_detect_flash_type(void)
+{
+       u32 val;
+
+       switch (bcm63xx_get_cpu_id()) {
+       case BCM6328_CPU_ID:
+               val = bcm_misc_readl(MISC_STRAPBUS_6328_REG);
+               if (val & STRAPBUS_6328_BOOT_SEL_SERIAL)
+                       return BCM63XX_FLASH_TYPE_SERIAL;
+               else
+                       return BCM63XX_FLASH_TYPE_NAND;
+       case BCM6338_CPU_ID:
+       case BCM6345_CPU_ID:
+       case BCM6348_CPU_ID:
+               /* no way to auto detect so assume parallel */
+               return BCM63XX_FLASH_TYPE_PARALLEL;
+       case BCM6358_CPU_ID:
+               val = bcm_gpio_readl(GPIO_STRAPBUS_REG);
+               if (val & STRAPBUS_6358_BOOT_SEL_PARALLEL)
+                       return BCM63XX_FLASH_TYPE_PARALLEL;
+               else
+                       return BCM63XX_FLASH_TYPE_SERIAL;
+       case BCM6368_CPU_ID:
+               val = bcm_gpio_readl(GPIO_STRAPBUS_REG);
+               switch (val & STRAPBUS_6368_BOOT_SEL_MASK) {
+               case STRAPBUS_6368_BOOT_SEL_NAND:
+                       return BCM63XX_FLASH_TYPE_NAND;
+               case STRAPBUS_6368_BOOT_SEL_SERIAL:
+                       return BCM63XX_FLASH_TYPE_SERIAL;
+               case STRAPBUS_6368_BOOT_SEL_PARALLEL:
+                       return BCM63XX_FLASH_TYPE_PARALLEL;
+               }
+       default:
+               return -EINVAL;
+       }
+}
+
+int __init bcm63xx_flash_register(void)
+{
+       int flash_type;
+       u32 val;
+
+       flash_type = bcm63xx_detect_flash_type();
+
+       switch (flash_type) {
+       case BCM63XX_FLASH_TYPE_PARALLEL:
+               /* read base address of boot chip select (0) */
+               val = bcm_mpi_readl(MPI_CSBASE_REG(0));
+               val &= MPI_CSBASE_BASE_MASK;
+
+               mtd_resources[0].start = val;
+               mtd_resources[0].end = 0x1FFFFFFF;
+
+               return platform_device_register(&mtd_dev);
+       case BCM63XX_FLASH_TYPE_SERIAL:
+               pr_warn("unsupported serial flash detected\n");
+               return -ENODEV;
+       case BCM63XX_FLASH_TYPE_NAND:
+               pr_warn("unsupported NAND flash detected\n");
+               return -ENODEV;
+       default:
+               pr_err("flash detection failed for BCM%x: %d\n",
+                      bcm63xx_get_cpu_id(), flash_type);
+               return -ENODEV;
+       }
+}
diff --git a/arch/mips/bcm63xx/dev-rng.c b/arch/mips/bcm63xx/dev-rng.c
new file mode 100644 (file)
index 0000000..d277b4d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011 Florian Fainelli <florian@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <bcm63xx_cpu.h>
+
+static struct resource rng_resources[] = {
+       {
+               .start          = -1, /* filled at runtime */
+               .end            = -1, /* filled at runtime */
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device bcm63xx_rng_device = {
+       .name           = "bcm63xx-rng",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(rng_resources),
+       .resource       = rng_resources,
+};
+
+int __init bcm63xx_rng_register(void)
+{
+       if (!BCMCPU_IS_6368())
+               return -ENODEV;
+
+       rng_resources[0].start = bcm63xx_regset_address(RSET_RNG);
+       rng_resources[0].end = rng_resources[0].start;
+       rng_resources[0].end += RSET_RNG_SIZE - 1;
+
+       return platform_device_register(&bcm63xx_rng_device);
+}
+arch_initcall(bcm63xx_rng_register);
diff --git a/arch/mips/bcm63xx/dev-spi.c b/arch/mips/bcm63xx/dev-spi.c
new file mode 100644 (file)
index 0000000..e39f730
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009-2011 Florian Fainelli <florian@openwrt.org>
+ * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <bcm63xx_cpu.h>
+#include <bcm63xx_dev_spi.h>
+#include <bcm63xx_regs.h>
+
+#ifdef BCMCPU_RUNTIME_DETECT
+/*
+ * register offsets
+ */
+static const unsigned long bcm6338_regs_spi[] = {
+       __GEN_SPI_REGS_TABLE(6338)
+};
+
+static const unsigned long bcm6348_regs_spi[] = {
+       __GEN_SPI_REGS_TABLE(6348)
+};
+
+static const unsigned long bcm6358_regs_spi[] = {
+       __GEN_SPI_REGS_TABLE(6358)
+};
+
+static const unsigned long bcm6368_regs_spi[] = {
+       __GEN_SPI_REGS_TABLE(6368)
+};
+
+const unsigned long *bcm63xx_regs_spi;
+EXPORT_SYMBOL(bcm63xx_regs_spi);
+
+static __init void bcm63xx_spi_regs_init(void)
+{
+       if (BCMCPU_IS_6338())
+               bcm63xx_regs_spi = bcm6338_regs_spi;
+       if (BCMCPU_IS_6348())
+               bcm63xx_regs_spi = bcm6348_regs_spi;
+       if (BCMCPU_IS_6358())
+               bcm63xx_regs_spi = bcm6358_regs_spi;
+       if (BCMCPU_IS_6368())
+               bcm63xx_regs_spi = bcm6368_regs_spi;
+}
+#else
+static __init void bcm63xx_spi_regs_init(void) { }
+#endif
+
+static struct resource spi_resources[] = {
+       {
+               .start          = -1, /* filled at runtime */
+               .end            = -1, /* filled at runtime */
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = -1, /* filled at runtime */
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct bcm63xx_spi_pdata spi_pdata = {
+       .bus_num                = 0,
+       .num_chipselect         = 8,
+};
+
+static struct platform_device bcm63xx_spi_device = {
+       .name           = "bcm63xx-spi",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(spi_resources),
+       .resource       = spi_resources,
+       .dev            = {
+               .platform_data = &spi_pdata,
+       },
+};
+
+int __init bcm63xx_spi_register(void)
+{
+       struct clk *periph_clk;
+
+       if (BCMCPU_IS_6328() || BCMCPU_IS_6345())
+               return -ENODEV;
+
+       periph_clk = clk_get(NULL, "periph");
+       if (IS_ERR(periph_clk)) {
+               pr_err("unable to get periph clock\n");
+               return -ENODEV;
+       }
+
+       /* Set bus frequency */
+       spi_pdata.speed_hz = clk_get_rate(periph_clk);
+
+       spi_resources[0].start = bcm63xx_regset_address(RSET_SPI);
+       spi_resources[0].end = spi_resources[0].start;
+       spi_resources[1].start = bcm63xx_get_irq_number(IRQ_SPI);
+
+       if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) {
+               spi_resources[0].end += BCM_6338_RSET_SPI_SIZE - 1;
+               spi_pdata.fifo_size = SPI_6338_MSG_DATA_SIZE;
+       }
+
+       if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) {
+               spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1;
+               spi_pdata.fifo_size = SPI_6358_MSG_DATA_SIZE;
+       }
+
+       bcm63xx_spi_regs_init();
+
+       return platform_device_register(&bcm63xx_spi_device);
+}
index 3e6c716a4c11b890df34168251c5a611ff56a9af..2a2346a99bcb16d7250dc1c332a3ac339546ccc5 100644 (file)
@@ -21,7 +21,7 @@ static struct resource wdt_resources[] = {
 
 static struct platform_device bcm63xx_wdt_device = {
        .name           = "bcm63xx-wdt",
-       .id             = 0,
+       .id             = -1,
        .num_resources  = ARRAY_SIZE(wdt_resources),
        .resource       = wdt_resources,
 };
index 9a216a451d92fd74228d697ac19ca949a9d11469..18e051ad18a5a4e4f443ac9668045f835d140f8a 100644 (file)
@@ -27,6 +27,17 @@ static void __internal_irq_unmask_32(unsigned int irq) __maybe_unused;
 static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused;
 
 #ifndef BCMCPU_RUNTIME_DETECT
+#ifdef CONFIG_BCM63XX_CPU_6328
+#define irq_stat_reg           PERF_IRQSTAT_6328_REG
+#define irq_mask_reg           PERF_IRQMASK_6328_REG
+#define irq_bits               64
+#define is_ext_irq_cascaded    1
+#define ext_irq_start          (BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE)
+#define ext_irq_end            (BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE)
+#define ext_irq_count          4
+#define ext_irq_cfg_reg1       PERF_EXTIRQ_CFG_REG_6328
+#define ext_irq_cfg_reg2       0
+#endif
 #ifdef CONFIG_BCM63XX_CPU_6338
 #define irq_stat_reg           PERF_IRQSTAT_6338_REG
 #define irq_mask_reg           PERF_IRQMASK_6338_REG
@@ -118,6 +129,16 @@ static void bcm63xx_init_irq(void)
        irq_mask_addr = bcm63xx_regset_address(RSET_PERF);
 
        switch (bcm63xx_get_cpu_id()) {
+       case BCM6328_CPU_ID:
+               irq_stat_addr += PERF_IRQSTAT_6328_REG;
+               irq_mask_addr += PERF_IRQMASK_6328_REG;
+               irq_bits = 64;
+               ext_irq_count = 4;
+               is_ext_irq_cascaded = 1;
+               ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+               ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE;
+               ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328;
+               break;
        case BCM6338_CPU_ID:
                irq_stat_addr += PERF_IRQSTAT_6338_REG;
                irq_mask_addr += PERF_IRQMASK_6338_REG;
index 99d7f405cbebf953c2646a842f1221bc7fe58d18..10eaff4580710d4eae4879691502c55ebef3f1d6 100644 (file)
@@ -26,7 +26,9 @@ void __init prom_init(void)
        bcm_wdt_writel(WDT_STOP_2, WDT_CTL_REG);
 
        /* disable all hardware blocks clock for now */
-       if (BCMCPU_IS_6338())
+       if (BCMCPU_IS_6328())
+               mask = CKCTL_6328_ALL_SAFE_EN;
+       else if (BCMCPU_IS_6338())
                mask = CKCTL_6338_ALL_SAFE_EN;
        else if (BCMCPU_IS_6345())
                mask = CKCTL_6345_ALL_SAFE_EN;
index 356b05583e14ca97d7ee9a1968950c41827b1c8f..0e74a13639cd235b47fcbb8070ecab9b01782e2b 100644 (file)
@@ -68,6 +68,9 @@ void bcm63xx_machine_reboot(void)
 
        /* mask and clear all external irq */
        switch (bcm63xx_get_cpu_id()) {
+       case BCM6328_CPU_ID:
+               perf_regs[0] = PERF_EXTIRQ_CFG_REG_6328;
+               break;
        case BCM6338_CPU_ID:
                perf_regs[0] = PERF_EXTIRQ_CFG_REG_6338;
                break;
@@ -95,9 +98,13 @@ void bcm63xx_machine_reboot(void)
                bcm6348_a1_reboot();
 
        printk(KERN_INFO "triggering watchdog soft-reset...\n");
-       reg = bcm_perf_readl(PERF_SYS_PLL_CTL_REG);
-       reg |= SYS_PLL_SOFT_RESET;
-       bcm_perf_writel(reg, PERF_SYS_PLL_CTL_REG);
+       if (BCMCPU_IS_6328()) {
+               bcm_wdt_writel(1, WDT_SOFTRESET_REG);
+       } else {
+               reg = bcm_perf_readl(PERF_SYS_PLL_CTL_REG);
+               reg |= SYS_PLL_SOFT_RESET;
+               bcm_perf_writel(reg, PERF_SYS_PLL_CTL_REG);
+       }
        while (1)
                ;
 }
index 5042d51b0512a087b02b85853aad2d2b38d9d7d6..c2a3fb0ffc873b971c8461257d5e422b91c832e6 100644 (file)
@@ -58,8 +58,12 @@ $(obj)/piggy.o: $(obj)/dummy.o $(obj)/vmlinux.bin.z FORCE
 # Calculate the load address of the compressed kernel image
 hostprogs-y := calc_vmlinuz_load_addr
 
+ifeq ($(CONFIG_MACH_JZ4740),y)
+VMLINUZ_LOAD_ADDRESS := 0x80600000
+else
 VMLINUZ_LOAD_ADDRESS = $(shell $(obj)/calc_vmlinuz_load_addr \
                $(obj)/vmlinux.bin $(VMLINUX_LOAD_ADDRESS))
+endif
 
 vmlinuzobjs-y += $(obj)/piggy.o
 
index c9caaf4fbf60ecb0c4bdedeb2c04647e162ff635..1c7b739b6a1dfcc9383e403307fbca269f3d43a6 100644 (file)
 #define PORT(offset) (CKSEG1ADDR(AR7_REGS_UART0) + (4 * offset))
 #endif
 
+#ifdef CONFIG_MACH_JZ4740
+#define UART0_BASE  0xB0030000
+#define PORT(offset) (UART0_BASE + (4 * offset))
+#endif
+
 #ifndef PORT
 #error please define the serial port address for your own machine
 #endif
diff --git a/arch/mips/cavium-octeon/.gitignore b/arch/mips/cavium-octeon/.gitignore
new file mode 100644 (file)
index 0000000..39c9686
--- /dev/null
@@ -0,0 +1,2 @@
+*.dtb.S
+*.dtb
index 19eb0434269ffc6017bb79da7f00485d2cb13813..bc96e2908f14436616083cf3706fd0dddf718d6a 100644 (file)
@@ -9,9 +9,25 @@
 # Copyright (C) 2005-2009 Cavium Networks
 #
 
+CFLAGS_octeon-platform.o = -I$(src)/../../../scripts/dtc/libfdt
+CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
+
 obj-y := cpu.o setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o
 obj-y += dma-octeon.o flash_setup.o
 obj-y += octeon-memcpy.o
 obj-y += executive/
 
 obj-$(CONFIG_SMP)                     += smp.o
+
+DTS_FILES = octeon_3xxx.dts octeon_68xx.dts
+DTB_FILES = $(patsubst %.dts, %.dtb, $(DTS_FILES))
+
+obj-y += $(patsubst %.dts, %.dtb.o, $(DTS_FILES))
+
+$(obj)/%.dtb: $(src)/%.dts FORCE
+       $(call if_changed_dep,dtc)
+
+# Let's keep the .dtb files around in case we want to look at them.
+.SECONDARY:  $(addprefix $(obj)/, $(DTB_FILES))
+
+clean-files += $(DTB_FILES) $(patsubst %.dtb, %.dtb.S, $(DTB_FILES))
diff --git a/arch/mips/cavium-octeon/executive/cvmx-fpa.c b/arch/mips/cavium-octeon/executive/cvmx-fpa.c
deleted file mode 100644 (file)
index ad44b8b..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/***********************license start***************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2008 Cavium Networks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
- ***********************license end**************************************/
-
-/**
- * @file
- *
- * Support library for the hardware Free Pool Allocator.
- *
- *
- */
-
-#include "cvmx-config.h"
-#include "cvmx.h"
-#include "cvmx-fpa.h"
-#include "cvmx-ipd.h"
-
-/**
- * Current state of all the pools. Use access functions
- * instead of using it directly.
- */
-CVMX_SHARED cvmx_fpa_pool_info_t cvmx_fpa_pool_info[CVMX_FPA_NUM_POOLS];
-
-/**
- * Setup a FPA pool to control a new block of memory. The
- * buffer pointer must be a physical address.
- *
- * @pool:       Pool to initialize
- *                   0 <= pool < 8
- * @name:       Constant character string to name this pool.
- *                   String is not copied.
- * @buffer:     Pointer to the block of memory to use. This must be
- *                   accessible by all processors and external hardware.
- * @block_size: Size for each block controlled by the FPA
- * @num_blocks: Number of blocks
- *
- * Returns 0 on Success,
- *         -1 on failure
- */
-int cvmx_fpa_setup_pool(uint64_t pool, const char *name, void *buffer,
-                       uint64_t block_size, uint64_t num_blocks)
-{
-       char *ptr;
-       if (!buffer) {
-               cvmx_dprintf
-                   ("ERROR: cvmx_fpa_setup_pool: NULL buffer pointer!\n");
-               return -1;
-       }
-       if (pool >= CVMX_FPA_NUM_POOLS) {
-               cvmx_dprintf("ERROR: cvmx_fpa_setup_pool: Illegal pool!\n");
-               return -1;
-       }
-
-       if (block_size < CVMX_FPA_MIN_BLOCK_SIZE) {
-               cvmx_dprintf
-                   ("ERROR: cvmx_fpa_setup_pool: Block size too small.\n");
-               return -1;
-       }
-
-       if (((unsigned long)buffer & (CVMX_FPA_ALIGNMENT - 1)) != 0) {
-               cvmx_dprintf
-                   ("ERROR: cvmx_fpa_setup_pool: Buffer not aligned properly.\n");
-               return -1;
-       }
-
-       cvmx_fpa_pool_info[pool].name = name;
-       cvmx_fpa_pool_info[pool].size = block_size;
-       cvmx_fpa_pool_info[pool].starting_element_count = num_blocks;
-       cvmx_fpa_pool_info[pool].base = buffer;
-
-       ptr = (char *)buffer;
-       while (num_blocks--) {
-               cvmx_fpa_free(ptr, pool, 0);
-               ptr += block_size;
-       }
-       return 0;
-}
-
-/**
- * Shutdown a Memory pool and validate that it had all of
- * the buffers originally placed in it.
- *
- * @pool:   Pool to shutdown
- * Returns Zero on success
- *         - Positive is count of missing buffers
- *         - Negative is too many buffers or corrupted pointers
- */
-uint64_t cvmx_fpa_shutdown_pool(uint64_t pool)
-{
-       uint64_t errors = 0;
-       uint64_t count = 0;
-       uint64_t base = cvmx_ptr_to_phys(cvmx_fpa_pool_info[pool].base);
-       uint64_t finish =
-           base +
-           cvmx_fpa_pool_info[pool].size *
-           cvmx_fpa_pool_info[pool].starting_element_count;
-       void *ptr;
-       uint64_t address;
-
-       count = 0;
-       do {
-               ptr = cvmx_fpa_alloc(pool);
-               if (ptr)
-                       address = cvmx_ptr_to_phys(ptr);
-               else
-                       address = 0;
-               if (address) {
-                       if ((address >= base) && (address < finish) &&
-                           (((address -
-                              base) % cvmx_fpa_pool_info[pool].size) == 0)) {
-                               count++;
-                       } else {
-                               cvmx_dprintf
-                                   ("ERROR: cvmx_fpa_shutdown_pool: Illegal address 0x%llx in pool %s(%d)\n",
-                                    (unsigned long long)address,
-                                    cvmx_fpa_pool_info[pool].name, (int)pool);
-                               errors++;
-                       }
-               }
-       } while (address);
-
-#ifdef CVMX_ENABLE_PKO_FUNCTIONS
-       if (pool == 0)
-               cvmx_ipd_free_ptr();
-#endif
-
-       if (errors) {
-               cvmx_dprintf
-                   ("ERROR: cvmx_fpa_shutdown_pool: Pool %s(%d) started at 0x%llx, ended at 0x%llx, with a step of 0x%llx\n",
-                    cvmx_fpa_pool_info[pool].name, (int)pool,
-                    (unsigned long long)base, (unsigned long long)finish,
-                    (unsigned long long)cvmx_fpa_pool_info[pool].size);
-               return -errors;
-       } else
-               return 0;
-}
-
-uint64_t cvmx_fpa_get_block_size(uint64_t pool)
-{
-       switch (pool) {
-       case 0:
-               return CVMX_FPA_POOL_0_SIZE;
-       case 1:
-               return CVMX_FPA_POOL_1_SIZE;
-       case 2:
-               return CVMX_FPA_POOL_2_SIZE;
-       case 3:
-               return CVMX_FPA_POOL_3_SIZE;
-       case 4:
-               return CVMX_FPA_POOL_4_SIZE;
-       case 5:
-               return CVMX_FPA_POOL_5_SIZE;
-       case 6:
-               return CVMX_FPA_POOL_6_SIZE;
-       case 7:
-               return CVMX_FPA_POOL_7_SIZE;
-       default:
-               return 0;
-       }
-}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c b/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c
deleted file mode 100644 (file)
index c239e5f..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-/***********************license start***************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2008 Cavium Networks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
- ***********************license end**************************************/
-
-/**
- * @file
- *
- * Helper functions for FPA setup.
- *
- */
-#include "executive-config.h"
-#include "cvmx-config.h"
-#include "cvmx.h"
-#include "cvmx-bootmem.h"
-#include "cvmx-fpa.h"
-#include "cvmx-helper-fpa.h"
-
-/**
- * Allocate memory for and initialize a single FPA pool.
- *
- * @pool:    Pool to initialize
- * @buffer_size:  Size of buffers to allocate in bytes
- * @buffers: Number of buffers to put in the pool. Zero is allowed
- * @name:    String name of the pool for debugging purposes
- * Returns Zero on success, non-zero on failure
- */
-static int __cvmx_helper_initialize_fpa_pool(int pool, uint64_t buffer_size,
-                                            uint64_t buffers, const char *name)
-{
-       uint64_t current_num;
-       void *memory;
-       uint64_t align = CVMX_CACHE_LINE_SIZE;
-
-       /*
-        * Align the allocation so that power of 2 size buffers are
-        * naturally aligned.
-        */
-       while (align < buffer_size)
-               align = align << 1;
-
-       if (buffers == 0)
-               return 0;
-
-       current_num = cvmx_read_csr(CVMX_FPA_QUEX_AVAILABLE(pool));
-       if (current_num) {
-               cvmx_dprintf("Fpa pool %d(%s) already has %llu buffers. "
-                            "Skipping setup.\n",
-                    pool, name, (unsigned long long)current_num);
-               return 0;
-       }
-
-       memory = cvmx_bootmem_alloc(buffer_size * buffers, align);
-       if (memory == NULL) {
-               cvmx_dprintf("Out of memory initializing fpa pool %d(%s).\n",
-                            pool, name);
-               return -1;
-       }
-       cvmx_fpa_setup_pool(pool, name, memory, buffer_size, buffers);
-       return 0;
-}
-
-/**
- * Allocate memory and initialize the FPA pools using memory
- * from cvmx-bootmem. Specifying zero for the number of
- * buffers will cause that FPA pool to not be setup. This is
- * useful if you aren't using some of the hardware and want
- * to save memory. Use cvmx_helper_initialize_fpa instead of
- * this function directly.
- *
- * @pip_pool: Should always be CVMX_FPA_PACKET_POOL
- * @pip_size: Should always be CVMX_FPA_PACKET_POOL_SIZE
- * @pip_buffers:
- *                 Number of packet buffers.
- * @wqe_pool: Should always be CVMX_FPA_WQE_POOL
- * @wqe_size: Should always be CVMX_FPA_WQE_POOL_SIZE
- * @wqe_entries:
- *                 Number of work queue entries
- * @pko_pool: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL
- * @pko_size: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE
- * @pko_buffers:
- *                 PKO Command buffers. You should at minimum have two per
- *                 each PKO queue.
- * @tim_pool: Should always be CVMX_FPA_TIMER_POOL
- * @tim_size: Should always be CVMX_FPA_TIMER_POOL_SIZE
- * @tim_buffers:
- *                 TIM ring buffer command queues. At least two per timer bucket
- *                 is recommened.
- * @dfa_pool: Should always be CVMX_FPA_DFA_POOL
- * @dfa_size: Should always be CVMX_FPA_DFA_POOL_SIZE
- * @dfa_buffers:
- *                 DFA command buffer. A relatively small (32 for example)
- *                 number should work.
- * Returns Zero on success, non-zero if out of memory
- */
-static int __cvmx_helper_initialize_fpa(int pip_pool, int pip_size,
-                                       int pip_buffers, int wqe_pool,
-                                       int wqe_size, int wqe_entries,
-                                       int pko_pool, int pko_size,
-                                       int pko_buffers, int tim_pool,
-                                       int tim_size, int tim_buffers,
-                                       int dfa_pool, int dfa_size,
-                                       int dfa_buffers)
-{
-       int status;
-
-       cvmx_fpa_enable();
-
-       if ((pip_buffers > 0) && (pip_buffers <= 64))
-               cvmx_dprintf
-                   ("Warning: %d packet buffers may not be enough for hardware"
-                    " prefetch. 65 or more is recommended.\n", pip_buffers);
-
-       if (pip_pool >= 0) {
-               status =
-                   __cvmx_helper_initialize_fpa_pool(pip_pool, pip_size,
-                                                     pip_buffers,
-                                                     "Packet Buffers");
-               if (status)
-                       return status;
-       }
-
-       if (wqe_pool >= 0) {
-               status =
-                   __cvmx_helper_initialize_fpa_pool(wqe_pool, wqe_size,
-                                                     wqe_entries,
-                                                     "Work Queue Entries");
-               if (status)
-                       return status;
-       }
-
-       if (pko_pool >= 0) {
-               status =
-                   __cvmx_helper_initialize_fpa_pool(pko_pool, pko_size,
-                                                     pko_buffers,
-                                                     "PKO Command Buffers");
-               if (status)
-                       return status;
-       }
-
-       if (tim_pool >= 0) {
-               status =
-                   __cvmx_helper_initialize_fpa_pool(tim_pool, tim_size,
-                                                     tim_buffers,
-                                                     "TIM Command Buffers");
-               if (status)
-                       return status;
-       }
-
-       if (dfa_pool >= 0) {
-               status =
-                   __cvmx_helper_initialize_fpa_pool(dfa_pool, dfa_size,
-                                                     dfa_buffers,
-                                                     "DFA Command Buffers");
-               if (status)
-                       return status;
-       }
-
-       return 0;
-}
-
-/**
- * Allocate memory and initialize the FPA pools using memory
- * from cvmx-bootmem. Sizes of each element in the pools is
- * controlled by the cvmx-config.h header file. Specifying
- * zero for any parameter will cause that FPA pool to not be
- * setup. This is useful if you aren't using some of the
- * hardware and want to save memory.
- *
- * @packet_buffers:
- *               Number of packet buffers to allocate
- * @work_queue_entries:
- *               Number of work queue entries
- * @pko_buffers:
- *               PKO Command buffers. You should at minimum have two per
- *               each PKO queue.
- * @tim_buffers:
- *               TIM ring buffer command queues. At least two per timer bucket
- *               is recommened.
- * @dfa_buffers:
- *               DFA command buffer. A relatively small (32 for example)
- *               number should work.
- * Returns Zero on success, non-zero if out of memory
- */
-int cvmx_helper_initialize_fpa(int packet_buffers, int work_queue_entries,
-                              int pko_buffers, int tim_buffers,
-                              int dfa_buffers)
-{
-#ifndef CVMX_FPA_PACKET_POOL
-#define CVMX_FPA_PACKET_POOL -1
-#define CVMX_FPA_PACKET_POOL_SIZE 0
-#endif
-#ifndef CVMX_FPA_WQE_POOL
-#define CVMX_FPA_WQE_POOL -1
-#define CVMX_FPA_WQE_POOL_SIZE 0
-#endif
-#ifndef CVMX_FPA_OUTPUT_BUFFER_POOL
-#define CVMX_FPA_OUTPUT_BUFFER_POOL -1
-#define CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE 0
-#endif
-#ifndef CVMX_FPA_TIMER_POOL
-#define CVMX_FPA_TIMER_POOL -1
-#define CVMX_FPA_TIMER_POOL_SIZE 0
-#endif
-#ifndef CVMX_FPA_DFA_POOL
-#define CVMX_FPA_DFA_POOL -1
-#define CVMX_FPA_DFA_POOL_SIZE 0
-#endif
-       return __cvmx_helper_initialize_fpa(CVMX_FPA_PACKET_POOL,
-                                           CVMX_FPA_PACKET_POOL_SIZE,
-                                           packet_buffers, CVMX_FPA_WQE_POOL,
-                                           CVMX_FPA_WQE_POOL_SIZE,
-                                           work_queue_entries,
-                                           CVMX_FPA_OUTPUT_BUFFER_POOL,
-                                           CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE,
-                                           pko_buffers, CVMX_FPA_TIMER_POOL,
-                                           CVMX_FPA_TIMER_POOL_SIZE,
-                                           tim_buffers, CVMX_FPA_DFA_POOL,
-                                           CVMX_FPA_DFA_POOL_SIZE,
-                                           dfa_buffers);
-}
index ffd4ae660f792461015be0f1d7ceb2dec7184dea..7fb1f222b8a538b9b000e99375899f37a0c069a9 100644 (file)
@@ -3,14 +3,17 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2004-2008, 2009, 2010, 2011 Cavium Networks
+ * Copyright (C) 2004-2012 Cavium, Inc.
  */
 
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/bitops.h>
 #include <linux/percpu.h>
+#include <linux/slab.h>
 #include <linux/irq.h>
 #include <linux/smp.h>
+#include <linux/of.h>
 
 #include <asm/octeon/octeon.h>
 
@@ -42,9 +45,9 @@ struct octeon_core_chip_data {
 
 static struct octeon_core_chip_data octeon_irq_core_chip_data[MIPS_CORE_IRQ_LINES];
 
-static void __init octeon_irq_set_ciu_mapping(int irq, int line, int bit,
-                                             struct irq_chip *chip,
-                                             irq_flow_handler_t handler)
+static void octeon_irq_set_ciu_mapping(int irq, int line, int bit,
+                                      struct irq_chip *chip,
+                                      irq_flow_handler_t handler)
 {
        union octeon_ciu_chip_data cd;
 
@@ -505,6 +508,85 @@ static void octeon_irq_ciu_enable_all_v2(struct irq_data *data)
        }
 }
 
+static void octeon_irq_gpio_setup(struct irq_data *data)
+{
+       union cvmx_gpio_bit_cfgx cfg;
+       union octeon_ciu_chip_data cd;
+       u32 t = irqd_get_trigger_type(data);
+
+       cd.p = irq_data_get_irq_chip_data(data);
+
+       cfg.u64 = 0;
+       cfg.s.int_en = 1;
+       cfg.s.int_type = (t & IRQ_TYPE_EDGE_BOTH) != 0;
+       cfg.s.rx_xor = (t & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) != 0;
+
+       /* 140 nS glitch filter*/
+       cfg.s.fil_cnt = 7;
+       cfg.s.fil_sel = 3;
+
+       cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd.s.bit - 16), cfg.u64);
+}
+
+static void octeon_irq_ciu_enable_gpio_v2(struct irq_data *data)
+{
+       octeon_irq_gpio_setup(data);
+       octeon_irq_ciu_enable_v2(data);
+}
+
+static void octeon_irq_ciu_enable_gpio(struct irq_data *data)
+{
+       octeon_irq_gpio_setup(data);
+       octeon_irq_ciu_enable(data);
+}
+
+static int octeon_irq_ciu_gpio_set_type(struct irq_data *data, unsigned int t)
+{
+       irqd_set_trigger_type(data, t);
+       octeon_irq_gpio_setup(data);
+
+       return IRQ_SET_MASK_OK;
+}
+
+static void octeon_irq_ciu_disable_gpio_v2(struct irq_data *data)
+{
+       union octeon_ciu_chip_data cd;
+
+       cd.p = irq_data_get_irq_chip_data(data);
+       cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd.s.bit - 16), 0);
+
+       octeon_irq_ciu_disable_all_v2(data);
+}
+
+static void octeon_irq_ciu_disable_gpio(struct irq_data *data)
+{
+       union octeon_ciu_chip_data cd;
+
+       cd.p = irq_data_get_irq_chip_data(data);
+       cvmx_write_csr(CVMX_GPIO_BIT_CFGX(cd.s.bit - 16), 0);
+
+       octeon_irq_ciu_disable_all(data);
+}
+
+static void octeon_irq_ciu_gpio_ack(struct irq_data *data)
+{
+       union octeon_ciu_chip_data cd;
+       u64 mask;
+
+       cd.p = irq_data_get_irq_chip_data(data);
+       mask = 1ull << (cd.s.bit - 16);
+
+       cvmx_write_csr(CVMX_GPIO_INT_CLR, mask);
+}
+
+static void octeon_irq_handle_gpio(unsigned int irq, struct irq_desc *desc)
+{
+       if (irqd_get_trigger_type(irq_desc_get_irq_data(desc)) & IRQ_TYPE_EDGE_BOTH)
+               handle_edge_irq(irq, desc);
+       else
+               handle_level_irq(irq, desc);
+}
+
 #ifdef CONFIG_SMP
 
 static void octeon_irq_cpu_offline_ciu(struct irq_data *data)
@@ -650,18 +732,6 @@ static struct irq_chip octeon_irq_chip_ciu_v2 = {
        .name = "CIU",
        .irq_enable = octeon_irq_ciu_enable_v2,
        .irq_disable = octeon_irq_ciu_disable_all_v2,
-       .irq_mask = octeon_irq_ciu_disable_local_v2,
-       .irq_unmask = octeon_irq_ciu_enable_v2,
-#ifdef CONFIG_SMP
-       .irq_set_affinity = octeon_irq_ciu_set_affinity_v2,
-       .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
-#endif
-};
-
-static struct irq_chip octeon_irq_chip_ciu_edge_v2 = {
-       .name = "CIU-E",
-       .irq_enable = octeon_irq_ciu_enable_v2,
-       .irq_disable = octeon_irq_ciu_disable_all_v2,
        .irq_ack = octeon_irq_ciu_ack,
        .irq_mask = octeon_irq_ciu_disable_local_v2,
        .irq_unmask = octeon_irq_ciu_enable_v2,
@@ -675,19 +745,8 @@ static struct irq_chip octeon_irq_chip_ciu = {
        .name = "CIU",
        .irq_enable = octeon_irq_ciu_enable,
        .irq_disable = octeon_irq_ciu_disable_all,
-       .irq_mask = octeon_irq_dummy_mask,
-#ifdef CONFIG_SMP
-       .irq_set_affinity = octeon_irq_ciu_set_affinity,
-       .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
-#endif
-};
-
-static struct irq_chip octeon_irq_chip_ciu_edge = {
-       .name = "CIU-E",
-       .irq_enable = octeon_irq_ciu_enable,
-       .irq_disable = octeon_irq_ciu_disable_all,
-       .irq_mask = octeon_irq_dummy_mask,
        .irq_ack = octeon_irq_ciu_ack,
+       .irq_mask = octeon_irq_dummy_mask,
 #ifdef CONFIG_SMP
        .irq_set_affinity = octeon_irq_ciu_set_affinity,
        .irq_cpu_offline = octeon_irq_cpu_offline_ciu,
@@ -717,6 +776,33 @@ static struct irq_chip octeon_irq_chip_ciu_mbox = {
        .flags = IRQCHIP_ONOFFLINE_ENABLED,
 };
 
+static struct irq_chip octeon_irq_chip_ciu_gpio_v2 = {
+       .name = "CIU-GPIO",
+       .irq_enable = octeon_irq_ciu_enable_gpio_v2,
+       .irq_disable = octeon_irq_ciu_disable_gpio_v2,
+       .irq_ack = octeon_irq_ciu_gpio_ack,
+       .irq_mask = octeon_irq_ciu_disable_local_v2,
+       .irq_unmask = octeon_irq_ciu_enable_v2,
+       .irq_set_type = octeon_irq_ciu_gpio_set_type,
+#ifdef CONFIG_SMP
+       .irq_set_affinity = octeon_irq_ciu_set_affinity_v2,
+#endif
+       .flags = IRQCHIP_SET_TYPE_MASKED,
+};
+
+static struct irq_chip octeon_irq_chip_ciu_gpio = {
+       .name = "CIU-GPIO",
+       .irq_enable = octeon_irq_ciu_enable_gpio,
+       .irq_disable = octeon_irq_ciu_disable_gpio,
+       .irq_mask = octeon_irq_dummy_mask,
+       .irq_ack = octeon_irq_ciu_gpio_ack,
+       .irq_set_type = octeon_irq_ciu_gpio_set_type,
+#ifdef CONFIG_SMP
+       .irq_set_affinity = octeon_irq_ciu_set_affinity,
+#endif
+       .flags = IRQCHIP_SET_TYPE_MASKED,
+};
+
 /*
  * Watchdog interrupts are special.  They are associated with a single
  * core, so we hardwire the affinity to that core.
@@ -764,6 +850,178 @@ static struct irq_chip octeon_irq_chip_ciu_wd = {
        .irq_mask = octeon_irq_dummy_mask,
 };
 
+static bool octeon_irq_ciu_is_edge(unsigned int line, unsigned int bit)
+{
+       bool edge = false;
+
+       if (line == 0)
+               switch (bit) {
+               case 48 ... 49: /* GMX DRP */
+               case 50: /* IPD_DRP */
+               case 52 ... 55: /* Timers */
+               case 58: /* MPI */
+                       edge = true;
+                       break;
+               default:
+                       break;
+               }
+       else /* line == 1 */
+               switch (bit) {
+               case 47: /* PTP */
+                       edge = true;
+                       break;
+               default:
+                       break;
+               }
+       return edge;
+}
+
+struct octeon_irq_gpio_domain_data {
+       unsigned int base_hwirq;
+};
+
+static int octeon_irq_gpio_xlat(struct irq_domain *d,
+                               struct device_node *node,
+                               const u32 *intspec,
+                               unsigned int intsize,
+                               unsigned long *out_hwirq,
+                               unsigned int *out_type)
+{
+       unsigned int type;
+       unsigned int pin;
+       unsigned int trigger;
+       struct octeon_irq_gpio_domain_data *gpiod;
+
+       if (d->of_node != node)
+               return -EINVAL;
+
+       if (intsize < 2)
+               return -EINVAL;
+
+       pin = intspec[0];
+       if (pin >= 16)
+               return -EINVAL;
+
+       trigger = intspec[1];
+
+       switch (trigger) {
+       case 1:
+               type = IRQ_TYPE_EDGE_RISING;
+               break;
+       case 2:
+               type = IRQ_TYPE_EDGE_FALLING;
+               break;
+       case 4:
+               type = IRQ_TYPE_LEVEL_HIGH;
+               break;
+       case 8:
+               type = IRQ_TYPE_LEVEL_LOW;
+               break;
+       default:
+               pr_err("Error: (%s) Invalid irq trigger specification: %x\n",
+                      node->name,
+                      trigger);
+               type = IRQ_TYPE_LEVEL_LOW;
+               break;
+       }
+       *out_type = type;
+       gpiod = d->host_data;
+       *out_hwirq = gpiod->base_hwirq + pin;
+
+       return 0;
+}
+
+static int octeon_irq_ciu_xlat(struct irq_domain *d,
+                              struct device_node *node,
+                              const u32 *intspec,
+                              unsigned int intsize,
+                              unsigned long *out_hwirq,
+                              unsigned int *out_type)
+{
+       unsigned int ciu, bit;
+
+       ciu = intspec[0];
+       bit = intspec[1];
+
+       if (ciu > 1 || bit > 63)
+               return -EINVAL;
+
+       /* These are the GPIO lines */
+       if (ciu == 0 && bit >= 16 && bit < 32)
+               return -EINVAL;
+
+       *out_hwirq = (ciu << 6) | bit;
+       *out_type = 0;
+
+       return 0;
+}
+
+static struct irq_chip *octeon_irq_ciu_chip;
+static struct irq_chip *octeon_irq_gpio_chip;
+
+static bool octeon_irq_virq_in_range(unsigned int virq)
+{
+       /* We cannot let it overflow the mapping array. */
+       if (virq < (1ul << 8 * sizeof(octeon_irq_ciu_to_irq[0][0])))
+               return true;
+
+       WARN_ONCE(true, "virq out of range %u.\n", virq);
+       return false;
+}
+
+static int octeon_irq_ciu_map(struct irq_domain *d,
+                             unsigned int virq, irq_hw_number_t hw)
+{
+       unsigned int line = hw >> 6;
+       unsigned int bit = hw & 63;
+
+       if (!octeon_irq_virq_in_range(virq))
+               return -EINVAL;
+
+       if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0)
+               return -EINVAL;
+
+       if (octeon_irq_ciu_is_edge(line, bit))
+               octeon_irq_set_ciu_mapping(virq, line, bit,
+                                          octeon_irq_ciu_chip,
+                                          handle_edge_irq);
+       else
+               octeon_irq_set_ciu_mapping(virq, line, bit,
+                                          octeon_irq_ciu_chip,
+                                          handle_level_irq);
+
+       return 0;
+}
+
+static int octeon_irq_gpio_map(struct irq_domain *d,
+                              unsigned int virq, irq_hw_number_t hw)
+{
+       unsigned int line = hw >> 6;
+       unsigned int bit = hw & 63;
+
+       if (!octeon_irq_virq_in_range(virq))
+               return -EINVAL;
+
+       if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0)
+               return -EINVAL;
+
+       octeon_irq_set_ciu_mapping(virq, line, bit,
+                                  octeon_irq_gpio_chip,
+                                  octeon_irq_handle_gpio);
+
+       return 0;
+}
+
+static struct irq_domain_ops octeon_irq_domain_ciu_ops = {
+       .map = octeon_irq_ciu_map,
+       .xlate = octeon_irq_ciu_xlat,
+};
+
+static struct irq_domain_ops octeon_irq_domain_gpio_ops = {
+       .map = octeon_irq_gpio_map,
+       .xlate = octeon_irq_gpio_xlat,
+};
+
 static void octeon_irq_ip2_v1(void)
 {
        const unsigned long core_id = cvmx_get_core_num();
@@ -887,9 +1145,10 @@ static void __init octeon_irq_init_ciu(void)
 {
        unsigned int i;
        struct irq_chip *chip;
-       struct irq_chip *chip_edge;
        struct irq_chip *chip_mbox;
        struct irq_chip *chip_wd;
+       struct device_node *gpio_node;
+       struct device_node *ciu_node;
 
        octeon_irq_init_ciu_percpu();
        octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu;
@@ -901,17 +1160,18 @@ static void __init octeon_irq_init_ciu(void)
                octeon_irq_ip2 = octeon_irq_ip2_v2;
                octeon_irq_ip3 = octeon_irq_ip3_v2;
                chip = &octeon_irq_chip_ciu_v2;
-               chip_edge = &octeon_irq_chip_ciu_edge_v2;
                chip_mbox = &octeon_irq_chip_ciu_mbox_v2;
                chip_wd = &octeon_irq_chip_ciu_wd_v2;
+               octeon_irq_gpio_chip = &octeon_irq_chip_ciu_gpio_v2;
        } else {
                octeon_irq_ip2 = octeon_irq_ip2_v1;
                octeon_irq_ip3 = octeon_irq_ip3_v1;
                chip = &octeon_irq_chip_ciu;
-               chip_edge = &octeon_irq_chip_ciu_edge;
                chip_mbox = &octeon_irq_chip_ciu_mbox;
                chip_wd = &octeon_irq_chip_ciu_wd;
+               octeon_irq_gpio_chip = &octeon_irq_chip_ciu_gpio;
        }
+       octeon_irq_ciu_chip = chip;
        octeon_irq_ip4 = octeon_irq_ip4_mask;
 
        /* Mips internal */
@@ -920,80 +1180,49 @@ static void __init octeon_irq_init_ciu(void)
        /* CIU_0 */
        for (i = 0; i < 16; i++)
                octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WORKQ0, 0, i + 0, chip, handle_level_irq);
-       for (i = 0; i < 16; i++)
-               octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_GPIO0, 0, i + 16, chip, handle_level_irq);
 
        octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq);
        octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq);
 
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_UART0, 0, 34, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_UART1, 0, 35, chip, handle_level_irq);
-
        for (i = 0; i < 4; i++)
                octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_INT0, 0, i + 36, chip, handle_level_irq);
        for (i = 0; i < 4; i++)
                octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_MSI0, 0, i + 40, chip, handle_level_irq);
 
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_TWSI, 0, 45, chip, handle_level_irq);
        octeon_irq_set_ciu_mapping(OCTEON_IRQ_RML, 0, 46, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_TRACE0, 0, 47, chip, handle_level_irq);
-
-       for (i = 0; i < 2; i++)
-               octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_GMX_DRP0, 0, i + 48, chip_edge, handle_edge_irq);
-
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_IPD_DRP, 0, 50, chip_edge, handle_edge_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_KEY_ZERO, 0, 51, chip_edge, handle_edge_irq);
-
        for (i = 0; i < 4; i++)
-               octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip_edge, handle_edge_irq);
+               octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip, handle_edge_irq);
 
        octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB0, 0, 56, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_PCM, 0, 57, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_MPI, 0, 58, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_TWSI2, 0, 59, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_POWIQ, 0, 60, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_IPDPPTHR, 0, 61, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII0, 0, 62, chip, handle_level_irq);
        octeon_irq_set_ciu_mapping(OCTEON_IRQ_BOOTDMA, 0, 63, chip, handle_level_irq);
 
        /* CIU_1 */
        for (i = 0; i < 16; i++)
                octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WDOG0, 1, i + 0, chip_wd, handle_level_irq);
 
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_UART2, 1, 16, chip, handle_level_irq);
        octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_MII1, 1, 18, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_NAND, 1, 19, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_MIO, 1, 20, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_IOB, 1, 21, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_FPA, 1, 22, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_POW, 1, 23, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_L2C, 1, 24, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_IPD, 1, 25, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_PIP, 1, 26, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_PKO, 1, 27, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_ZIP, 1, 28, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_TIM, 1, 29, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_RAD, 1, 30, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_KEY, 1, 31, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_DFA, 1, 32, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_USBCTL, 1, 33, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_SLI, 1, 34, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_DPI, 1, 35, chip, handle_level_irq);
-
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_AGX0, 1, 36, chip, handle_level_irq);
-
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_AGL, 1, 46, chip, handle_level_irq);
-
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_PTP, 1, 47, chip_edge, handle_edge_irq);
-
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_PEM0, 1, 48, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_PEM1, 1, 49, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_SRIO0, 1, 50, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_SRIO1, 1, 51, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_LMC0, 1, 52, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_DFM, 1, 56, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_RST, 1, 63, chip, handle_level_irq);
+
+       gpio_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-gpio");
+       if (gpio_node) {
+               struct octeon_irq_gpio_domain_data *gpiod;
+
+               gpiod = kzalloc(sizeof(*gpiod), GFP_KERNEL);
+               if (gpiod) {
+                       /* gpio domain host_data is the base hwirq number. */
+                       gpiod->base_hwirq = 16;
+                       irq_domain_add_linear(gpio_node, 16, &octeon_irq_domain_gpio_ops, gpiod);
+                       of_node_put(gpio_node);
+               } else
+                       pr_warn("Cannot allocate memory for GPIO irq_domain.\n");
+       } else
+               pr_warn("Cannot find device node for cavium,octeon-3860-gpio.\n");
+
+       ciu_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-ciu");
+       if (ciu_node) {
+               irq_domain_add_tree(ciu_node, &octeon_irq_domain_ciu_ops, NULL);
+               of_node_put(ciu_node);
+       } else
+               pr_warn("Cannot find device node for cavium,octeon-3860-ciu.\n");
 
        /* Enable the CIU lines */
        set_c0_status(STATUSF_IP3 | STATUSF_IP2);
index 88e0cddca2057addb1ad823844cc3e2351e0c2e7..db478dbb9c7beb87c1cef87932e9a5e107ce8991 100644 (file)
        .set    noreorder
        .set    noat
 
+/*
+ * t7 is used as a flag to note inatomic mode.
+ */
+LEAF(__copy_user_inatomic)
+       b       __copy_user_common
+        li     t7, 1
+       END(__copy_user_inatomic)
+
 /*
  * A combined memcpy/__copy_user
  * __copy_user sets len to 0 for success; else to an upper bound of
@@ -174,6 +182,8 @@ LEAF(memcpy)                                        /* a0=dst a1=src a2=len */
        move    v0, dst                         /* return value */
 __memcpy:
 FEXPORT(__copy_user)
+       li      t7, 0                           /* not inatomic */
+__copy_user_common:
        /*
         * Note: dst & src may be unaligned, len may be 0
         * Temps
@@ -412,7 +422,6 @@ l_exc_copy:
         * Assumes src < THREAD_BUADDR($28)
         */
        LOAD    t0, TI_TASK($28)
-        nop
        LOAD    t0, THREAD_BUADDR(t0)
 1:
 EXC(   lb      t1, 0(src),     l_exc)
@@ -422,10 +431,9 @@ EXC(       lb      t1, 0(src),     l_exc)
         ADD    dst, dst, 1
 l_exc:
        LOAD    t0, TI_TASK($28)
-        nop
        LOAD    t0, THREAD_BUADDR(t0)   # t0 is just past last good address
-        nop
        SUB     len, AT, t0             # len number of uncopied bytes
+       bnez    t7, 2f          /* Skip the zeroing out part if inatomic */
        /*
         * Here's where we rely on src and dst being incremented in tandem,
         *   See (3) above.
@@ -443,7 +451,7 @@ l_exc:
        ADD     dst, dst, 1
        bnez    src, 1b
         SUB    src, src, 1
-       jr      ra
+2:     jr      ra
         nop
 
 
index cd61d7281d9162c9e759a28772ec49ee3ef98707..0938df10a71c54f8816c866b86e602deef54102b 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2004-2010 Cavium Networks
+ * Copyright (C) 2004-2011 Cavium Networks
  * Copyright (C) 2008 Wind River Systems
  */
 
 #include <linux/usb.h>
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt.h>
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-rnm-defs.h>
+#include <asm/octeon/cvmx-helper.h>
+#include <asm/octeon/cvmx-helper-board.h>
 
 static struct octeon_cf_data octeon_cf_data;
 
@@ -162,182 +168,6 @@ out:
 }
 device_initcall(octeon_rng_device_init);
 
-static struct i2c_board_info __initdata octeon_i2c_devices[] = {
-       {
-               I2C_BOARD_INFO("ds1337", 0x68),
-       },
-};
-
-static int __init octeon_i2c_devices_init(void)
-{
-       return i2c_register_board_info(0, octeon_i2c_devices,
-                                      ARRAY_SIZE(octeon_i2c_devices));
-}
-arch_initcall(octeon_i2c_devices_init);
-
-#define OCTEON_I2C_IO_BASE 0x1180000001000ull
-#define OCTEON_I2C_IO_UNIT_OFFSET 0x200
-
-static struct octeon_i2c_data octeon_i2c_data[2];
-
-static int __init octeon_i2c_device_init(void)
-{
-       struct platform_device *pd;
-       int ret = 0;
-       int port, num_ports;
-
-       struct resource i2c_resources[] = {
-               {
-                       .flags  = IORESOURCE_MEM,
-               }, {
-                       .flags  = IORESOURCE_IRQ,
-               }
-       };
-
-       if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
-               num_ports = 2;
-       else
-               num_ports = 1;
-
-       for (port = 0; port < num_ports; port++) {
-               octeon_i2c_data[port].sys_freq = octeon_get_io_clock_rate();
-               /*FIXME: should be examined. At the moment is set for 100Khz */
-               octeon_i2c_data[port].i2c_freq = 100000;
-
-               pd = platform_device_alloc("i2c-octeon", port);
-               if (!pd) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
-               pd->dev.platform_data = octeon_i2c_data + port;
-
-               i2c_resources[0].start =
-                       OCTEON_I2C_IO_BASE + (port * OCTEON_I2C_IO_UNIT_OFFSET);
-               i2c_resources[0].end = i2c_resources[0].start + 0x1f;
-               switch (port) {
-               case 0:
-                       i2c_resources[1].start = OCTEON_IRQ_TWSI;
-                       i2c_resources[1].end = OCTEON_IRQ_TWSI;
-                       break;
-               case 1:
-                       i2c_resources[1].start = OCTEON_IRQ_TWSI2;
-                       i2c_resources[1].end = OCTEON_IRQ_TWSI2;
-                       break;
-               default:
-                       BUG();
-               }
-
-               ret = platform_device_add_resources(pd,
-                                                   i2c_resources,
-                                                   ARRAY_SIZE(i2c_resources));
-               if (ret)
-                       goto fail;
-
-               ret = platform_device_add(pd);
-               if (ret)
-                       goto fail;
-       }
-       return ret;
-fail:
-       platform_device_put(pd);
-out:
-       return ret;
-}
-device_initcall(octeon_i2c_device_init);
-
-/* Octeon SMI/MDIO interface.  */
-static int __init octeon_mdiobus_device_init(void)
-{
-       struct platform_device *pd;
-       int ret = 0;
-
-       if (octeon_is_simulation())
-               return 0; /* No mdio in the simulator. */
-
-       /* The bus number is the platform_device id.  */
-       pd = platform_device_alloc("mdio-octeon", 0);
-       if (!pd) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       ret = platform_device_add(pd);
-       if (ret)
-               goto fail;
-
-       return ret;
-fail:
-       platform_device_put(pd);
-
-out:
-       return ret;
-
-}
-device_initcall(octeon_mdiobus_device_init);
-
-/* Octeon mgmt port Ethernet interface.  */
-static int __init octeon_mgmt_device_init(void)
-{
-       struct platform_device *pd;
-       int ret = 0;
-       int port, num_ports;
-
-       struct resource mgmt_port_resource = {
-               .flags  = IORESOURCE_IRQ,
-               .start  = -1,
-               .end    = -1
-       };
-
-       if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX))
-               return 0;
-
-       if (OCTEON_IS_MODEL(OCTEON_CN56XX))
-               num_ports = 1;
-       else
-               num_ports = 2;
-
-       for (port = 0; port < num_ports; port++) {
-               pd = platform_device_alloc("octeon_mgmt", port);
-               if (!pd) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               /* No DMA restrictions */
-               pd->dev.coherent_dma_mask = DMA_BIT_MASK(64);
-               pd->dev.dma_mask = &pd->dev.coherent_dma_mask;
-
-               switch (port) {
-               case 0:
-                       mgmt_port_resource.start = OCTEON_IRQ_MII0;
-                       break;
-               case 1:
-                       mgmt_port_resource.start = OCTEON_IRQ_MII1;
-                       break;
-               default:
-                       BUG();
-               }
-               mgmt_port_resource.end = mgmt_port_resource.start;
-
-               ret = platform_device_add_resources(pd, &mgmt_port_resource, 1);
-
-               if (ret)
-                       goto fail;
-
-               ret = platform_device_add(pd);
-               if (ret)
-                       goto fail;
-       }
-       return ret;
-fail:
-       platform_device_put(pd);
-
-out:
-       return ret;
-
-}
-device_initcall(octeon_mgmt_device_init);
-
 #ifdef CONFIG_USB
 
 static int __init octeon_ehci_device_init(void)
@@ -440,6 +270,521 @@ device_initcall(octeon_ohci_device_init);
 
 #endif /* CONFIG_USB */
 
+static struct of_device_id __initdata octeon_ids[] = {
+       { .compatible = "simple-bus", },
+       { .compatible = "cavium,octeon-6335-uctl", },
+       { .compatible = "cavium,octeon-3860-bootbus", },
+       { .compatible = "cavium,mdio-mux", },
+       { .compatible = "gpio-leds", },
+       {},
+};
+
+static bool __init octeon_has_88e1145(void)
+{
+       return !OCTEON_IS_MODEL(OCTEON_CN52XX) &&
+              !OCTEON_IS_MODEL(OCTEON_CN6XXX) &&
+              !OCTEON_IS_MODEL(OCTEON_CN56XX);
+}
+
+static void __init octeon_fdt_set_phy(int eth, int phy_addr)
+{
+       const __be32 *phy_handle;
+       const __be32 *alt_phy_handle;
+       const __be32 *reg;
+       u32 phandle;
+       int phy;
+       int alt_phy;
+       const char *p;
+       int current_len;
+       char new_name[20];
+
+       phy_handle = fdt_getprop(initial_boot_params, eth, "phy-handle", NULL);
+       if (!phy_handle)
+               return;
+
+       phandle = be32_to_cpup(phy_handle);
+       phy = fdt_node_offset_by_phandle(initial_boot_params, phandle);
+
+       alt_phy_handle = fdt_getprop(initial_boot_params, eth, "cavium,alt-phy-handle", NULL);
+       if (alt_phy_handle) {
+               u32 alt_phandle = be32_to_cpup(alt_phy_handle);
+               alt_phy = fdt_node_offset_by_phandle(initial_boot_params, alt_phandle);
+       } else {
+               alt_phy = -1;
+       }
+
+       if (phy_addr < 0 || phy < 0) {
+               /* Delete the PHY things */
+               fdt_nop_property(initial_boot_params, eth, "phy-handle");
+               /* This one may fail */
+               fdt_nop_property(initial_boot_params, eth, "cavium,alt-phy-handle");
+               if (phy >= 0)
+                       fdt_nop_node(initial_boot_params, phy);
+               if (alt_phy >= 0)
+                       fdt_nop_node(initial_boot_params, alt_phy);
+               return;
+       }
+
+       if (phy_addr >= 256 && alt_phy > 0) {
+               const struct fdt_property *phy_prop;
+               struct fdt_property *alt_prop;
+               u32 phy_handle_name;
+
+               /* Use the alt phy node instead.*/
+               phy_prop = fdt_get_property(initial_boot_params, eth, "phy-handle", NULL);
+               phy_handle_name = phy_prop->nameoff;
+               fdt_nop_node(initial_boot_params, phy);
+               fdt_nop_property(initial_boot_params, eth, "phy-handle");
+               alt_prop = fdt_get_property_w(initial_boot_params, eth, "cavium,alt-phy-handle", NULL);
+               alt_prop->nameoff = phy_handle_name;
+               phy = alt_phy;
+       }
+
+       phy_addr &= 0xff;
+
+       if (octeon_has_88e1145()) {
+               fdt_nop_property(initial_boot_params, phy, "marvell,reg-init");
+               memset(new_name, 0, sizeof(new_name));
+               strcpy(new_name, "marvell,88e1145");
+               p = fdt_getprop(initial_boot_params, phy, "compatible",
+                               &current_len);
+               if (p && current_len >= strlen(new_name))
+                       fdt_setprop_inplace(initial_boot_params, phy,
+                                       "compatible", new_name, current_len);
+       }
+
+       reg = fdt_getprop(initial_boot_params, phy, "reg", NULL);
+       if (phy_addr == be32_to_cpup(reg))
+               return;
+
+       fdt_setprop_inplace_cell(initial_boot_params, phy, "reg", phy_addr);
+
+       snprintf(new_name, sizeof(new_name), "ethernet-phy@%x", phy_addr);
+
+       p = fdt_get_name(initial_boot_params, phy, &current_len);
+       if (p && current_len == strlen(new_name))
+               fdt_set_name(initial_boot_params, phy, new_name);
+       else
+               pr_err("Error: could not rename ethernet phy: <%s>", p);
+}
+
+static void __init octeon_fdt_set_mac_addr(int n, u64 *pmac)
+{
+       u8 new_mac[6];
+       u64 mac = *pmac;
+       int r;
+
+       new_mac[0] = (mac >> 40) & 0xff;
+       new_mac[1] = (mac >> 32) & 0xff;
+       new_mac[2] = (mac >> 24) & 0xff;
+       new_mac[3] = (mac >> 16) & 0xff;
+       new_mac[4] = (mac >> 8) & 0xff;
+       new_mac[5] = mac & 0xff;
+
+       r = fdt_setprop_inplace(initial_boot_params, n, "local-mac-address",
+                               new_mac, sizeof(new_mac));
+
+       if (r) {
+               pr_err("Setting \"local-mac-address\" failed %d", r);
+               return;
+       }
+       *pmac = mac + 1;
+}
+
+static void __init octeon_fdt_rm_ethernet(int node)
+{
+       const __be32 *phy_handle;
+
+       phy_handle = fdt_getprop(initial_boot_params, node, "phy-handle", NULL);
+       if (phy_handle) {
+               u32 ph = be32_to_cpup(phy_handle);
+               int p = fdt_node_offset_by_phandle(initial_boot_params, ph);
+               if (p >= 0)
+                       fdt_nop_node(initial_boot_params, p);
+       }
+       fdt_nop_node(initial_boot_params, node);
+}
+
+static void __init octeon_fdt_pip_port(int iface, int i, int p, int max, u64 *pmac)
+{
+       char name_buffer[20];
+       int eth;
+       int phy_addr;
+       int ipd_port;
+
+       snprintf(name_buffer, sizeof(name_buffer), "ethernet@%x", p);
+       eth = fdt_subnode_offset(initial_boot_params, iface, name_buffer);
+       if (eth < 0)
+               return;
+       if (p > max) {
+               pr_debug("Deleting port %x:%x\n", i, p);
+               octeon_fdt_rm_ethernet(eth);
+               return;
+       }
+       if (OCTEON_IS_MODEL(OCTEON_CN68XX))
+               ipd_port = (0x100 * i) + (0x10 * p) + 0x800;
+       else
+               ipd_port = 16 * i + p;
+
+       phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
+       octeon_fdt_set_phy(eth, phy_addr);
+       octeon_fdt_set_mac_addr(eth, pmac);
+}
+
+static void __init octeon_fdt_pip_iface(int pip, int idx, u64 *pmac)
+{
+       char name_buffer[20];
+       int iface;
+       int p;
+       int count;
+
+       count = cvmx_helper_interface_enumerate(idx);
+
+       snprintf(name_buffer, sizeof(name_buffer), "interface@%d", idx);
+       iface = fdt_subnode_offset(initial_boot_params, pip, name_buffer);
+       if (iface < 0)
+               return;
+
+       for (p = 0; p < 16; p++)
+               octeon_fdt_pip_port(iface, idx, p, count - 1, pmac);
+}
+
+int __init octeon_prune_device_tree(void)
+{
+       int i, max_port, uart_mask;
+       const char *pip_path;
+       const char *alias_prop;
+       char name_buffer[20];
+       int aliases;
+       u64 mac_addr_base;
+
+       if (fdt_check_header(initial_boot_params))
+               panic("Corrupt Device Tree.");
+
+       aliases = fdt_path_offset(initial_boot_params, "/aliases");
+       if (aliases < 0) {
+               pr_err("Error: No /aliases node in device tree.");
+               return -EINVAL;
+       }
+
+
+       mac_addr_base =
+               ((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 |
+               ((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 |
+               ((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 |
+               ((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 |
+               ((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 |
+               (octeon_bootinfo->mac_addr_base[5] & 0xffull);
+
+       if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX))
+               max_port = 2;
+       else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX))
+               max_port = 1;
+       else
+               max_port = 0;
+
+       if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E)
+               max_port = 0;
+
+       for (i = 0; i < 2; i++) {
+               int mgmt;
+               snprintf(name_buffer, sizeof(name_buffer),
+                        "mix%d", i);
+               alias_prop = fdt_getprop(initial_boot_params, aliases,
+                                       name_buffer, NULL);
+               if (alias_prop) {
+                       mgmt = fdt_path_offset(initial_boot_params, alias_prop);
+                       if (mgmt < 0)
+                               continue;
+                       if (i >= max_port) {
+                               pr_debug("Deleting mix%d\n", i);
+                               octeon_fdt_rm_ethernet(mgmt);
+                               fdt_nop_property(initial_boot_params, aliases,
+                                                name_buffer);
+                       } else {
+                               int phy_addr = cvmx_helper_board_get_mii_address(CVMX_HELPER_BOARD_MGMT_IPD_PORT + i);
+                               octeon_fdt_set_phy(mgmt, phy_addr);
+                               octeon_fdt_set_mac_addr(mgmt, &mac_addr_base);
+                       }
+               }
+       }
+
+       pip_path = fdt_getprop(initial_boot_params, aliases, "pip", NULL);
+       if (pip_path) {
+               int pip = fdt_path_offset(initial_boot_params, pip_path);
+               if (pip  >= 0)
+                       for (i = 0; i <= 4; i++)
+                               octeon_fdt_pip_iface(pip, i, &mac_addr_base);
+       }
+
+       /* I2C */
+       if (OCTEON_IS_MODEL(OCTEON_CN52XX) ||
+           OCTEON_IS_MODEL(OCTEON_CN63XX) ||
+           OCTEON_IS_MODEL(OCTEON_CN68XX) ||
+           OCTEON_IS_MODEL(OCTEON_CN56XX))
+               max_port = 2;
+       else
+               max_port = 1;
+
+       for (i = 0; i < 2; i++) {
+               int i2c;
+               snprintf(name_buffer, sizeof(name_buffer),
+                        "twsi%d", i);
+               alias_prop = fdt_getprop(initial_boot_params, aliases,
+                                       name_buffer, NULL);
+
+               if (alias_prop) {
+                       i2c = fdt_path_offset(initial_boot_params, alias_prop);
+                       if (i2c < 0)
+                               continue;
+                       if (i >= max_port) {
+                               pr_debug("Deleting twsi%d\n", i);
+                               fdt_nop_node(initial_boot_params, i2c);
+                               fdt_nop_property(initial_boot_params, aliases,
+                                                name_buffer);
+                       }
+               }
+       }
+
+       /* SMI/MDIO */
+       if (OCTEON_IS_MODEL(OCTEON_CN68XX))
+               max_port = 4;
+       else if (OCTEON_IS_MODEL(OCTEON_CN52XX) ||
+                OCTEON_IS_MODEL(OCTEON_CN63XX) ||
+                OCTEON_IS_MODEL(OCTEON_CN56XX))
+               max_port = 2;
+       else
+               max_port = 1;
+
+       for (i = 0; i < 2; i++) {
+               int i2c;
+               snprintf(name_buffer, sizeof(name_buffer),
+                        "smi%d", i);
+               alias_prop = fdt_getprop(initial_boot_params, aliases,
+                                       name_buffer, NULL);
+
+               if (alias_prop) {
+                       i2c = fdt_path_offset(initial_boot_params, alias_prop);
+                       if (i2c < 0)
+                               continue;
+                       if (i >= max_port) {
+                               pr_debug("Deleting smi%d\n", i);
+                               fdt_nop_node(initial_boot_params, i2c);
+                               fdt_nop_property(initial_boot_params, aliases,
+                                                name_buffer);
+                       }
+               }
+       }
+
+       /* Serial */
+       uart_mask = 3;
+
+       /* Right now CN52XX is the only chip with a third uart */
+       if (OCTEON_IS_MODEL(OCTEON_CN52XX))
+               uart_mask |= 4; /* uart2 */
+
+       for (i = 0; i < 3; i++) {
+               int uart;
+               snprintf(name_buffer, sizeof(name_buffer),
+                        "uart%d", i);
+               alias_prop = fdt_getprop(initial_boot_params, aliases,
+                                       name_buffer, NULL);
+
+               if (alias_prop) {
+                       uart = fdt_path_offset(initial_boot_params, alias_prop);
+                       if (uart_mask & (1 << i))
+                               continue;
+                       pr_debug("Deleting uart%d\n", i);
+                       fdt_nop_node(initial_boot_params, uart);
+                       fdt_nop_property(initial_boot_params, aliases,
+                                        name_buffer);
+               }
+       }
+
+       /* Compact Flash */
+       alias_prop = fdt_getprop(initial_boot_params, aliases,
+                                "cf0", NULL);
+       if (alias_prop) {
+               union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg;
+               unsigned long base_ptr, region_base, region_size;
+               unsigned long region1_base = 0;
+               unsigned long region1_size = 0;
+               int cs, bootbus;
+               bool is_16bit = false;
+               bool is_true_ide = false;
+               __be32 new_reg[6];
+               __be32 *ranges;
+               int len;
+
+               int cf = fdt_path_offset(initial_boot_params, alias_prop);
+               base_ptr = 0;
+               if (octeon_bootinfo->major_version == 1
+                       && octeon_bootinfo->minor_version >= 1) {
+                       if (octeon_bootinfo->compact_flash_common_base_addr)
+                               base_ptr = octeon_bootinfo->compact_flash_common_base_addr;
+               } else {
+                       base_ptr = 0x1d000800;
+               }
+
+               if (!base_ptr)
+                       goto no_cf;
+
+               /* Find CS0 region. */
+               for (cs = 0; cs < 8; cs++) {
+                       mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs));
+                       region_base = mio_boot_reg_cfg.s.base << 16;
+                       region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
+                       if (mio_boot_reg_cfg.s.en && base_ptr >= region_base
+                               && base_ptr < region_base + region_size) {
+                               is_16bit = mio_boot_reg_cfg.s.width;
+                               break;
+                       }
+               }
+               if (cs >= 7) {
+                       /* cs and cs + 1 are CS0 and CS1, both must be less than 8. */
+                       goto no_cf;
+               }
+
+               if (!(base_ptr & 0xfffful)) {
+                       /*
+                        * Boot loader signals availability of DMA (true_ide
+                        * mode) by setting low order bits of base_ptr to
+                        * zero.
+                        */
+
+                       /* Asume that CS1 immediately follows. */
+                       mio_boot_reg_cfg.u64 =
+                               cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs + 1));
+                       region1_base = mio_boot_reg_cfg.s.base << 16;
+                       region1_size = (mio_boot_reg_cfg.s.size + 1) << 16;
+                       if (!mio_boot_reg_cfg.s.en)
+                               goto no_cf;
+                       is_true_ide = true;
+
+               } else {
+                       fdt_nop_property(initial_boot_params, cf, "cavium,true-ide");
+                       fdt_nop_property(initial_boot_params, cf, "cavium,dma-engine-handle");
+                       if (!is_16bit) {
+                               __be32 width = cpu_to_be32(8);
+                               fdt_setprop_inplace(initial_boot_params, cf,
+                                               "cavium,bus-width", &width, sizeof(width));
+                       }
+               }
+               new_reg[0] = cpu_to_be32(cs);
+               new_reg[1] = cpu_to_be32(0);
+               new_reg[2] = cpu_to_be32(0x10000);
+               new_reg[3] = cpu_to_be32(cs + 1);
+               new_reg[4] = cpu_to_be32(0);
+               new_reg[5] = cpu_to_be32(0x10000);
+               fdt_setprop_inplace(initial_boot_params, cf,
+                                   "reg",  new_reg, sizeof(new_reg));
+
+               bootbus = fdt_parent_offset(initial_boot_params, cf);
+               if (bootbus < 0)
+                       goto no_cf;
+               ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len);
+               if (!ranges || len < (5 * 8 * sizeof(__be32)))
+                       goto no_cf;
+
+               ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32);
+               ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff);
+               ranges[(cs * 5) + 4] = cpu_to_be32(region_size);
+               if (is_true_ide) {
+                       cs++;
+                       ranges[(cs * 5) + 2] = cpu_to_be32(region1_base >> 32);
+                       ranges[(cs * 5) + 3] = cpu_to_be32(region1_base & 0xffffffff);
+                       ranges[(cs * 5) + 4] = cpu_to_be32(region1_size);
+               }
+               goto end_cf;
+no_cf:
+               fdt_nop_node(initial_boot_params, cf);
+
+end_cf:
+               ;
+       }
+
+       /* 8 char LED */
+       alias_prop = fdt_getprop(initial_boot_params, aliases,
+                                "led0", NULL);
+       if (alias_prop) {
+               union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg;
+               unsigned long base_ptr, region_base, region_size;
+               int cs, bootbus;
+               __be32 new_reg[6];
+               __be32 *ranges;
+               int len;
+               int led = fdt_path_offset(initial_boot_params, alias_prop);
+
+               base_ptr = octeon_bootinfo->led_display_base_addr;
+               if (base_ptr == 0)
+                       goto no_led;
+               /* Find CS0 region. */
+               for (cs = 0; cs < 8; cs++) {
+                       mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs));
+                       region_base = mio_boot_reg_cfg.s.base << 16;
+                       region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
+                       if (mio_boot_reg_cfg.s.en && base_ptr >= region_base
+                               && base_ptr < region_base + region_size)
+                               break;
+               }
+
+               if (cs > 7)
+                       goto no_led;
+
+               new_reg[0] = cpu_to_be32(cs);
+               new_reg[1] = cpu_to_be32(0x20);
+               new_reg[2] = cpu_to_be32(0x20);
+               new_reg[3] = cpu_to_be32(cs);
+               new_reg[4] = cpu_to_be32(0);
+               new_reg[5] = cpu_to_be32(0x20);
+               fdt_setprop_inplace(initial_boot_params, led,
+                                   "reg",  new_reg, sizeof(new_reg));
+
+               bootbus = fdt_parent_offset(initial_boot_params, led);
+               if (bootbus < 0)
+                       goto no_led;
+               ranges = fdt_getprop_w(initial_boot_params, bootbus, "ranges", &len);
+               if (!ranges || len < (5 * 8 * sizeof(__be32)))
+                       goto no_led;
+
+               ranges[(cs * 5) + 2] = cpu_to_be32(region_base >> 32);
+               ranges[(cs * 5) + 3] = cpu_to_be32(region_base & 0xffffffff);
+               ranges[(cs * 5) + 4] = cpu_to_be32(region_size);
+               goto end_led;
+
+no_led:
+               fdt_nop_node(initial_boot_params, led);
+end_led:
+               ;
+       }
+
+       /* OHCI/UHCI USB */
+       alias_prop = fdt_getprop(initial_boot_params, aliases,
+                                "uctl", NULL);
+       if (alias_prop) {
+               int uctl = fdt_path_offset(initial_boot_params, alias_prop);
+
+               if (uctl >= 0 && (!OCTEON_IS_MODEL(OCTEON_CN6XXX) ||
+                                 octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC2E)) {
+                       pr_debug("Deleting uctl\n");
+                       fdt_nop_node(initial_boot_params, uctl);
+                       fdt_nop_property(initial_boot_params, aliases, "uctl");
+               } else if (octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC10E ||
+                          octeon_bootinfo->board_type == CVMX_BOARD_TYPE_NIC4E) {
+                       /* Missing "refclk-type" defaults to crystal. */
+                       fdt_nop_property(initial_boot_params, uctl, "refclk-type");
+               }
+       }
+
+       return 0;
+}
+
+static int __init octeon_publish_devices(void)
+{
+       return of_platform_bus_probe(NULL, octeon_ids, NULL);
+}
+device_initcall(octeon_publish_devices);
+
 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Platform driver for Octeon SOC");
diff --git a/arch/mips/cavium-octeon/octeon_3xxx.dts b/arch/mips/cavium-octeon/octeon_3xxx.dts
new file mode 100644 (file)
index 0000000..f28b2d0
--- /dev/null
@@ -0,0 +1,571 @@
+/dts-v1/;
+/*
+ * OCTEON 3XXX, 5XXX, 63XX device tree skeleton.
+ *
+ * This device tree is pruned and patched by early boot code before
+ * use.  Because of this, it contains a super-set of the available
+ * devices and properties.
+ */
+/ {
+       compatible = "cavium,octeon-3860";
+       #address-cells = <2>;
+       #size-cells = <2>;
+       interrupt-parent = <&ciu>;
+
+       soc@0 {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges; /* Direct mapping */
+
+               ciu: interrupt-controller@1070000000000 {
+                       compatible = "cavium,octeon-3860-ciu";
+                       interrupt-controller;
+                       /* Interrupts are specified by two parts:
+                        * 1) Controller register (0 or 1)
+                        * 2) Bit within the register (0..63)
+                        */
+                       #interrupt-cells = <2>;
+                       reg = <0x10700 0x00000000 0x0 0x7000>;
+               };
+
+               gpio: gpio-controller@1070000000800 {
+                       #gpio-cells = <2>;
+                       compatible = "cavium,octeon-3860-gpio";
+                       reg = <0x10700 0x00000800 0x0 0x100>;
+                       gpio-controller;
+                       /* Interrupts are specified by two parts:
+                        * 1) GPIO pin number (0..15)
+                        * 2) Triggering (1 - edge rising
+                        *                2 - edge falling
+                        *                4 - level active high
+                        *                8 - level active low)
+                        */
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       /* The GPIO pin connect to 16 consecutive CUI bits */
+                       interrupts = <0 16>, <0 17>, <0 18>, <0 19>,
+                                    <0 20>, <0 21>, <0 22>, <0 23>,
+                                    <0 24>, <0 25>, <0 26>, <0 27>,
+                                    <0 28>, <0 29>, <0 30>, <0 31>;
+               };
+
+               smi0: mdio@1180000001800 {
+                       compatible = "cavium,octeon-3860-mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x11800 0x00001800 0x0 0x40>;
+
+                       phy0: ethernet-phy@0 {
+                               compatible = "marvell,88e1118";
+                               marvell,reg-init =
+                                       /* Fix rx and tx clock transition timing */
+                                       <2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */
+                                       /* Adjust LED drive. */
+                                       <3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */
+                                       /* irq, blink-activity, blink-link */
+                                       <3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */
+                               reg = <0>;
+                       };
+
+                       phy1: ethernet-phy@1 {
+                               compatible = "marvell,88e1118";
+                               marvell,reg-init =
+                                       /* Fix rx and tx clock transition timing */
+                                       <2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */
+                                       /* Adjust LED drive. */
+                                       <3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */
+                                       /* irq, blink-activity, blink-link */
+                                       <3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */
+                               reg = <1>;
+                       };
+
+                       phy2: ethernet-phy@2 {
+                               reg = <2>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy3: ethernet-phy@3 {
+                               reg = <3>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy4: ethernet-phy@4 {
+                               reg = <4>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy5: ethernet-phy@5 {
+                               reg = <5>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+
+                       phy6: ethernet-phy@6 {
+                               reg = <6>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy7: ethernet-phy@7 {
+                               reg = <7>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy8: ethernet-phy@8 {
+                               reg = <8>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy9: ethernet-phy@9 {
+                               reg = <9>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+               };
+
+               smi1: mdio@1180000001900 {
+                       compatible = "cavium,octeon-3860-mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x11800 0x00001900 0x0 0x40>;
+
+                       phy100: ethernet-phy@1 {
+                               reg = <1>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                               interrupt-parent = <&gpio>;
+                               interrupts = <12 8>; /* Pin 12, active low */
+                       };
+                       phy101: ethernet-phy@2 {
+                               reg = <2>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                               interrupt-parent = <&gpio>;
+                               interrupts = <12 8>; /* Pin 12, active low */
+                       };
+                       phy102: ethernet-phy@3 {
+                               reg = <3>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                               interrupt-parent = <&gpio>;
+                               interrupts = <12 8>; /* Pin 12, active low */
+                       };
+                       phy103: ethernet-phy@4 {
+                               reg = <4>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                               interrupt-parent = <&gpio>;
+                               interrupts = <12 8>; /* Pin 12, active low */
+                       };
+               };
+
+               mix0: ethernet@1070000100000 {
+                       compatible = "cavium,octeon-5750-mix";
+                       reg = <0x10700 0x00100000 0x0 0x100>, /* MIX */
+                             <0x11800 0xE0000000 0x0 0x300>, /* AGL */
+                             <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED  */
+                             <0x11800 0xE0002000 0x0 0x8>;   /* AGL_PRT_CTL */
+                       cell-index = <0>;
+                       interrupts = <0 62>, <1 46>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       phy-handle = <&phy0>;
+               };
+
+               mix1: ethernet@1070000100800 {
+                       compatible = "cavium,octeon-5750-mix";
+                       reg = <0x10700 0x00100800 0x0 0x100>, /* MIX */
+                             <0x11800 0xE0000800 0x0 0x300>, /* AGL */
+                             <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED  */
+                             <0x11800 0xE0002008 0x0 0x8>;   /* AGL_PRT_CTL */
+                       cell-index = <1>;
+                       interrupts = <1 18>, < 1 46>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       phy-handle = <&phy1>;
+               };
+
+               pip: pip@11800a0000000 {
+                       compatible = "cavium,octeon-3860-pip";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x11800 0xa0000000 0x0 0x2000>;
+
+                       interface@0 {
+                               compatible = "cavium,octeon-3860-pip-interface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0>; /* interface */
+
+                               ethernet@0 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x0>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy2>;
+                                       cavium,alt-phy-handle = <&phy100>;
+                               };
+                               ethernet@1 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x1>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy3>;
+                                       cavium,alt-phy-handle = <&phy101>;
+                               };
+                               ethernet@2 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x2>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy4>;
+                                       cavium,alt-phy-handle = <&phy102>;
+                               };
+                               ethernet@3 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x3>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy5>;
+                                       cavium,alt-phy-handle = <&phy103>;
+                               };
+                               ethernet@4 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x4>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                               ethernet@5 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x5>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                               ethernet@6 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x6>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                               ethernet@7 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x7>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                               ethernet@8 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x8>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                               ethernet@9 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x9>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                               ethernet@a {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0xa>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                               ethernet@b {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0xb>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                               ethernet@c {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0xc>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                               ethernet@d {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0xd>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                               ethernet@e {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0xe>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                               ethernet@f {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0xf>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                       };
+
+                       interface@1 {
+                               compatible = "cavium,octeon-3860-pip-interface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <1>; /* interface */
+
+                               ethernet@0 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x0>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy6>;
+                               };
+                               ethernet@1 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x1>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy7>;
+                               };
+                               ethernet@2 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x2>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy8>;
+                               };
+                               ethernet@3 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x3>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy9>;
+                               };
+                       };
+               };
+
+               twsi0: i2c@1180000001000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "cavium,octeon-3860-twsi";
+                       reg = <0x11800 0x00001000 0x0 0x200>;
+                       interrupts = <0 45>;
+                       clock-frequency = <100000>;
+
+                       rtc@68 {
+                               compatible = "dallas,ds1337";
+                               reg = <0x68>;
+                       };
+                       tmp@4c {
+                               compatible = "ti,tmp421";
+                               reg = <0x4c>;
+                       };
+               };
+
+               twsi1: i2c@1180000001200 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "cavium,octeon-3860-twsi";
+                       reg = <0x11800 0x00001200 0x0 0x200>;
+                       interrupts = <0 59>;
+                       clock-frequency = <100000>;
+               };
+
+               uart0: serial@1180000000800 {
+                       compatible = "cavium,octeon-3860-uart","ns16550";
+                       reg = <0x11800 0x00000800 0x0 0x400>;
+                       clock-frequency = <0>;
+                       current-speed = <115200>;
+                       reg-shift = <3>;
+                       interrupts = <0 34>;
+               };
+
+               uart1: serial@1180000000c00 {
+                       compatible = "cavium,octeon-3860-uart","ns16550";
+                       reg = <0x11800 0x00000c00 0x0 0x400>;
+                       clock-frequency = <0>;
+                       current-speed = <115200>;
+                       reg-shift = <3>;
+                       interrupts = <0 35>;
+               };
+
+               uart2: serial@1180000000400 {
+                       compatible = "cavium,octeon-3860-uart","ns16550";
+                       reg = <0x11800 0x00000400 0x0 0x400>;
+                       clock-frequency = <0>;
+                       current-speed = <115200>;
+                       reg-shift = <3>;
+                       interrupts = <1 16>;
+               };
+
+               bootbus: bootbus@1180000000000 {
+                       compatible = "cavium,octeon-3860-bootbus";
+                       reg = <0x11800 0x00000000 0x0 0x200>;
+                       /* The chip select number and offset */
+                       #address-cells = <2>;
+                       /* The size of the chip select region */
+                       #size-cells = <1>;
+                       ranges = <0 0  0x0 0x1f400000  0xc00000>,
+                                <1 0  0x10000 0x30000000  0>,
+                                <2 0  0x10000 0x40000000  0>,
+                                <3 0  0x10000 0x50000000  0>,
+                                <4 0  0x0 0x1d020000  0x10000>,
+                                <5 0  0x0 0x1d040000  0x10000>,
+                                <6 0  0x0 0x1d050000  0x10000>,
+                                <7 0  0x10000 0x90000000  0>;
+
+                       cavium,cs-config@0 {
+                               compatible = "cavium,octeon-3860-bootbus-config";
+                               cavium,cs-index = <0>;
+                               cavium,t-adr  = <20>;
+                               cavium,t-ce   = <60>;
+                               cavium,t-oe   = <60>;
+                               cavium,t-we   = <45>;
+                               cavium,t-rd-hld = <35>;
+                               cavium,t-wr-hld = <45>;
+                               cavium,t-pause  = <0>;
+                               cavium,t-wait   = <0>;
+                               cavium,t-page   = <35>;
+                               cavium,t-rd-dly = <0>;
+
+                               cavium,pages     = <0>;
+                               cavium,bus-width = <8>;
+                       };
+                       cavium,cs-config@4 {
+                               compatible = "cavium,octeon-3860-bootbus-config";
+                               cavium,cs-index = <4>;
+                               cavium,t-adr  = <320>;
+                               cavium,t-ce   = <320>;
+                               cavium,t-oe   = <320>;
+                               cavium,t-we   = <320>;
+                               cavium,t-rd-hld = <320>;
+                               cavium,t-wr-hld = <320>;
+                               cavium,t-pause  = <320>;
+                               cavium,t-wait   = <320>;
+                               cavium,t-page   = <320>;
+                               cavium,t-rd-dly = <0>;
+
+                               cavium,pages     = <0>;
+                               cavium,bus-width = <8>;
+                       };
+                       cavium,cs-config@5 {
+                               compatible = "cavium,octeon-3860-bootbus-config";
+                               cavium,cs-index = <5>;
+                               cavium,t-adr  = <5>;
+                               cavium,t-ce   = <300>;
+                               cavium,t-oe   = <125>;
+                               cavium,t-we   = <150>;
+                               cavium,t-rd-hld = <100>;
+                               cavium,t-wr-hld = <30>;
+                               cavium,t-pause  = <0>;
+                               cavium,t-wait   = <30>;
+                               cavium,t-page   = <320>;
+                               cavium,t-rd-dly = <0>;
+
+                               cavium,pages     = <0>;
+                               cavium,bus-width = <16>;
+                       };
+                       cavium,cs-config@6 {
+                               compatible = "cavium,octeon-3860-bootbus-config";
+                               cavium,cs-index = <6>;
+                               cavium,t-adr  = <5>;
+                               cavium,t-ce   = <300>;
+                               cavium,t-oe   = <270>;
+                               cavium,t-we   = <150>;
+                               cavium,t-rd-hld = <100>;
+                               cavium,t-wr-hld = <70>;
+                               cavium,t-pause  = <0>;
+                               cavium,t-wait   = <0>;
+                               cavium,t-page   = <320>;
+                               cavium,t-rd-dly = <0>;
+
+                               cavium,pages     = <0>;
+                               cavium,wait-mode;
+                               cavium,bus-width = <16>;
+                       };
+
+                       flash0: nor@0,0 {
+                               compatible = "cfi-flash";
+                               reg = <0 0 0x800000>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                       };
+
+                       led0: led-display@4,0 {
+                               compatible = "avago,hdsp-253x";
+                               reg = <4 0x20 0x20>, <4 0 0x20>;
+                       };
+
+                       cf0: compact-flash@5,0 {
+                               compatible = "cavium,ebt3000-compact-flash";
+                               reg = <5 0 0x10000>, <6 0 0x10000>;
+                               cavium,bus-width = <16>;
+                               cavium,true-ide;
+                               cavium,dma-engine-handle = <&dma0>;
+                       };
+               };
+
+               dma0: dma-engine@1180000000100 {
+                       compatible = "cavium,octeon-5750-bootbus-dma";
+                       reg = <0x11800 0x00000100 0x0 0x8>;
+                       interrupts = <0 63>;
+               };
+               dma1: dma-engine@1180000000108 {
+                       compatible = "cavium,octeon-5750-bootbus-dma";
+                       reg = <0x11800 0x00000108 0x0 0x8>;
+                       interrupts = <0 63>;
+               };
+
+               uctl: uctl@118006f000000 {
+                       compatible = "cavium,octeon-6335-uctl";
+                       reg = <0x11800 0x6f000000 0x0 0x100>;
+                       ranges; /* Direct mapping */
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       /* 12MHz, 24MHz and 48MHz allowed */
+                       refclk-frequency = <12000000>;
+                       /* Either "crystal" or "external" */
+                       refclk-type = "crystal";
+
+                       ehci@16f0000000000 {
+                               compatible = "cavium,octeon-6335-ehci","usb-ehci";
+                               reg = <0x16f00 0x00000000 0x0 0x100>;
+                               interrupts = <0 56>;
+                               big-endian-regs;
+                       };
+                       ohci@16f0000000400 {
+                               compatible = "cavium,octeon-6335-ohci","usb-ohci";
+                               reg = <0x16f00 0x00000400 0x0 0x100>;
+                               interrupts = <0 56>;
+                               big-endian-regs;
+                       };
+               };
+       };
+
+       aliases {
+               mix0 = &mix0;
+               mix1 = &mix1;
+               pip = &pip;
+               smi0 = &smi0;
+               smi1 = &smi1;
+               twsi0 = &twsi0;
+               twsi1 = &twsi1;
+               uart0 = &uart0;
+               uart1 = &uart1;
+               uart2 = &uart2;
+               flash0 = &flash0;
+               cf0 = &cf0;
+               uctl = &uctl;
+               led0 = &led0;
+       };
+ };
diff --git a/arch/mips/cavium-octeon/octeon_68xx.dts b/arch/mips/cavium-octeon/octeon_68xx.dts
new file mode 100644 (file)
index 0000000..1839468
--- /dev/null
@@ -0,0 +1,625 @@
+/dts-v1/;
+/*
+ * OCTEON 68XX device tree skeleton.
+ *
+ * This device tree is pruned and patched by early boot code before
+ * use.  Because of this, it contains a super-set of the available
+ * devices and properties.
+ */
+/ {
+       compatible = "cavium,octeon-6880";
+       #address-cells = <2>;
+       #size-cells = <2>;
+       interrupt-parent = <&ciu2>;
+
+       soc@0 {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges; /* Direct mapping */
+
+               ciu2: interrupt-controller@1070100000000 {
+                       compatible = "cavium,octeon-6880-ciu2";
+                       interrupt-controller;
+                       /* Interrupts are specified by two parts:
+                        * 1) Controller register (0 or 7)
+                        * 2) Bit within the register (0..63)
+                        */
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0x10701 0x00000000 0x0 0x4000000>;
+               };
+
+               gpio: gpio-controller@1070000000800 {
+                       #gpio-cells = <2>;
+                       compatible = "cavium,octeon-3860-gpio";
+                       reg = <0x10700 0x00000800 0x0 0x100>;
+                       gpio-controller;
+                       /* Interrupts are specified by two parts:
+                        * 1) GPIO pin number (0..15)
+                        * 2) Triggering (1 - edge rising
+                        *                2 - edge falling
+                        *                4 - level active high
+                        *                8 - level active low)
+                        */
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       /* The GPIO pins connect to 16 consecutive CUI bits */
+                       interrupts = <7 0>,  <7 1>,  <7 2>,  <7 3>,
+                                    <7 4>,  <7 5>,  <7 6>,  <7 7>,
+                                    <7 8>,  <7 9>,  <7 10>, <7 11>,
+                                    <7 12>, <7 13>, <7 14>, <7 15>;
+               };
+
+               smi0: mdio@1180000003800 {
+                       compatible = "cavium,octeon-3860-mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x11800 0x00003800 0x0 0x40>;
+
+                       phy0: ethernet-phy@6 {
+                               compatible = "marvell,88e1118";
+                               marvell,reg-init =
+                                       /* Fix rx and tx clock transition timing */
+                                       <2 0x15 0xffcf 0>, /* Reg 2,21 Clear bits 4, 5 */
+                                       /* Adjust LED drive. */
+                                       <3 0x11 0 0x442a>, /* Reg 3,17 <- 0442a */
+                                       /* irq, blink-activity, blink-link */
+                                       <3 0x10 0 0x0242>; /* Reg 3,16 <- 0x0242 */
+                               reg = <6>;
+                       };
+
+                       phy1: ethernet-phy@1 {
+                               cavium,qlm-trim = "4,sgmii";
+                               reg = <1>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy2: ethernet-phy@2 {
+                               cavium,qlm-trim = "4,sgmii";
+                               reg = <2>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy3: ethernet-phy@3 {
+                               cavium,qlm-trim = "4,sgmii";
+                               reg = <3>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy4: ethernet-phy@4 {
+                               cavium,qlm-trim = "4,sgmii";
+                               reg = <4>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+               };
+
+               smi1: mdio@1180000003880 {
+                       compatible = "cavium,octeon-3860-mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x11800 0x00003880 0x0 0x40>;
+
+                       phy41: ethernet-phy@1 {
+                               cavium,qlm-trim = "0,sgmii";
+                               reg = <1>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy42: ethernet-phy@2 {
+                               cavium,qlm-trim = "0,sgmii";
+                               reg = <2>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy43: ethernet-phy@3 {
+                               cavium,qlm-trim = "0,sgmii";
+                               reg = <3>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy44: ethernet-phy@4 {
+                               cavium,qlm-trim = "0,sgmii";
+                               reg = <4>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+               };
+
+               smi2: mdio@1180000003900 {
+                       compatible = "cavium,octeon-3860-mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x11800 0x00003900 0x0 0x40>;
+
+                       phy21: ethernet-phy@1 {
+                               cavium,qlm-trim = "2,sgmii";
+                               reg = <1>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy22: ethernet-phy@2 {
+                               cavium,qlm-trim = "2,sgmii";
+                               reg = <2>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy23: ethernet-phy@3 {
+                               cavium,qlm-trim = "2,sgmii";
+                               reg = <3>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy24: ethernet-phy@4 {
+                               cavium,qlm-trim = "2,sgmii";
+                               reg = <4>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+               };
+
+               smi3: mdio@1180000003980 {
+                       compatible = "cavium,octeon-3860-mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x11800 0x00003980 0x0 0x40>;
+
+                       phy11: ethernet-phy@1 {
+                               cavium,qlm-trim = "3,sgmii";
+                               reg = <1>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy12: ethernet-phy@2 {
+                               cavium,qlm-trim = "3,sgmii";
+                               reg = <2>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy13: ethernet-phy@3 {
+                               cavium,qlm-trim = "3,sgmii";
+                               reg = <3>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+                       phy14: ethernet-phy@4 {
+                               cavium,qlm-trim = "3,sgmii";
+                               reg = <4>;
+                               compatible = "marvell,88e1149r";
+                               marvell,reg-init = <3 0x10 0 0x5777>,
+                                       <3 0x11 0 0x00aa>,
+                                       <3 0x12 0 0x4105>,
+                                       <3 0x13 0 0x0a60>;
+                       };
+               };
+
+               mix0: ethernet@1070000100000 {
+                       compatible = "cavium,octeon-5750-mix";
+                       reg = <0x10700 0x00100000 0x0 0x100>, /* MIX */
+                             <0x11800 0xE0000000 0x0 0x300>, /* AGL */
+                             <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED  */
+                             <0x11800 0xE0002000 0x0 0x8>;   /* AGL_PRT_CTL */
+                       cell-index = <0>;
+                       interrupts = <6 40>, <6 32>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       phy-handle = <&phy0>;
+               };
+
+               pip: pip@11800a0000000 {
+                       compatible = "cavium,octeon-3860-pip";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x11800 0xa0000000 0x0 0x2000>;
+
+                       interface@4 {
+                               compatible = "cavium,octeon-3860-pip-interface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x4>; /* interface */
+
+                               ethernet@0 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x0>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy1>;
+                               };
+                               ethernet@1 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x1>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy2>;
+                               };
+                               ethernet@2 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x2>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy3>;
+                               };
+                               ethernet@3 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x3>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy4>;
+                               };
+                       };
+
+                       interface@3 {
+                               compatible = "cavium,octeon-3860-pip-interface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x3>; /* interface */
+
+                               ethernet@0 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x0>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy11>;
+                               };
+                               ethernet@1 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x1>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy12>;
+                               };
+                               ethernet@2 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x2>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy13>;
+                               };
+                               ethernet@3 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x3>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy14>;
+                               };
+                       };
+
+                       interface@2 {
+                               compatible = "cavium,octeon-3860-pip-interface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x2>; /* interface */
+
+                               ethernet@0 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x0>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy21>;
+                               };
+                               ethernet@1 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x1>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy22>;
+                               };
+                               ethernet@2 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x2>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy23>;
+                               };
+                               ethernet@3 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x3>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy24>;
+                               };
+                       };
+
+                       interface@1 {
+                               compatible = "cavium,octeon-3860-pip-interface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x1>; /* interface */
+
+                               ethernet@0 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x0>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                               };
+                       };
+
+                       interface@0 {
+                               compatible = "cavium,octeon-3860-pip-interface";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               reg = <0x0>; /* interface */
+
+                               ethernet@0 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x0>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy41>;
+                               };
+                               ethernet@1 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x1>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy42>;
+                               };
+                               ethernet@2 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x2>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy43>;
+                               };
+                               ethernet@3 {
+                                       compatible = "cavium,octeon-3860-pip-port";
+                                       reg = <0x3>; /* Port */
+                                       local-mac-address = [ 00 00 00 00 00 00 ];
+                                       phy-handle = <&phy44>;
+                               };
+                       };
+               };
+
+               twsi0: i2c@1180000001000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "cavium,octeon-3860-twsi";
+                       reg = <0x11800 0x00001000 0x0 0x200>;
+                       interrupts = <3 32>;
+                       clock-frequency = <100000>;
+
+                       rtc@68 {
+                               compatible = "dallas,ds1337";
+                               reg = <0x68>;
+                       };
+                       tmp@4c {
+                               compatible = "ti,tmp421";
+                               reg = <0x4c>;
+                       };
+               };
+
+               twsi1: i2c@1180000001200 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "cavium,octeon-3860-twsi";
+                       reg = <0x11800 0x00001200 0x0 0x200>;
+                       interrupts = <3 33>;
+                       clock-frequency = <100000>;
+               };
+
+               uart0: serial@1180000000800 {
+                       compatible = "cavium,octeon-3860-uart","ns16550";
+                       reg = <0x11800 0x00000800 0x0 0x400>;
+                       clock-frequency = <0>;
+                       current-speed = <115200>;
+                       reg-shift = <3>;
+                       interrupts = <3 36>;
+               };
+
+               uart1: serial@1180000000c00 {
+                       compatible = "cavium,octeon-3860-uart","ns16550";
+                       reg = <0x11800 0x00000c00 0x0 0x400>;
+                       clock-frequency = <0>;
+                       current-speed = <115200>;
+                       reg-shift = <3>;
+                       interrupts = <3 37>;
+               };
+
+               bootbus: bootbus@1180000000000 {
+                       compatible = "cavium,octeon-3860-bootbus";
+                       reg = <0x11800 0x00000000 0x0 0x200>;
+                       /* The chip select number and offset */
+                       #address-cells = <2>;
+                       /* The size of the chip select region */
+                       #size-cells = <1>;
+                       ranges = <0 0  0       0x1f400000  0xc00000>,
+                                <1 0  0x10000 0x30000000  0>,
+                                <2 0  0x10000 0x40000000  0>,
+                                <3 0  0x10000 0x50000000  0>,
+                                <4 0  0       0x1d020000  0x10000>,
+                                <5 0  0       0x1d040000  0x10000>,
+                                <6 0  0       0x1d050000  0x10000>,
+                                <7 0  0x10000 0x90000000  0>;
+
+                       cavium,cs-config@0 {
+                               compatible = "cavium,octeon-3860-bootbus-config";
+                               cavium,cs-index = <0>;
+                               cavium,t-adr  = <10>;
+                               cavium,t-ce   = <50>;
+                               cavium,t-oe   = <50>;
+                               cavium,t-we   = <35>;
+                               cavium,t-rd-hld = <25>;
+                               cavium,t-wr-hld = <35>;
+                               cavium,t-pause  = <0>;
+                               cavium,t-wait   = <300>;
+                               cavium,t-page   = <25>;
+                               cavium,t-rd-dly = <0>;
+
+                               cavium,pages     = <0>;
+                               cavium,bus-width = <8>;
+                       };
+                       cavium,cs-config@4 {
+                               compatible = "cavium,octeon-3860-bootbus-config";
+                               cavium,cs-index = <4>;
+                               cavium,t-adr  = <320>;
+                               cavium,t-ce   = <320>;
+                               cavium,t-oe   = <320>;
+                               cavium,t-we   = <320>;
+                               cavium,t-rd-hld = <320>;
+                               cavium,t-wr-hld = <320>;
+                               cavium,t-pause  = <320>;
+                               cavium,t-wait   = <320>;
+                               cavium,t-page   = <320>;
+                               cavium,t-rd-dly = <0>;
+
+                               cavium,pages     = <0>;
+                               cavium,bus-width = <8>;
+                       };
+                       cavium,cs-config@5 {
+                               compatible = "cavium,octeon-3860-bootbus-config";
+                               cavium,cs-index = <5>;
+                               cavium,t-adr  = <0>;
+                               cavium,t-ce   = <300>;
+                               cavium,t-oe   = <125>;
+                               cavium,t-we   = <150>;
+                               cavium,t-rd-hld = <100>;
+                               cavium,t-wr-hld = <300>;
+                               cavium,t-pause  = <0>;
+                               cavium,t-wait   = <300>;
+                               cavium,t-page   = <310>;
+                               cavium,t-rd-dly = <0>;
+
+                               cavium,pages     = <0>;
+                               cavium,bus-width = <16>;
+                       };
+                       cavium,cs-config@6 {
+                               compatible = "cavium,octeon-3860-bootbus-config";
+                               cavium,cs-index = <6>;
+                               cavium,t-adr  = <0>;
+                               cavium,t-ce   = <30>;
+                               cavium,t-oe   = <125>;
+                               cavium,t-we   = <150>;
+                               cavium,t-rd-hld = <100>;
+                               cavium,t-wr-hld = <30>;
+                               cavium,t-pause  = <0>;
+                               cavium,t-wait   = <30>;
+                               cavium,t-page   = <310>;
+                               cavium,t-rd-dly = <0>;
+
+                               cavium,pages     = <0>;
+                               cavium,wait-mode;
+                               cavium,bus-width = <16>;
+                       };
+
+                       flash0: nor@0,0 {
+                               compatible = "cfi-flash";
+                               reg = <0 0 0x800000>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               partition@0 {
+                                       label = "bootloader";
+                                       reg = <0 0x200000>;
+                                       read-only;
+                               };
+                               partition@200000 {
+                                       label = "kernel";
+                                       reg = <0x200000 0x200000>;
+                               };
+                               partition@400000 {
+                                       label = "cramfs";
+                                       reg = <0x400000 0x3fe000>;
+                               };
+                               partition@7fe000 {
+                                       label = "environment";
+                                       reg = <0x7fe000 0x2000>;
+                                       read-only;
+                               };
+                       };
+
+                       led0: led-display@4,0 {
+                               compatible = "avago,hdsp-253x";
+                               reg = <4 0x20 0x20>, <4 0 0x20>;
+                       };
+
+                       compact-flash@5,0 {
+                               compatible = "cavium,ebt3000-compact-flash";
+                               reg = <5 0 0x10000>, <6 0 0x10000>;
+                               cavium,bus-width = <16>;
+                               cavium,true-ide;
+                               cavium,dma-engine-handle = <&dma0>;
+                       };
+               };
+
+               dma0: dma-engine@1180000000100 {
+                       compatible = "cavium,octeon-5750-bootbus-dma";
+                       reg = <0x11800 0x00000100 0x0 0x8>;
+                       interrupts = <0 63>;
+               };
+               dma1: dma-engine@1180000000108 {
+                       compatible = "cavium,octeon-5750-bootbus-dma";
+                       reg = <0x11800 0x00000108 0x0 0x8>;
+                       interrupts = <0 63>;
+               };
+
+               uctl: uctl@118006f000000 {
+                       compatible = "cavium,octeon-6335-uctl";
+                       reg = <0x11800 0x6f000000 0x0 0x100>;
+                       ranges; /* Direct mapping */
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       /* 12MHz, 24MHz and 48MHz allowed */
+                       refclk-frequency = <12000000>;
+                       /* Either "crystal" or "external" */
+                       refclk-type = "crystal";
+
+                       ehci@16f0000000000 {
+                               compatible = "cavium,octeon-6335-ehci","usb-ehci";
+                               reg = <0x16f00 0x00000000 0x0 0x100>;
+                               interrupts = <3 44>;
+                               big-endian-regs;
+                       };
+                       ohci@16f0000000400 {
+                               compatible = "cavium,octeon-6335-ohci","usb-ohci";
+                               reg = <0x16f00 0x00000400 0x0 0x100>;
+                               interrupts = <3 44>;
+                               big-endian-regs;
+                       };
+               };
+       };
+
+       aliases {
+               mix0 = &mix0;
+               pip = &pip;
+               smi0 = &smi0;
+               smi1 = &smi1;
+               smi2 = &smi2;
+               smi3 = &smi3;
+               twsi0 = &twsi0;
+               twsi1 = &twsi1;
+               uart0 = &uart0;
+               uart1 = &uart1;
+               uctl = &uctl;
+               led0 = &led0;
+               flash0 = &flash0;
+       };
+ };
index 057f0ae88c994e6052892d4fc44620c0da7d26fa..138b2216b4f8ba396be6ae788e9a9b3215a13630 100644 (file)
@@ -43,95 +43,67 @@ void octeon_serial_out(struct uart_port *up, int offset, int value)
        cvmx_write_csr((uint64_t)(up->membase + (offset << 3)), (u8)value);
 }
 
-/*
- * Allocated in .bss, so it is all zeroed.
- */
-#define OCTEON_MAX_UARTS 3
-static struct plat_serial8250_port octeon_uart8250_data[OCTEON_MAX_UARTS + 1];
-static struct platform_device octeon_uart8250_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_PLATFORM,
-       .dev                    = {
-               .platform_data  = octeon_uart8250_data,
-       },
-};
-
-static void __init octeon_uart_set_common(struct plat_serial8250_port *p)
+static int __devinit octeon_serial_probe(struct platform_device *pdev)
 {
-       p->flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
-       p->type = PORT_OCTEON;
-       p->iotype = UPIO_MEM;
-       p->regshift = 3;        /* I/O addresses are every 8 bytes */
+       int irq, res;
+       struct resource *res_mem;
+       struct uart_port port;
+
+       /* All adaptors have an irq.  */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       memset(&port, 0, sizeof(port));
+
+       port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+       port.type = PORT_OCTEON;
+       port.iotype = UPIO_MEM;
+       port.regshift = 3;
+       port.dev = &pdev->dev;
+
        if (octeon_is_simulation())
                /* Make simulator output fast*/
-               p->uartclk = 115200 * 16;
+               port.uartclk = 115200 * 16;
        else
-               p->uartclk = octeon_get_io_clock_rate();
-       p->serial_in = octeon_serial_in;
-       p->serial_out = octeon_serial_out;
-}
+               port.uartclk = octeon_get_io_clock_rate();
 
-static int __init octeon_serial_init(void)
-{
-       int enable_uart0;
-       int enable_uart1;
-       int enable_uart2;
-       struct plat_serial8250_port *p;
-
-#ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL
-       /*
-        * If we are configured to run as the second of two kernels,
-        * disable uart0 and enable uart1. Uart0 is owned by the first
-        * kernel
-        */
-       enable_uart0 = 0;
-       enable_uart1 = 1;
-#else
-       /*
-        * We are configured for the first kernel. We'll enable uart0
-        * if the bootloader told us to use 0, otherwise will enable
-        * uart 1.
-        */
-       enable_uart0 = (octeon_get_boot_uart() == 0);
-       enable_uart1 = (octeon_get_boot_uart() == 1);
-#ifdef CONFIG_KGDB
-       enable_uart1 = 1;
-#endif
-#endif
-
-       /* Right now CN52XX is the only chip with a third uart */
-       enable_uart2 = OCTEON_IS_MODEL(OCTEON_CN52XX);
-
-       p = octeon_uart8250_data;
-       if (enable_uart0) {
-               /* Add a ttyS device for hardware uart 0 */
-               octeon_uart_set_common(p);
-               p->membase = (void *) CVMX_MIO_UARTX_RBR(0);
-               p->mapbase = CVMX_MIO_UARTX_RBR(0) & ((1ull << 49) - 1);
-               p->irq = OCTEON_IRQ_UART0;
-               p++;
-       }
+       port.serial_in = octeon_serial_in;
+       port.serial_out = octeon_serial_out;
+       port.irq = irq;
 
-       if (enable_uart1) {
-               /* Add a ttyS device for hardware uart 1 */
-               octeon_uart_set_common(p);
-               p->membase = (void *) CVMX_MIO_UARTX_RBR(1);
-               p->mapbase = CVMX_MIO_UARTX_RBR(1) & ((1ull << 49) - 1);
-               p->irq = OCTEON_IRQ_UART1;
-               p++;
-       }
-       if (enable_uart2) {
-               /* Add a ttyS device for hardware uart 2 */
-               octeon_uart_set_common(p);
-               p->membase = (void *) CVMX_MIO_UART2_RBR;
-               p->mapbase = CVMX_MIO_UART2_RBR & ((1ull << 49) - 1);
-               p->irq = OCTEON_IRQ_UART2;
-               p++;
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res_mem == NULL) {
+               dev_err(&pdev->dev, "found no memory resource\n");
+               return -ENXIO;
        }
+       port.mapbase = res_mem->start;
+       port.membase = ioremap(res_mem->start, resource_size(res_mem));
 
-       BUG_ON(p > &octeon_uart8250_data[OCTEON_MAX_UARTS]);
+       res = serial8250_register_port(&port);
 
-       return platform_device_register(&octeon_uart8250_device);
+       return res >= 0 ? 0 : res;
 }
 
-device_initcall(octeon_serial_init);
+static struct of_device_id octeon_serial_match[] = {
+       {
+               .compatible = "cavium,octeon-3860-uart",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, octeon_serial_match);
+
+static struct platform_driver octeon_serial_driver = {
+       .probe          = octeon_serial_probe,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "octeon_serial",
+               .of_match_table = octeon_serial_match,
+       },
+};
+
+static int __init octeon_serial_init(void)
+{
+       return platform_driver_register(&octeon_serial_driver);
+}
+late_initcall(octeon_serial_init);
index 260dc247c052ca5874c23594f0db926a7fcfb1eb..919b0fb7bb1a779d77551d9743fe9d321fb6b9c3 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt.h>
 
 #include <asm/processor.h>
 #include <asm/reboot.h>
@@ -775,3 +777,46 @@ void prom_free_prom_memory(void)
        }
 #endif
 }
+
+int octeon_prune_device_tree(void);
+
+extern const char __dtb_octeon_3xxx_begin;
+extern const char __dtb_octeon_3xxx_end;
+extern const char __dtb_octeon_68xx_begin;
+extern const char __dtb_octeon_68xx_end;
+void __init device_tree_init(void)
+{
+       int dt_size;
+       struct boot_param_header *fdt;
+       bool do_prune;
+
+       if (octeon_bootinfo->minor_version >= 3 && octeon_bootinfo->fdt_addr) {
+               fdt = phys_to_virt(octeon_bootinfo->fdt_addr);
+               if (fdt_check_header(fdt))
+                       panic("Corrupt Device Tree passed to kernel.");
+               dt_size = be32_to_cpu(fdt->totalsize);
+               do_prune = false;
+       } else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
+               fdt = (struct boot_param_header *)&__dtb_octeon_68xx_begin;
+               dt_size = &__dtb_octeon_68xx_end - &__dtb_octeon_68xx_begin;
+               do_prune = true;
+       } else {
+               fdt = (struct boot_param_header *)&__dtb_octeon_3xxx_begin;
+               dt_size = &__dtb_octeon_3xxx_end - &__dtb_octeon_3xxx_begin;
+               do_prune = true;
+       }
+
+       /* Copy the default tree from init memory. */
+       initial_boot_params = early_init_dt_alloc_memory_arch(dt_size, 8);
+       if (initial_boot_params == NULL)
+               panic("Could not allocate initial_boot_params\n");
+       memcpy(initial_boot_params, fdt, dt_size);
+
+       if (do_prune) {
+               octeon_prune_device_tree();
+               pr_info("Using internal Device Tree.\n");
+       } else {
+               pr_info("Using passed Device Tree.\n");
+       }
+       unflatten_device_tree();
+}
diff --git a/arch/mips/configs/ls1b_defconfig b/arch/mips/configs/ls1b_defconfig
new file mode 100644 (file)
index 0000000..80cff8b
--- /dev/null
@@ -0,0 +1,109 @@
+CONFIG_MACH_LOONGSON1=y
+CONFIG_PREEMPT=y
+# CONFIG_SECCOMP is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_EXPERT=y
+CONFIG_PERF_EVENTS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_SCSI=m
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=m
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+CONFIG_STMMAC_ETH=y
+CONFIG_STMMAC_DA=y
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_WLAN is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_LEGACY_PTY_COUNT=8
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_USB_HID=m
+CONFIG_HID_GENERIC=m
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_STORAGE=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_LOONGSON1=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_FTRACE is not set
+# CONFIG_EARLY_PRINTK is not set
index d0b857d98c91703b01950f9d1a705c1048cd7ac0..138f698d7c00048c4b172718891bac49ef778b61 100644 (file)
@@ -367,6 +367,10 @@ CONFIG_SERIAL_8250_RSA=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_TIMERIOMEM=m
 CONFIG_RAW_DRIVER=m
+CONFIG_I2C=y
+CONFIG_I2C_XLR=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1374=y
 # CONFIG_HWMON is not set
 # CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID_SUPPORT is not set
index e95ff3054ff61f83bc56a0458142046655daba6c..8c62316f22f438b4b9cc18b23585f3e0ad8b7258 100644 (file)
@@ -101,7 +101,7 @@ void __init prom_free_prom_memory(void)
         * the first page reserved for the exception handlers.
         */
 
-#if defined(CONFIG_DECLANCE) || defined(CONFIG_DECLANCE_MODULE)
+#if IS_ENABLED(CONFIG_DECLANCE)
        /*
         * Leave 128 KB reserved for Lance memory for
         * IOASIC DECstations.
index 95e40c1e8ed114a3a95ad9cab9794e129ccbdca2..f21b7c04e95a2f70073e087e69d384e53d11862f 100644 (file)
 #define PRID_REV_VR4181A       0x0070  /* Same as VR4122 */
 #define PRID_REV_VR4130                0x0080
 #define PRID_REV_34K_V1_0_2    0x0022
+#define PRID_REV_LOONGSON1B    0x0020
 #define PRID_REV_LOONGSON2E    0x0002
 #define PRID_REV_LOONGSON2F    0x0003
 
@@ -261,7 +262,7 @@ enum cpu_type_enum {
         */
        CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
        CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350,
-       CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_M14KC,
+       CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC,
 
        /*
         * MIPS64 class processors
index 5b8d15bb5fe85a4b6d234f6aaf006d9e451efb8d..e104ddb694a88b0c6a0556a2eef8dad22a3a537f 100644 (file)
@@ -9,6 +9,7 @@
  * compile time if only one CPU support is enabled (idea stolen from
  * arm mach-types)
  */
+#define BCM6328_CPU_ID         0x6328
 #define BCM6338_CPU_ID         0x6338
 #define BCM6345_CPU_ID         0x6345
 #define BCM6348_CPU_ID         0x6348
@@ -20,6 +21,19 @@ u16 __bcm63xx_get_cpu_id(void);
 u16 bcm63xx_get_cpu_rev(void);
 unsigned int bcm63xx_get_cpu_freq(void);
 
+#ifdef CONFIG_BCM63XX_CPU_6328
+# ifdef bcm63xx_get_cpu_id
+#  undef bcm63xx_get_cpu_id
+#  define bcm63xx_get_cpu_id() __bcm63xx_get_cpu_id()
+#  define BCMCPU_RUNTIME_DETECT
+# else
+#  define bcm63xx_get_cpu_id() BCM6328_CPU_ID
+# endif
+# define BCMCPU_IS_6328()      (bcm63xx_get_cpu_id() == BCM6328_CPU_ID)
+#else
+# define BCMCPU_IS_6328()      (0)
+#endif
+
 #ifdef CONFIG_BCM63XX_CPU_6338
 # ifdef bcm63xx_get_cpu_id
 #  undef bcm63xx_get_cpu_id
@@ -102,13 +116,13 @@ enum bcm63xx_regs_set {
        RSET_UART1,
        RSET_GPIO,
        RSET_SPI,
-       RSET_SPI2,
        RSET_UDC0,
        RSET_OHCI0,
        RSET_OHCI_PRIV,
        RSET_USBH_PRIV,
        RSET_MPI,
        RSET_PCMCIA,
+       RSET_PCIE,
        RSET_DSL,
        RSET_ENET0,
        RSET_ENET1,
@@ -130,11 +144,17 @@ enum bcm63xx_regs_set {
        RSET_PCMDMA,
        RSET_PCMDMAC,
        RSET_PCMDMAS,
+       RSET_RNG,
+       RSET_MISC
 };
 
 #define RSET_DSL_LMEM_SIZE             (64 * 1024 * 4)
 #define RSET_DSL_SIZE                  4096
 #define RSET_WDT_SIZE                  12
+#define BCM_6338_RSET_SPI_SIZE         64
+#define BCM_6348_RSET_SPI_SIZE         64
+#define BCM_6358_RSET_SPI_SIZE         1804
+#define BCM_6368_RSET_SPI_SIZE         1804
 #define RSET_ENET_SIZE                 2048
 #define RSET_ENETDMA_SIZE              2048
 #define RSET_ENETSW_SIZE               65536
@@ -149,7 +169,52 @@ enum bcm63xx_regs_set {
 #define RSET_XTMDMA_SIZE               256
 #define RSET_XTMDMAC_SIZE(chans)       (16 * (chans))
 #define RSET_XTMDMAS_SIZE(chans)       (16 * (chans))
+#define RSET_RNG_SIZE                  20
 
+/*
+ * 6328 register sets base address
+ */
+#define BCM_6328_DSL_LMEM_BASE         (0xdeadbeef)
+#define BCM_6328_PERF_BASE             (0xb0000000)
+#define BCM_6328_TIMER_BASE            (0xb0000040)
+#define BCM_6328_WDT_BASE              (0xb000005c)
+#define BCM_6328_UART0_BASE             (0xb0000100)
+#define BCM_6328_UART1_BASE            (0xb0000120)
+#define BCM_6328_GPIO_BASE             (0xb0000080)
+#define BCM_6328_SPI_BASE              (0xdeadbeef)
+#define BCM_6328_UDC0_BASE             (0xdeadbeef)
+#define BCM_6328_USBDMA_BASE           (0xdeadbeef)
+#define BCM_6328_OHCI0_BASE            (0xdeadbeef)
+#define BCM_6328_OHCI_PRIV_BASE                (0xdeadbeef)
+#define BCM_6328_USBH_PRIV_BASE                (0xdeadbeef)
+#define BCM_6328_MPI_BASE              (0xdeadbeef)
+#define BCM_6328_PCMCIA_BASE           (0xdeadbeef)
+#define BCM_6328_PCIE_BASE             (0xb0e40000)
+#define BCM_6328_SDRAM_REGS_BASE       (0xdeadbeef)
+#define BCM_6328_DSL_BASE              (0xb0001900)
+#define BCM_6328_UBUS_BASE             (0xdeadbeef)
+#define BCM_6328_ENET0_BASE            (0xdeadbeef)
+#define BCM_6328_ENET1_BASE            (0xdeadbeef)
+#define BCM_6328_ENETDMA_BASE          (0xb000d800)
+#define BCM_6328_ENETDMAC_BASE         (0xb000da00)
+#define BCM_6328_ENETDMAS_BASE         (0xb000dc00)
+#define BCM_6328_ENETSW_BASE           (0xb0e00000)
+#define BCM_6328_EHCI0_BASE            (0x10002500)
+#define BCM_6328_SDRAM_BASE            (0xdeadbeef)
+#define BCM_6328_MEMC_BASE             (0xdeadbeef)
+#define BCM_6328_DDR_BASE              (0xb0003000)
+#define BCM_6328_M2M_BASE              (0xdeadbeef)
+#define BCM_6328_ATM_BASE              (0xdeadbeef)
+#define BCM_6328_XTM_BASE              (0xdeadbeef)
+#define BCM_6328_XTMDMA_BASE           (0xb000b800)
+#define BCM_6328_XTMDMAC_BASE          (0xdeadbeef)
+#define BCM_6328_XTMDMAS_BASE          (0xdeadbeef)
+#define BCM_6328_PCM_BASE              (0xb000a800)
+#define BCM_6328_PCMDMA_BASE           (0xdeadbeef)
+#define BCM_6328_PCMDMAC_BASE          (0xdeadbeef)
+#define BCM_6328_PCMDMAS_BASE          (0xdeadbeef)
+#define BCM_6328_RNG_BASE              (0xdeadbeef)
+#define BCM_6328_MISC_BASE             (0xb0001800)
 /*
  * 6338 register sets base address
  */
@@ -162,7 +227,6 @@ enum bcm63xx_regs_set {
 #define BCM_6338_UART1_BASE            (0xdeadbeef)
 #define BCM_6338_GPIO_BASE             (0xfffe0400)
 #define BCM_6338_SPI_BASE              (0xfffe0c00)
-#define BCM_6338_SPI2_BASE             (0xdeadbeef)
 #define BCM_6338_UDC0_BASE             (0xdeadbeef)
 #define BCM_6338_USBDMA_BASE           (0xfffe2400)
 #define BCM_6338_OHCI0_BASE            (0xdeadbeef)
@@ -170,6 +234,7 @@ enum bcm63xx_regs_set {
 #define BCM_6338_USBH_PRIV_BASE                (0xdeadbeef)
 #define BCM_6338_MPI_BASE              (0xfffe3160)
 #define BCM_6338_PCMCIA_BASE           (0xdeadbeef)
+#define BCM_6338_PCIE_BASE             (0xdeadbeef)
 #define BCM_6338_SDRAM_REGS_BASE       (0xfffe3100)
 #define BCM_6338_DSL_BASE              (0xfffe1000)
 #define BCM_6338_UBUS_BASE             (0xdeadbeef)
@@ -193,6 +258,8 @@ enum bcm63xx_regs_set {
 #define BCM_6338_PCMDMA_BASE           (0xdeadbeef)
 #define BCM_6338_PCMDMAC_BASE          (0xdeadbeef)
 #define BCM_6338_PCMDMAS_BASE          (0xdeadbeef)
+#define BCM_6338_RNG_BASE              (0xdeadbeef)
+#define BCM_6338_MISC_BASE             (0xdeadbeef)
 
 /*
  * 6345 register sets base address
@@ -206,7 +273,6 @@ enum bcm63xx_regs_set {
 #define BCM_6345_UART1_BASE            (0xdeadbeef)
 #define BCM_6345_GPIO_BASE             (0xfffe0400)
 #define BCM_6345_SPI_BASE              (0xdeadbeef)
-#define BCM_6345_SPI2_BASE             (0xdeadbeef)
 #define BCM_6345_UDC0_BASE             (0xdeadbeef)
 #define BCM_6345_USBDMA_BASE           (0xfffe2800)
 #define BCM_6345_ENET0_BASE            (0xfffe1800)
@@ -216,6 +282,7 @@ enum bcm63xx_regs_set {
 #define BCM_6345_ENETSW_BASE           (0xdeadbeef)
 #define BCM_6345_PCMCIA_BASE           (0xfffe2028)
 #define BCM_6345_MPI_BASE              (0xfffe2000)
+#define BCM_6345_PCIE_BASE             (0xdeadbeef)
 #define BCM_6345_OHCI0_BASE            (0xfffe2100)
 #define BCM_6345_OHCI_PRIV_BASE                (0xfffe2200)
 #define BCM_6345_USBH_PRIV_BASE                (0xdeadbeef)
@@ -237,6 +304,8 @@ enum bcm63xx_regs_set {
 #define BCM_6345_PCMDMA_BASE           (0xdeadbeef)
 #define BCM_6345_PCMDMAC_BASE          (0xdeadbeef)
 #define BCM_6345_PCMDMAS_BASE          (0xdeadbeef)
+#define BCM_6345_RNG_BASE              (0xdeadbeef)
+#define BCM_6345_MISC_BASE             (0xdeadbeef)
 
 /*
  * 6348 register sets base address
@@ -249,13 +318,13 @@ enum bcm63xx_regs_set {
 #define BCM_6348_UART1_BASE            (0xdeadbeef)
 #define BCM_6348_GPIO_BASE             (0xfffe0400)
 #define BCM_6348_SPI_BASE              (0xfffe0c00)
-#define BCM_6348_SPI2_BASE             (0xdeadbeef)
 #define BCM_6348_UDC0_BASE             (0xfffe1000)
 #define BCM_6348_OHCI0_BASE            (0xfffe1b00)
 #define BCM_6348_OHCI_PRIV_BASE                (0xfffe1c00)
 #define BCM_6348_USBH_PRIV_BASE                (0xdeadbeef)
 #define BCM_6348_MPI_BASE              (0xfffe2000)
 #define BCM_6348_PCMCIA_BASE           (0xfffe2054)
+#define BCM_6348_PCIE_BASE             (0xdeadbeef)
 #define BCM_6348_SDRAM_REGS_BASE       (0xfffe2300)
 #define BCM_6348_M2M_BASE              (0xfffe2800)
 #define BCM_6348_DSL_BASE              (0xfffe3000)
@@ -278,6 +347,8 @@ enum bcm63xx_regs_set {
 #define BCM_6348_PCMDMA_BASE           (0xdeadbeef)
 #define BCM_6348_PCMDMAC_BASE          (0xdeadbeef)
 #define BCM_6348_PCMDMAS_BASE          (0xdeadbeef)
+#define BCM_6348_RNG_BASE              (0xdeadbeef)
+#define BCM_6348_MISC_BASE             (0xdeadbeef)
 
 /*
  * 6358 register sets base address
@@ -289,14 +360,14 @@ enum bcm63xx_regs_set {
 #define BCM_6358_UART0_BASE            (0xfffe0100)
 #define BCM_6358_UART1_BASE            (0xfffe0120)
 #define BCM_6358_GPIO_BASE             (0xfffe0080)
-#define BCM_6358_SPI_BASE              (0xdeadbeef)
-#define BCM_6358_SPI2_BASE             (0xfffe0800)
+#define BCM_6358_SPI_BASE              (0xfffe0800)
 #define BCM_6358_UDC0_BASE             (0xfffe0800)
 #define BCM_6358_OHCI0_BASE            (0xfffe1400)
 #define BCM_6358_OHCI_PRIV_BASE                (0xdeadbeef)
 #define BCM_6358_USBH_PRIV_BASE                (0xfffe1500)
 #define BCM_6358_MPI_BASE              (0xfffe1000)
 #define BCM_6358_PCMCIA_BASE           (0xfffe1054)
+#define BCM_6358_PCIE_BASE             (0xdeadbeef)
 #define BCM_6358_SDRAM_REGS_BASE       (0xfffe2300)
 #define BCM_6358_M2M_BASE              (0xdeadbeef)
 #define BCM_6358_DSL_BASE              (0xfffe3000)
@@ -319,6 +390,8 @@ enum bcm63xx_regs_set {
 #define BCM_6358_PCMDMA_BASE           (0xfffe1800)
 #define BCM_6358_PCMDMAC_BASE          (0xfffe1900)
 #define BCM_6358_PCMDMAS_BASE          (0xfffe1a00)
+#define BCM_6358_RNG_BASE              (0xdeadbeef)
+#define BCM_6358_MISC_BASE             (0xdeadbeef)
 
 
 /*
@@ -331,14 +404,14 @@ enum bcm63xx_regs_set {
 #define BCM_6368_UART0_BASE            (0xb0000100)
 #define BCM_6368_UART1_BASE            (0xb0000120)
 #define BCM_6368_GPIO_BASE             (0xb0000080)
-#define BCM_6368_SPI_BASE              (0xdeadbeef)
-#define BCM_6368_SPI2_BASE             (0xb0000800)
+#define BCM_6368_SPI_BASE              (0xb0000800)
 #define BCM_6368_UDC0_BASE             (0xdeadbeef)
 #define BCM_6368_OHCI0_BASE            (0xb0001600)
 #define BCM_6368_OHCI_PRIV_BASE                (0xdeadbeef)
 #define BCM_6368_USBH_PRIV_BASE                (0xb0001700)
 #define BCM_6368_MPI_BASE              (0xb0001000)
 #define BCM_6368_PCMCIA_BASE           (0xb0001054)
+#define BCM_6368_PCIE_BASE             (0xdeadbeef)
 #define BCM_6368_SDRAM_REGS_BASE       (0xdeadbeef)
 #define BCM_6368_M2M_BASE              (0xdeadbeef)
 #define BCM_6368_DSL_BASE              (0xdeadbeef)
@@ -361,6 +434,8 @@ enum bcm63xx_regs_set {
 #define BCM_6368_PCMDMA_BASE           (0xb0005800)
 #define BCM_6368_PCMDMAC_BASE          (0xb0005a00)
 #define BCM_6368_PCMDMAS_BASE          (0xb0005c00)
+#define BCM_6368_RNG_BASE              (0xb0004180)
+#define BCM_6368_MISC_BASE             (0xdeadbeef)
 
 
 extern const unsigned long *bcm63xx_regs_base;
@@ -379,13 +454,13 @@ extern const unsigned long *bcm63xx_regs_base;
        __GEN_RSET_BASE(__cpu, UART1)                                   \
        __GEN_RSET_BASE(__cpu, GPIO)                                    \
        __GEN_RSET_BASE(__cpu, SPI)                                     \
-       __GEN_RSET_BASE(__cpu, SPI2)                                    \
        __GEN_RSET_BASE(__cpu, UDC0)                                    \
        __GEN_RSET_BASE(__cpu, OHCI0)                                   \
        __GEN_RSET_BASE(__cpu, OHCI_PRIV)                               \
        __GEN_RSET_BASE(__cpu, USBH_PRIV)                               \
        __GEN_RSET_BASE(__cpu, MPI)                                     \
        __GEN_RSET_BASE(__cpu, PCMCIA)                                  \
+       __GEN_RSET_BASE(__cpu, PCIE)                                    \
        __GEN_RSET_BASE(__cpu, DSL)                                     \
        __GEN_RSET_BASE(__cpu, ENET0)                                   \
        __GEN_RSET_BASE(__cpu, ENET1)                                   \
@@ -407,6 +482,8 @@ extern const unsigned long *bcm63xx_regs_base;
        __GEN_RSET_BASE(__cpu, PCMDMA)                                  \
        __GEN_RSET_BASE(__cpu, PCMDMAC)                                 \
        __GEN_RSET_BASE(__cpu, PCMDMAS)                                 \
+       __GEN_RSET_BASE(__cpu, RNG)                                     \
+       __GEN_RSET_BASE(__cpu, MISC)                                    \
        }
 
 #define __GEN_CPU_REGS_TABLE(__cpu)                                    \
@@ -418,13 +495,13 @@ extern const unsigned long *bcm63xx_regs_base;
        [RSET_UART1]            = BCM_## __cpu ##_UART1_BASE,           \
        [RSET_GPIO]             = BCM_## __cpu ##_GPIO_BASE,            \
        [RSET_SPI]              = BCM_## __cpu ##_SPI_BASE,             \
-       [RSET_SPI2]             = BCM_## __cpu ##_SPI2_BASE,            \
        [RSET_UDC0]             = BCM_## __cpu ##_UDC0_BASE,            \
        [RSET_OHCI0]            = BCM_## __cpu ##_OHCI0_BASE,           \
        [RSET_OHCI_PRIV]        = BCM_## __cpu ##_OHCI_PRIV_BASE,       \
        [RSET_USBH_PRIV]        = BCM_## __cpu ##_USBH_PRIV_BASE,       \
        [RSET_MPI]              = BCM_## __cpu ##_MPI_BASE,             \
        [RSET_PCMCIA]           = BCM_## __cpu ##_PCMCIA_BASE,          \
+       [RSET_PCIE]             = BCM_## __cpu ##_PCIE_BASE,            \
        [RSET_DSL]              = BCM_## __cpu ##_DSL_BASE,             \
        [RSET_ENET0]            = BCM_## __cpu ##_ENET0_BASE,           \
        [RSET_ENET1]            = BCM_## __cpu ##_ENET1_BASE,           \
@@ -446,6 +523,8 @@ extern const unsigned long *bcm63xx_regs_base;
        [RSET_PCMDMA]           = BCM_## __cpu ##_PCMDMA_BASE,          \
        [RSET_PCMDMAC]          = BCM_## __cpu ##_PCMDMAC_BASE,         \
        [RSET_PCMDMAS]          = BCM_## __cpu ##_PCMDMAS_BASE,         \
+       [RSET_RNG]              = BCM_## __cpu ##_RNG_BASE,             \
+       [RSET_MISC]             = BCM_## __cpu ##_MISC_BASE,            \
 
 
 static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set)
@@ -453,6 +532,9 @@ static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set)
 #ifdef BCMCPU_RUNTIME_DETECT
        return bcm63xx_regs_base[set];
 #else
+#ifdef CONFIG_BCM63XX_CPU_6328
+       __GEN_RSET(6328)
+#endif
 #ifdef CONFIG_BCM63XX_CPU_6338
        __GEN_RSET(6338)
 #endif
@@ -478,6 +560,7 @@ static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set)
  */
 enum bcm63xx_irq {
        IRQ_TIMER = 0,
+       IRQ_SPI,
        IRQ_UART0,
        IRQ_UART1,
        IRQ_DSL,
@@ -505,10 +588,52 @@ enum bcm63xx_irq {
        IRQ_XTM_DMA0,
 };
 
+/*
+ * 6328 irqs
+ */
+#define BCM_6328_HIGH_IRQ_BASE         (IRQ_INTERNAL_BASE + 32)
+
+#define BCM_6328_TIMER_IRQ             (IRQ_INTERNAL_BASE + 31)
+#define BCM_6328_SPI_IRQ               0
+#define BCM_6328_UART0_IRQ             (IRQ_INTERNAL_BASE + 28)
+#define BCM_6328_UART1_IRQ             (BCM_6328_HIGH_IRQ_BASE + 7)
+#define BCM_6328_DSL_IRQ               (IRQ_INTERNAL_BASE + 4)
+#define BCM_6328_UDC0_IRQ              0
+#define BCM_6328_ENET0_IRQ             0
+#define BCM_6328_ENET1_IRQ             0
+#define BCM_6328_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 12)
+#define BCM_6328_OHCI0_IRQ             (IRQ_INTERNAL_BASE + 9)
+#define BCM_6328_EHCI0_IRQ             (IRQ_INTERNAL_BASE + 10)
+#define BCM_6328_PCMCIA_IRQ            0
+#define BCM_6328_ENET0_RXDMA_IRQ       0
+#define BCM_6328_ENET0_TXDMA_IRQ       0
+#define BCM_6328_ENET1_RXDMA_IRQ       0
+#define BCM_6328_ENET1_TXDMA_IRQ       0
+#define BCM_6328_PCI_IRQ               (IRQ_INTERNAL_BASE + 23)
+#define BCM_6328_ATM_IRQ               0
+#define BCM_6328_ENETSW_RXDMA0_IRQ     (BCM_6328_HIGH_IRQ_BASE + 0)
+#define BCM_6328_ENETSW_RXDMA1_IRQ     (BCM_6328_HIGH_IRQ_BASE + 1)
+#define BCM_6328_ENETSW_RXDMA2_IRQ     (BCM_6328_HIGH_IRQ_BASE + 2)
+#define BCM_6328_ENETSW_RXDMA3_IRQ     (BCM_6328_HIGH_IRQ_BASE + 3)
+#define BCM_6328_ENETSW_TXDMA0_IRQ     (BCM_6328_HIGH_IRQ_BASE + 4)
+#define BCM_6328_ENETSW_TXDMA1_IRQ     (BCM_6328_HIGH_IRQ_BASE + 5)
+#define BCM_6328_ENETSW_TXDMA2_IRQ     (BCM_6328_HIGH_IRQ_BASE + 6)
+#define BCM_6328_ENETSW_TXDMA3_IRQ     (BCM_6328_HIGH_IRQ_BASE + 7)
+#define BCM_6328_XTM_IRQ               (BCM_6328_HIGH_IRQ_BASE + 31)
+#define BCM_6328_XTM_DMA0_IRQ          (BCM_6328_HIGH_IRQ_BASE + 11)
+
+#define BCM_6328_PCM_DMA0_IRQ          (IRQ_INTERNAL_BASE + 2)
+#define BCM_6328_PCM_DMA1_IRQ          (IRQ_INTERNAL_BASE + 3)
+#define BCM_6328_EXT_IRQ0              (IRQ_INTERNAL_BASE + 24)
+#define BCM_6328_EXT_IRQ1              (IRQ_INTERNAL_BASE + 25)
+#define BCM_6328_EXT_IRQ2              (IRQ_INTERNAL_BASE + 26)
+#define BCM_6328_EXT_IRQ3              (IRQ_INTERNAL_BASE + 27)
+
 /*
  * 6338 irqs
  */
 #define BCM_6338_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
+#define BCM_6338_SPI_IRQ               (IRQ_INTERNAL_BASE + 1)
 #define BCM_6338_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
 #define BCM_6338_UART1_IRQ             0
 #define BCM_6338_DSL_IRQ               (IRQ_INTERNAL_BASE + 5)
@@ -539,6 +664,7 @@ enum bcm63xx_irq {
  * 6345 irqs
  */
 #define BCM_6345_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
+#define BCM_6345_SPI_IRQ               0
 #define BCM_6345_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
 #define BCM_6345_UART1_IRQ             0
 #define BCM_6345_DSL_IRQ               (IRQ_INTERNAL_BASE + 3)
@@ -569,6 +695,7 @@ enum bcm63xx_irq {
  * 6348 irqs
  */
 #define BCM_6348_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
+#define BCM_6348_SPI_IRQ               (IRQ_INTERNAL_BASE + 1)
 #define BCM_6348_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
 #define BCM_6348_UART1_IRQ             0
 #define BCM_6348_DSL_IRQ               (IRQ_INTERNAL_BASE + 4)
@@ -599,6 +726,7 @@ enum bcm63xx_irq {
  * 6358 irqs
  */
 #define BCM_6358_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
+#define BCM_6358_SPI_IRQ               (IRQ_INTERNAL_BASE + 1)
 #define BCM_6358_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
 #define BCM_6358_UART1_IRQ             (IRQ_INTERNAL_BASE + 3)
 #define BCM_6358_DSL_IRQ               (IRQ_INTERNAL_BASE + 29)
@@ -638,6 +766,7 @@ enum bcm63xx_irq {
 #define BCM_6368_HIGH_IRQ_BASE         (IRQ_INTERNAL_BASE + 32)
 
 #define BCM_6368_TIMER_IRQ             (IRQ_INTERNAL_BASE + 0)
+#define BCM_6368_SPI_IRQ               (IRQ_INTERNAL_BASE + 1)
 #define BCM_6368_UART0_IRQ             (IRQ_INTERNAL_BASE + 2)
 #define BCM_6368_UART1_IRQ             (IRQ_INTERNAL_BASE + 3)
 #define BCM_6368_DSL_IRQ               (IRQ_INTERNAL_BASE + 4)
@@ -677,6 +806,7 @@ extern const int *bcm63xx_irqs;
 
 #define __GEN_CPU_IRQ_TABLE(__cpu)                                     \
        [IRQ_TIMER]             = BCM_## __cpu ##_TIMER_IRQ,            \
+       [IRQ_SPI]               = BCM_## __cpu ##_SPI_IRQ,              \
        [IRQ_UART0]             = BCM_## __cpu ##_UART0_IRQ,            \
        [IRQ_UART1]             = BCM_## __cpu ##_UART1_IRQ,            \
        [IRQ_DSL]               = BCM_## __cpu ##_DSL_IRQ,              \
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_flash.h
new file mode 100644 (file)
index 0000000..354b848
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __BCM63XX_FLASH_H
+#define __BCM63XX_FLASH_H
+
+enum {
+       BCM63XX_FLASH_TYPE_PARALLEL,
+       BCM63XX_FLASH_TYPE_SERIAL,
+       BCM63XX_FLASH_TYPE_NAND,
+};
+
+int __init bcm63xx_flash_register(void);
+
+#endif /* __BCM63XX_FLASH_H */
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
new file mode 100644 (file)
index 0000000..7d98dbe
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef BCM63XX_DEV_SPI_H
+#define BCM63XX_DEV_SPI_H
+
+#include <linux/types.h>
+#include <bcm63xx_io.h>
+#include <bcm63xx_regs.h>
+
+int __init bcm63xx_spi_register(void);
+
+struct bcm63xx_spi_pdata {
+       unsigned int    fifo_size;
+       int             bus_num;
+       int             num_chipselect;
+       u32             speed_hz;
+};
+
+enum bcm63xx_regs_spi {
+       SPI_CMD,
+       SPI_INT_STATUS,
+       SPI_INT_MASK_ST,
+       SPI_INT_MASK,
+       SPI_ST,
+       SPI_CLK_CFG,
+       SPI_FILL_BYTE,
+       SPI_MSG_TAIL,
+       SPI_RX_TAIL,
+       SPI_MSG_CTL,
+       SPI_MSG_DATA,
+       SPI_RX_DATA,
+};
+
+#define __GEN_SPI_RSET_BASE(__cpu, __rset)                             \
+       case SPI_## __rset:                                             \
+               return SPI_## __cpu ##_## __rset;
+
+#define __GEN_SPI_RSET(__cpu)                                          \
+       switch (reg) {                                                  \
+       __GEN_SPI_RSET_BASE(__cpu, CMD)                                 \
+       __GEN_SPI_RSET_BASE(__cpu, INT_STATUS)                          \
+       __GEN_SPI_RSET_BASE(__cpu, INT_MASK_ST)                         \
+       __GEN_SPI_RSET_BASE(__cpu, INT_MASK)                            \
+       __GEN_SPI_RSET_BASE(__cpu, ST)                                  \
+       __GEN_SPI_RSET_BASE(__cpu, CLK_CFG)                             \
+       __GEN_SPI_RSET_BASE(__cpu, FILL_BYTE)                           \
+       __GEN_SPI_RSET_BASE(__cpu, MSG_TAIL)                            \
+       __GEN_SPI_RSET_BASE(__cpu, RX_TAIL)                             \
+       __GEN_SPI_RSET_BASE(__cpu, MSG_CTL)                             \
+       __GEN_SPI_RSET_BASE(__cpu, MSG_DATA)                            \
+       __GEN_SPI_RSET_BASE(__cpu, RX_DATA)                             \
+       }
+
+#define __GEN_SPI_REGS_TABLE(__cpu)                                    \
+       [SPI_CMD]               = SPI_## __cpu ##_CMD,                  \
+       [SPI_INT_STATUS]        = SPI_## __cpu ##_INT_STATUS,           \
+       [SPI_INT_MASK_ST]       = SPI_## __cpu ##_INT_MASK_ST,          \
+       [SPI_INT_MASK]          = SPI_## __cpu ##_INT_MASK,             \
+       [SPI_ST]                = SPI_## __cpu ##_ST,                   \
+       [SPI_CLK_CFG]           = SPI_## __cpu ##_CLK_CFG,              \
+       [SPI_FILL_BYTE]         = SPI_## __cpu ##_FILL_BYTE,            \
+       [SPI_MSG_TAIL]          = SPI_## __cpu ##_MSG_TAIL,             \
+       [SPI_RX_TAIL]           = SPI_## __cpu ##_RX_TAIL,              \
+       [SPI_MSG_CTL]           = SPI_## __cpu ##_MSG_CTL,              \
+       [SPI_MSG_DATA]          = SPI_## __cpu ##_MSG_DATA,             \
+       [SPI_RX_DATA]           = SPI_## __cpu ##_RX_DATA,
+
+static inline unsigned long bcm63xx_spireg(enum bcm63xx_regs_spi reg)
+{
+#ifdef BCMCPU_RUNTIME_DETECT
+       extern const unsigned long *bcm63xx_regs_spi;
+
+       return bcm63xx_regs_spi[reg];
+#else
+#ifdef CONFIG_BCM63XX_CPU_6338
+       __GEN_SPI_RSET(6338)
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6348
+       __GEN_SPI_RSET(6348)
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6358
+       __GEN_SPI_RSET(6358)
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6368
+       __GEN_SPI_RSET(6368)
+#endif
+#endif
+       return 0;
+}
+
+#endif /* BCM63XX_DEV_SPI_H */
index 1d7dd96aa460b5d150f4d15660993a1170a4f3e8..0a9891f7580de557e702e7c4708139705b27605e 100644 (file)
@@ -9,6 +9,8 @@ int __init bcm63xx_gpio_init(void);
 static inline unsigned long bcm63xx_gpio_count(void)
 {
        switch (bcm63xx_get_cpu_id()) {
+       case BCM6328_CPU_ID:
+               return 32;
        case BCM6358_CPU_ID:
                return 40;
        case BCM6338_CPU_ID:
index 72477a6441ddb9a39c769c47809878f120de027a..9203d90e610cc801fa70045058c75ed974dcdd3b 100644 (file)
 #define BCM_CB_MEM_END_PA              (BCM_CB_MEM_BASE_PA +           \
                                        BCM_CB_MEM_SIZE - 1)
 
+#define BCM_PCIE_MEM_BASE_PA           0x10f00000
+#define BCM_PCIE_MEM_SIZE              (16 * 1024 * 1024)
+#define BCM_PCIE_MEM_END_PA            (BCM_PCIE_MEM_BASE_PA +         \
+                                       BCM_PCIE_MEM_SIZE - 1)
 
 /*
  * Internal registers are accessed through KSEG3
 #define bcm_mpi_writel(v, o)   bcm_rset_writel(RSET_MPI, (v), (o))
 #define bcm_pcmcia_readl(o)    bcm_rset_readl(RSET_PCMCIA, (o))
 #define bcm_pcmcia_writel(v, o)        bcm_rset_writel(RSET_PCMCIA, (v), (o))
+#define bcm_pcie_readl(o)      bcm_rset_readl(RSET_PCIE, (o))
+#define bcm_pcie_writel(v, o)  bcm_rset_writel(RSET_PCIE, (v), (o))
 #define bcm_sdram_readl(o)     bcm_rset_readl(RSET_SDRAM, (o))
 #define bcm_sdram_writel(v, o) bcm_rset_writel(RSET_SDRAM, (v), (o))
 #define bcm_memc_readl(o)      bcm_rset_readl(RSET_MEMC, (o))
 #define bcm_memc_writel(v, o)  bcm_rset_writel(RSET_MEMC, (v), (o))
 #define bcm_ddr_readl(o)       bcm_rset_readl(RSET_DDR, (o))
 #define bcm_ddr_writel(v, o)   bcm_rset_writel(RSET_DDR, (v), (o))
+#define bcm_misc_readl(o)      bcm_rset_readl(RSET_MISC, (o))
+#define bcm_misc_writel(v, o)  bcm_rset_writel(RSET_MISC, (v), (o))
 
 #endif /* ! BCM63XX_IO_H_ */
index fdcd78ca1b03d054f807ee0c64839c763194f855..4ccc2a748aff2db6913dab0e8b67e1eb6fbceeb8 100644 (file)
 /* Clock Control register */
 #define PERF_CKCTL_REG                 0x4
 
+#define CKCTL_6328_PHYMIPS_EN          (1 << 0)
+#define CKCTL_6328_ADSL_QPROC_EN       (1 << 1)
+#define CKCTL_6328_ADSL_AFE_EN         (1 << 2)
+#define CKCTL_6328_ADSL_EN             (1 << 3)
+#define CKCTL_6328_MIPS_EN             (1 << 4)
+#define CKCTL_6328_SAR_EN              (1 << 5)
+#define CKCTL_6328_PCM_EN              (1 << 6)
+#define CKCTL_6328_USBD_EN             (1 << 7)
+#define CKCTL_6328_USBH_EN             (1 << 8)
+#define CKCTL_6328_HSSPI_EN            (1 << 9)
+#define CKCTL_6328_PCIE_EN             (1 << 10)
+#define CKCTL_6328_ROBOSW_EN           (1 << 11)
+
+#define CKCTL_6328_ALL_SAFE_EN         (CKCTL_6328_PHYMIPS_EN |        \
+                                       CKCTL_6328_ADSL_QPROC_EN |      \
+                                       CKCTL_6328_ADSL_AFE_EN |        \
+                                       CKCTL_6328_ADSL_EN |            \
+                                       CKCTL_6328_SAR_EN  |            \
+                                       CKCTL_6328_PCM_EN  |            \
+                                       CKCTL_6328_USBD_EN |            \
+                                       CKCTL_6328_USBH_EN |            \
+                                       CKCTL_6328_ROBOSW_EN |          \
+                                       CKCTL_6328_PCIE_EN)
+
 #define CKCTL_6338_ADSLPHY_EN          (1 << 0)
 #define CKCTL_6338_MPI_EN              (1 << 1)
 #define CKCTL_6338_DRAM_EN             (1 << 2)
 #define CKCTL_6368_PHYMIPS_EN          (1 << 6)
 #define CKCTL_6368_SWPKT_USB_EN                (1 << 7)
 #define CKCTL_6368_SWPKT_SAR_EN                (1 << 8)
-#define CKCTL_6368_SPI_CLK_EN          (1 << 9)
-#define CKCTL_6368_USBD_CLK_EN         (1 << 10)
-#define CKCTL_6368_SAR_CLK_EN          (1 << 11)
-#define CKCTL_6368_ROBOSW_CLK_EN       (1 << 12)
-#define CKCTL_6368_UTOPIA_CLK_EN       (1 << 13)
-#define CKCTL_6368_PCM_CLK_EN          (1 << 14)
-#define CKCTL_6368_USBH_CLK_EN         (1 << 15)
+#define CKCTL_6368_SPI_EN              (1 << 9)
+#define CKCTL_6368_USBD_EN             (1 << 10)
+#define CKCTL_6368_SAR_EN              (1 << 11)
+#define CKCTL_6368_ROBOSW_EN           (1 << 12)
+#define CKCTL_6368_UTOPIA_EN           (1 << 13)
+#define CKCTL_6368_PCM_EN              (1 << 14)
+#define CKCTL_6368_USBH_EN             (1 << 15)
 #define CKCTL_6368_DISABLE_GLESS_EN    (1 << 16)
-#define CKCTL_6368_NAND_CLK_EN         (1 << 17)
-#define CKCTL_6368_IPSEC_CLK_EN                (1 << 18)
+#define CKCTL_6368_NAND_EN             (1 << 17)
+#define CKCTL_6368_IPSEC_EN            (1 << 18)
 
 #define CKCTL_6368_ALL_SAFE_EN         (CKCTL_6368_SWPKT_USB_EN |      \
                                        CKCTL_6368_SWPKT_SAR_EN |       \
-                                       CKCTL_6368_SPI_CLK_EN |         \
-                                       CKCTL_6368_USBD_CLK_EN |        \
-                                       CKCTL_6368_SAR_CLK_EN |         \
-                                       CKCTL_6368_ROBOSW_CLK_EN |      \
-                                       CKCTL_6368_UTOPIA_CLK_EN |      \
-                                       CKCTL_6368_PCM_CLK_EN |         \
-                                       CKCTL_6368_USBH_CLK_EN |        \
+                                       CKCTL_6368_SPI_EN |             \
+                                       CKCTL_6368_USBD_EN |            \
+                                       CKCTL_6368_SAR_EN |             \
+                                       CKCTL_6368_ROBOSW_EN |          \
+                                       CKCTL_6368_UTOPIA_EN |          \
+                                       CKCTL_6368_PCM_EN |             \
+                                       CKCTL_6368_USBH_EN |            \
                                        CKCTL_6368_DISABLE_GLESS_EN |   \
-                                       CKCTL_6368_NAND_CLK_EN |        \
-                                       CKCTL_6368_IPSEC_CLK_EN)
+                                       CKCTL_6368_NAND_EN |            \
+                                       CKCTL_6368_IPSEC_EN)
 
 /* System PLL Control register  */
 #define PERF_SYS_PLL_CTL_REG           0x8
 #define SYS_PLL_SOFT_RESET             0x1
 
 /* Interrupt Mask register */
+#define PERF_IRQMASK_6328_REG          0x20
 #define PERF_IRQMASK_6338_REG          0xc
 #define PERF_IRQMASK_6345_REG          0xc
 #define PERF_IRQMASK_6348_REG          0xc
 #define PERF_IRQMASK_6368_REG          0x20
 
 /* Interrupt Status register */
+#define PERF_IRQSTAT_6328_REG          0x28
 #define PERF_IRQSTAT_6338_REG          0x10
 #define PERF_IRQSTAT_6345_REG          0x10
 #define PERF_IRQSTAT_6348_REG          0x10
 #define PERF_IRQSTAT_6368_REG          0x28
 
 /* External Interrupt Configuration register */
+#define PERF_EXTIRQ_CFG_REG_6328       0x18
 #define PERF_EXTIRQ_CFG_REG_6338       0x14
 #define PERF_EXTIRQ_CFG_REG_6348       0x14
 #define PERF_EXTIRQ_CFG_REG_6358       0x14
 
 /* Soft Reset register */
 #define PERF_SOFTRESET_REG             0x28
+#define PERF_SOFTRESET_6328_REG                0x10
 #define PERF_SOFTRESET_6368_REG                0x10
 
+#define SOFTRESET_6328_SPI_MASK                (1 << 0)
+#define SOFTRESET_6328_EPHY_MASK       (1 << 1)
+#define SOFTRESET_6328_SAR_MASK                (1 << 2)
+#define SOFTRESET_6328_ENETSW_MASK     (1 << 3)
+#define SOFTRESET_6328_USBS_MASK       (1 << 4)
+#define SOFTRESET_6328_USBH_MASK       (1 << 5)
+#define SOFTRESET_6328_PCM_MASK                (1 << 6)
+#define SOFTRESET_6328_PCIE_CORE_MASK  (1 << 7)
+#define SOFTRESET_6328_PCIE_MASK       (1 << 8)
+#define SOFTRESET_6328_PCIE_EXT_MASK   (1 << 9)
+#define SOFTRESET_6328_PCIE_HARD_MASK  (1 << 10)
+
 #define SOFTRESET_6338_SPI_MASK                (1 << 0)
 #define SOFTRESET_6338_ENET_MASK       (1 << 2)
 #define SOFTRESET_6338_USBH_MASK       (1 << 3)
 /* Watchdog reset length register */
 #define WDT_RSTLEN_REG                 0x8
 
+/* Watchdog soft reset register (BCM6328 only) */
+#define WDT_SOFTRESET_REG              0xc
 
 /*************************************************************************
  * _REG relative to RSET_UARTx
 #define GPIO_BASEMODE_6368_MASK                0x7
 /* those bits must be kept as read in gpio basemode register*/
 
+#define GPIO_STRAPBUS_REG              0x40
+#define STRAPBUS_6358_BOOT_SEL_PARALLEL        (1 << 1)
+#define STRAPBUS_6358_BOOT_SEL_SERIAL  (0 << 1)
+#define STRAPBUS_6368_BOOT_SEL_MASK    0x3
+#define STRAPBUS_6368_BOOT_SEL_NAND    0
+#define STRAPBUS_6368_BOOT_SEL_SERIAL  1
+#define STRAPBUS_6368_BOOT_SEL_PARALLEL        3
+
+
 /*************************************************************************
  * _REG relative to RSET_ENET
  *************************************************************************/
  * _REG relative to RSET_DDR
  *************************************************************************/
 
+#define DDR_CSEND_REG                  0x8
+
 #define DDR_DMIPSPLLCFG_REG            0x18
 #define DMIPSPLLCFG_M1_SHIFT           0
 #define DMIPSPLLCFG_M1_MASK            (0xff << DMIPSPLLCFG_M1_SHIFT)
 #define M2M_SRCID_REG(x)               ((x) * 0x40 + 0x14)
 #define M2M_DSTID_REG(x)               ((x) * 0x40 + 0x18)
 
+/*************************************************************************
+ * _REG relative to RSET_RNG
+ *************************************************************************/
+
+#define RNG_CTRL                       0x00
+#define RNG_EN                         (1 << 0)
+
+#define RNG_STAT                       0x04
+#define RNG_AVAIL_MASK                 (0xff000000)
+
+#define RNG_DATA                       0x08
+#define RNG_THRES                      0x0c
+#define RNG_MASK                       0x10
+
+/*************************************************************************
+ * _REG relative to RSET_SPI
+ *************************************************************************/
+
+/* BCM 6338 SPI core */
+#define SPI_6338_CMD                   0x00    /* 16-bits register */
+#define SPI_6338_INT_STATUS            0x02
+#define SPI_6338_INT_MASK_ST           0x03
+#define SPI_6338_INT_MASK              0x04
+#define SPI_6338_ST                    0x05
+#define SPI_6338_CLK_CFG               0x06
+#define SPI_6338_FILL_BYTE             0x07
+#define SPI_6338_MSG_TAIL              0x09
+#define SPI_6338_RX_TAIL               0x0b
+#define SPI_6338_MSG_CTL               0x40
+#define SPI_6338_MSG_DATA              0x41
+#define SPI_6338_MSG_DATA_SIZE         0x3f
+#define SPI_6338_RX_DATA               0x80
+#define SPI_6338_RX_DATA_SIZE          0x3f
+
+/* BCM 6348 SPI core */
+#define SPI_6348_CMD                   0x00    /* 16-bits register */
+#define SPI_6348_INT_STATUS            0x02
+#define SPI_6348_INT_MASK_ST           0x03
+#define SPI_6348_INT_MASK              0x04
+#define SPI_6348_ST                    0x05
+#define SPI_6348_CLK_CFG               0x06
+#define SPI_6348_FILL_BYTE             0x07
+#define SPI_6348_MSG_TAIL              0x09
+#define SPI_6348_RX_TAIL               0x0b
+#define SPI_6348_MSG_CTL               0x40
+#define SPI_6348_MSG_DATA              0x41
+#define SPI_6348_MSG_DATA_SIZE         0x3f
+#define SPI_6348_RX_DATA               0x80
+#define SPI_6348_RX_DATA_SIZE          0x3f
+
+/* BCM 6358 SPI core */
+#define SPI_6358_MSG_CTL               0x00    /* 16-bits register */
+#define SPI_6358_MSG_DATA              0x02
+#define SPI_6358_MSG_DATA_SIZE         0x21e
+#define SPI_6358_RX_DATA               0x400
+#define SPI_6358_RX_DATA_SIZE          0x220
+#define SPI_6358_CMD                   0x700   /* 16-bits register */
+#define SPI_6358_INT_STATUS            0x702
+#define SPI_6358_INT_MASK_ST           0x703
+#define SPI_6358_INT_MASK              0x704
+#define SPI_6358_ST                    0x705
+#define SPI_6358_CLK_CFG               0x706
+#define SPI_6358_FILL_BYTE             0x707
+#define SPI_6358_MSG_TAIL              0x709
+#define SPI_6358_RX_TAIL               0x70B
+
+/* BCM 6358 SPI core */
+#define SPI_6368_MSG_CTL               0x00    /* 16-bits register */
+#define SPI_6368_MSG_DATA              0x02
+#define SPI_6368_MSG_DATA_SIZE         0x21e
+#define SPI_6368_RX_DATA               0x400
+#define SPI_6368_RX_DATA_SIZE          0x220
+#define SPI_6368_CMD                   0x700   /* 16-bits register */
+#define SPI_6368_INT_STATUS            0x702
+#define SPI_6368_INT_MASK_ST           0x703
+#define SPI_6368_INT_MASK              0x704
+#define SPI_6368_ST                    0x705
+#define SPI_6368_CLK_CFG               0x706
+#define SPI_6368_FILL_BYTE             0x707
+#define SPI_6368_MSG_TAIL              0x709
+#define SPI_6368_RX_TAIL               0x70B
+
+/* Shared SPI definitions */
+
+/* Message configuration */
+#define SPI_FD_RW                      0x00
+#define SPI_HD_W                       0x01
+#define SPI_HD_R                       0x02
+#define SPI_BYTE_CNT_SHIFT             0
+#define SPI_MSG_TYPE_SHIFT             14
+
+/* Command */
+#define SPI_CMD_NOOP                   0x00
+#define SPI_CMD_SOFT_RESET             0x01
+#define SPI_CMD_HARD_RESET             0x02
+#define SPI_CMD_START_IMMEDIATE                0x03
+#define SPI_CMD_COMMAND_SHIFT          0
+#define SPI_CMD_COMMAND_MASK           0x000f
+#define SPI_CMD_DEVICE_ID_SHIFT                4
+#define SPI_CMD_PREPEND_BYTE_CNT_SHIFT 8
+#define SPI_CMD_ONE_BYTE_SHIFT         11
+#define SPI_CMD_ONE_WIRE_SHIFT         12
+#define SPI_DEV_ID_0                   0
+#define SPI_DEV_ID_1                   1
+#define SPI_DEV_ID_2                   2
+#define SPI_DEV_ID_3                   3
+
+/* Interrupt mask */
+#define SPI_INTR_CMD_DONE              0x01
+#define SPI_INTR_RX_OVERFLOW           0x02
+#define SPI_INTR_TX_UNDERFLOW          0x04
+#define SPI_INTR_TX_OVERFLOW           0x08
+#define SPI_INTR_RX_UNDERFLOW          0x10
+#define SPI_INTR_CLEAR_ALL             0x1f
+
+/* Status */
+#define SPI_RX_EMPTY                   0x02
+#define SPI_CMD_BUSY                   0x04
+#define SPI_SERIAL_BUSY                        0x08
+
+/* Clock configuration */
+#define SPI_CLK_20MHZ                  0x00
+#define SPI_CLK_0_391MHZ               0x01
+#define SPI_CLK_0_781MHZ               0x02 /* default */
+#define SPI_CLK_1_563MHZ               0x03
+#define SPI_CLK_3_125MHZ               0x04
+#define SPI_CLK_6_250MHZ               0x05
+#define SPI_CLK_12_50MHZ               0x06
+#define SPI_CLK_MASK                   0x07
+#define SPI_SSOFFTIME_MASK             0x38
+#define SPI_SSOFFTIME_SHIFT            3
+#define SPI_BYTE_SWAP                  0x80
+
+/*************************************************************************
+ * _REG relative to RSET_MISC
+ *************************************************************************/
+#define MISC_SERDES_CTRL_REG           0x0
+#define SERDES_PCIE_EN                 (1 << 0)
+#define SERDES_PCIE_EXD_EN             (1 << 15)
+
+#define MISC_STRAPBUS_6328_REG         0x240
+#define STRAPBUS_6328_FCVO_SHIFT       7
+#define STRAPBUS_6328_FCVO_MASK                (0x1f << STRAPBUS_6328_FCVO_SHIFT)
+#define STRAPBUS_6328_BOOT_SEL_SERIAL  (1 << 28)
+#define STRAPBUS_6328_BOOT_SEL_NAND    (0 << 28)
+
+/*************************************************************************
+ * _REG relative to RSET_PCIE
+ *************************************************************************/
+
+#define PCIE_CONFIG2_REG               0x408
+#define CONFIG2_BAR1_SIZE_EN           1
+#define CONFIG2_BAR1_SIZE_MASK         0xf
+
+#define PCIE_IDVAL3_REG                        0x43c
+#define IDVAL3_CLASS_CODE_MASK         0xffffff
+#define IDVAL3_SUBCLASS_SHIFT          8
+#define IDVAL3_CLASS_SHIFT             16
+
+#define PCIE_DLSTATUS_REG              0x1048
+#define DLSTATUS_PHYLINKUP             (1 << 13)
+
+#define PCIE_BRIDGE_OPT1_REG           0x2820
+#define OPT1_RD_BE_OPT_EN              (1 << 7)
+#define OPT1_RD_REPLY_BE_FIX_EN                (1 << 9)
+#define OPT1_PCIE_BRIDGE_HOLE_DET_EN   (1 << 11)
+#define OPT1_L1_INT_STATUS_MASK_POL    (1 << 12)
+
+#define PCIE_BRIDGE_OPT2_REG           0x2824
+#define OPT2_UBUS_UR_DECODE_DIS                (1 << 2)
+#define OPT2_TX_CREDIT_CHK_EN          (1 << 4)
+#define OPT2_CFG_TYPE1_BD_SEL          (1 << 7)
+#define OPT2_CFG_TYPE1_BUS_NO_SHIFT    16
+#define OPT2_CFG_TYPE1_BUS_NO_MASK     (0xff << OPT2_CFG_TYPE1_BUS_NO_SHIFT)
+
+#define PCIE_BRIDGE_BAR0_BASEMASK_REG  0x2828
+#define PCIE_BRIDGE_BAR1_BASEMASK_REG  0x2830
+#define BASEMASK_REMAP_EN              (1 << 0)
+#define BASEMASK_SWAP_EN               (1 << 1)
+#define BASEMASK_MASK_SHIFT            4
+#define BASEMASK_MASK_MASK             (0xfff << BASEMASK_MASK_SHIFT)
+#define BASEMASK_BASE_SHIFT            20
+#define BASEMASK_BASE_MASK             (0xfff << BASEMASK_BASE_SHIFT)
+
+#define PCIE_BRIDGE_BAR0_REBASE_ADDR_REG 0x282c
+#define PCIE_BRIDGE_BAR1_REBASE_ADDR_REG 0x2834
+#define REBASE_ADDR_BASE_SHIFT         20
+#define REBASE_ADDR_BASE_MASK          (0xfff << REBASE_ADDR_BASE_SHIFT)
+
+#define PCIE_BRIDGE_RC_INT_MASK_REG    0x2854
+#define PCIE_RC_INT_A                  (1 << 0)
+#define PCIE_RC_INT_B                  (1 << 1)
+#define PCIE_RC_INT_C                  (1 << 2)
+#define PCIE_RC_INT_D                  (1 << 3)
+
+#define PCIE_DEVICE_OFFSET             0x8000
+
 #endif /* BCM63XX_REGS_H_ */
index ef94ba73646e315592c303cf743474f09291d538..30931c42379d95841ff667bc2036e1f4939dfe51 100644 (file)
@@ -18,6 +18,7 @@ static inline int is_bcm63xx_internal_registers(phys_t offset)
                if (offset >= 0xfff00000)
                        return 1;
                break;
+       case BCM6328_CPU_ID:
        case BCM6368_CPU_ID:
                if (offset >= 0xb0000000 && offset < 0xb1000000)
                        return 1;
index 5b05f186e3952744bb932508d631932209e9e530..418992042f6fcbc23f1612a82ee886cd969c5fa5 100644 (file)
@@ -41,61 +41,26 @@ enum octeon_irq {
        OCTEON_IRQ_TWSI,
        OCTEON_IRQ_TWSI2,
        OCTEON_IRQ_RML,
-       OCTEON_IRQ_TRACE0,
-       OCTEON_IRQ_GMX_DRP0 = OCTEON_IRQ_TRACE0 + 4,
-       OCTEON_IRQ_IPD_DRP = OCTEON_IRQ_GMX_DRP0 + 5,
-       OCTEON_IRQ_KEY_ZERO,
        OCTEON_IRQ_TIMER0,
        OCTEON_IRQ_TIMER1,
        OCTEON_IRQ_TIMER2,
        OCTEON_IRQ_TIMER3,
        OCTEON_IRQ_USB0,
        OCTEON_IRQ_USB1,
-       OCTEON_IRQ_PCM,
-       OCTEON_IRQ_MPI,
-       OCTEON_IRQ_POWIQ,
-       OCTEON_IRQ_IPDPPTHR,
        OCTEON_IRQ_MII0,
        OCTEON_IRQ_MII1,
        OCTEON_IRQ_BOOTDMA,
-
-       OCTEON_IRQ_NAND,
-       OCTEON_IRQ_MIO,         /* Summary of MIO_BOOT_ERR */
-       OCTEON_IRQ_IOB,         /* Summary of IOB_INT_SUM */
-       OCTEON_IRQ_FPA,         /* Summary of FPA_INT_SUM */
-       OCTEON_IRQ_POW,         /* Summary of POW_ECC_ERR */
-       OCTEON_IRQ_L2C,         /* Summary of L2C_INT_STAT */
-       OCTEON_IRQ_IPD,         /* Summary of IPD_INT_SUM */
-       OCTEON_IRQ_PIP,         /* Summary of PIP_INT_REG */
-       OCTEON_IRQ_PKO,         /* Summary of PKO_REG_ERROR */
-       OCTEON_IRQ_ZIP,         /* Summary of ZIP_ERROR */
-       OCTEON_IRQ_TIM,         /* Summary of TIM_REG_ERROR */
-       OCTEON_IRQ_RAD,         /* Summary of RAD_REG_ERROR */
-       OCTEON_IRQ_KEY,         /* Summary of KEY_INT_SUM */
-       OCTEON_IRQ_DFA,         /* Summary of DFA */
-       OCTEON_IRQ_USBCTL,      /* Summary of USBN0_INT_SUM */
-       OCTEON_IRQ_SLI,         /* Summary of SLI_INT_SUM */
-       OCTEON_IRQ_DPI,         /* Summary of DPI_INT_SUM */
-       OCTEON_IRQ_AGX0,        /* Summary of GMX0*+PCS0_INT*_REG */
-       OCTEON_IRQ_AGL  = OCTEON_IRQ_AGX0 + 5,
-       OCTEON_IRQ_PTP,
-       OCTEON_IRQ_PEM0,
-       OCTEON_IRQ_PEM1,
-       OCTEON_IRQ_SRIO0,
-       OCTEON_IRQ_SRIO1,
-       OCTEON_IRQ_LMC0,
-       OCTEON_IRQ_DFM = OCTEON_IRQ_LMC0 + 4,           /* Summary of DFM */
-       OCTEON_IRQ_RST,
+#ifndef CONFIG_PCI_MSI
+       OCTEON_IRQ_LAST = 127
+#endif
 };
 
 #ifdef CONFIG_PCI_MSI
-/* 152 - 407 represent the MSI interrupts 0-255 */
-#define OCTEON_IRQ_MSI_BIT0    (OCTEON_IRQ_RST + 1)
+/* 256 - 511 represent the MSI interrupts 0-255 */
+#define OCTEON_IRQ_MSI_BIT0    (256)
 
 #define OCTEON_IRQ_MSI_LAST      (OCTEON_IRQ_MSI_BIT0 + 255)
 #define OCTEON_IRQ_LAST          (OCTEON_IRQ_MSI_LAST + 1)
-#else
-#define OCTEON_IRQ_LAST         (OCTEON_IRQ_RST + 1)
 #endif
 
 #endif
index bb5b9a4e29c8226846796a162e1b447f4a0e4ab8..986982db7c38c95cf8ca0e4beac9bcee6570f8fe 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
+#define JZ_NAND_NUM_BANKS 4
+
 struct jz_nand_platform_data {
        int                     num_partitions;
        struct mtd_partition    *partitions;
@@ -27,6 +29,8 @@ struct jz_nand_platform_data {
 
        unsigned int busy_gpio;
 
+       unsigned char banks[JZ_NAND_NUM_BANKS];
+
        void (*ident_callback)(struct platform_device *, struct nand_chip *,
                                struct mtd_partition **, int *num_partitions);
 };
index 1e29b9dd1d7395752d401fca112b2f1f528357c8..06367c37e1b2dd2c04154143a17b9c07e1ae6e30 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/io.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/kconfig.h>
 
 /* loongson internal northbridge initialization */
 extern void bonito_irq_init(void);
@@ -66,7 +67,7 @@ extern int mach_i8259_irq(void);
 #include <linux/interrupt.h>
 static inline void do_perfcnt_IRQ(void)
 {
-#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE)
+#if IS_ENABLED(CONFIG_OPROFILE)
        do_IRQ(LOONGSON2_PERFCNT_IRQ);
 #endif
 }
diff --git a/arch/mips/include/asm/mach-loongson1/irq.h b/arch/mips/include/asm/mach-loongson1/irq.h
new file mode 100644 (file)
index 0000000..da96ed4
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * IRQ mappings for Loongson 1
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+#ifndef __ASM_MACH_LOONGSON1_IRQ_H
+#define __ASM_MACH_LOONGSON1_IRQ_H
+
+/*
+ * CPU core Interrupt Numbers
+ */
+#define MIPS_CPU_IRQ_BASE              0
+#define MIPS_CPU_IRQ(x)                        (MIPS_CPU_IRQ_BASE + (x))
+
+#define SOFTINT0_IRQ                   MIPS_CPU_IRQ(0)
+#define SOFTINT1_IRQ                   MIPS_CPU_IRQ(1)
+#define INT0_IRQ                       MIPS_CPU_IRQ(2)
+#define INT1_IRQ                       MIPS_CPU_IRQ(3)
+#define INT2_IRQ                       MIPS_CPU_IRQ(4)
+#define INT3_IRQ                       MIPS_CPU_IRQ(5)
+#define INT4_IRQ                       MIPS_CPU_IRQ(6)
+#define TIMER_IRQ                      MIPS_CPU_IRQ(7)         /* cpu timer */
+
+#define MIPS_CPU_IRQS          (MIPS_CPU_IRQ(7) + 1 - MIPS_CPU_IRQ_BASE)
+
+/*
+ * INT0~3 Interrupt Numbers
+ */
+#define LS1X_IRQ_BASE                  MIPS_CPU_IRQS
+#define LS1X_IRQ(n, x)                 (LS1X_IRQ_BASE + (n << 5) + (x))
+
+#define LS1X_UART0_IRQ                 LS1X_IRQ(0, 2)
+#define LS1X_UART1_IRQ                 LS1X_IRQ(0, 3)
+#define LS1X_UART2_IRQ                 LS1X_IRQ(0, 4)
+#define LS1X_UART3_IRQ                 LS1X_IRQ(0, 5)
+#define LS1X_CAN0_IRQ                  LS1X_IRQ(0, 6)
+#define LS1X_CAN1_IRQ                  LS1X_IRQ(0, 7)
+#define LS1X_SPI0_IRQ                  LS1X_IRQ(0, 8)
+#define LS1X_SPI1_IRQ                  LS1X_IRQ(0, 9)
+#define LS1X_AC97_IRQ                  LS1X_IRQ(0, 10)
+#define LS1X_DMA0_IRQ                  LS1X_IRQ(0, 13)
+#define LS1X_DMA1_IRQ                  LS1X_IRQ(0, 14)
+#define LS1X_DMA2_IRQ                  LS1X_IRQ(0, 15)
+#define LS1X_PWM0_IRQ                  LS1X_IRQ(0, 17)
+#define LS1X_PWM1_IRQ                  LS1X_IRQ(0, 18)
+#define LS1X_PWM2_IRQ                  LS1X_IRQ(0, 19)
+#define LS1X_PWM3_IRQ                  LS1X_IRQ(0, 20)
+#define LS1X_RTC_INT0_IRQ              LS1X_IRQ(0, 21)
+#define LS1X_RTC_INT1_IRQ              LS1X_IRQ(0, 22)
+#define LS1X_RTC_INT2_IRQ              LS1X_IRQ(0, 23)
+#define LS1X_TOY_INT0_IRQ              LS1X_IRQ(0, 24)
+#define LS1X_TOY_INT1_IRQ              LS1X_IRQ(0, 25)
+#define LS1X_TOY_INT2_IRQ              LS1X_IRQ(0, 26)
+#define LS1X_RTC_TICK_IRQ              LS1X_IRQ(0, 27)
+#define LS1X_TOY_TICK_IRQ              LS1X_IRQ(0, 28)
+
+#define LS1X_EHCI_IRQ                  LS1X_IRQ(1, 0)
+#define LS1X_OHCI_IRQ                  LS1X_IRQ(1, 1)
+#define LS1X_GMAC0_IRQ                 LS1X_IRQ(1, 2)
+#define LS1X_GMAC1_IRQ                 LS1X_IRQ(1, 3)
+
+#define LS1X_IRQS              (LS1X_IRQ(4, 31) + 1 - LS1X_IRQ_BASE)
+
+#define NR_IRQS                        (MIPS_CPU_IRQS + LS1X_IRQS)
+
+#endif /* __ASM_MACH_LOONGSON1_IRQ_H */
diff --git a/arch/mips/include/asm/mach-loongson1/loongson1.h b/arch/mips/include/asm/mach-loongson1/loongson1.h
new file mode 100644 (file)
index 0000000..4e18e88
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * Register mappings for Loongson 1
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+#ifndef __ASM_MACH_LOONGSON1_LOONGSON1_H
+#define __ASM_MACH_LOONGSON1_LOONGSON1_H
+
+#define DEFAULT_MEMSIZE                        256     /* If no memsize provided */
+
+/* Loongson 1 Register Bases */
+#define LS1X_INTC_BASE                 0x1fd01040
+#define LS1X_EHCI_BASE                 0x1fe00000
+#define LS1X_OHCI_BASE                 0x1fe08000
+#define LS1X_GMAC0_BASE                        0x1fe10000
+#define LS1X_GMAC1_BASE                        0x1fe20000
+
+#define LS1X_UART0_BASE                        0x1fe40000
+#define LS1X_UART1_BASE                        0x1fe44000
+#define LS1X_UART2_BASE                        0x1fe48000
+#define LS1X_UART3_BASE                        0x1fe4c000
+#define LS1X_CAN0_BASE                 0x1fe50000
+#define LS1X_CAN1_BASE                 0x1fe54000
+#define LS1X_I2C0_BASE                 0x1fe58000
+#define LS1X_I2C1_BASE                 0x1fe68000
+#define LS1X_I2C2_BASE                 0x1fe70000
+#define LS1X_PWM_BASE                  0x1fe5c000
+#define LS1X_WDT_BASE                  0x1fe5c060
+#define LS1X_RTC_BASE                  0x1fe64000
+#define LS1X_AC97_BASE                 0x1fe74000
+#define LS1X_NAND_BASE                 0x1fe78000
+#define LS1X_CLK_BASE                  0x1fe78030
+
+#include <regs-clk.h>
+#include <regs-wdt.h>
+
+#endif /* __ASM_MACH_LOONGSON1_LOONGSON1_H */
diff --git a/arch/mips/include/asm/mach-loongson1/platform.h b/arch/mips/include/asm/mach-loongson1/platform.h
new file mode 100644 (file)
index 0000000..2f17161
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+#ifndef __ASM_MACH_LOONGSON1_PLATFORM_H
+#define __ASM_MACH_LOONGSON1_PLATFORM_H
+
+#include <linux/platform_device.h>
+
+extern struct platform_device ls1x_uart_device;
+extern struct platform_device ls1x_eth0_device;
+extern struct platform_device ls1x_ehci_device;
+extern struct platform_device ls1x_rtc_device;
+
+void ls1x_serial_setup(void);
+
+#endif /* __ASM_MACH_LOONGSON1_PLATFORM_H */
diff --git a/arch/mips/include/asm/mach-loongson1/prom.h b/arch/mips/include/asm/mach-loongson1/prom.h
new file mode 100644 (file)
index 0000000..b871dc4
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_MACH_LOONGSON1_PROM_H
+#define __ASM_MACH_LOONGSON1_PROM_H
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+/* environment arguments from bootloader */
+extern unsigned long memsize, highmemsize;
+
+/* loongson-specific command line, env and memory initialization */
+extern char *prom_getenv(char *name);
+extern void __init prom_init_cmdline(void);
+
+#endif /* __ASM_MACH_LOONGSON1_PROM_H */
diff --git a/arch/mips/include/asm/mach-loongson1/regs-clk.h b/arch/mips/include/asm/mach-loongson1/regs-clk.h
new file mode 100644 (file)
index 0000000..8efa7fb
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * Loongson 1 Clock Register Definitions.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_MACH_LOONGSON1_REGS_CLK_H
+#define __ASM_MACH_LOONGSON1_REGS_CLK_H
+
+#define LS1X_CLK_REG(x) \
+               ((void __iomem *)KSEG1ADDR(LS1X_CLK_BASE + (x)))
+
+#define LS1X_CLK_PLL_FREQ              LS1X_CLK_REG(0x0)
+#define LS1X_CLK_PLL_DIV               LS1X_CLK_REG(0x4)
+
+/* Clock PLL Divisor Register Bits */
+#define DIV_DC_EN                      (0x1 << 31)
+#define DIV_DC                         (0x1f << 26)
+#define DIV_CPU_EN                     (0x1 << 25)
+#define DIV_CPU                                (0x1f << 20)
+#define DIV_DDR_EN                     (0x1 << 19)
+#define DIV_DDR                                (0x1f << 14)
+
+#define DIV_DC_SHIFT                   26
+#define DIV_CPU_SHIFT                  20
+#define DIV_DDR_SHIFT                  14
+
+#endif /* __ASM_MACH_LOONGSON1_REGS_CLK_H */
diff --git a/arch/mips/include/asm/mach-loongson1/regs-wdt.h b/arch/mips/include/asm/mach-loongson1/regs-wdt.h
new file mode 100644 (file)
index 0000000..f897de6
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * Loongson 1 watchdog register definitions.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_MACH_LOONGSON1_REGS_WDT_H
+#define __ASM_MACH_LOONGSON1_REGS_WDT_H
+
+#define LS1X_WDT_REG(x) \
+               ((void __iomem *)KSEG1ADDR(LS1X_WDT_BASE + (x)))
+
+#define LS1X_WDT_EN                    LS1X_WDT_REG(0x0)
+#define LS1X_WDT_SET                   LS1X_WDT_REG(0x4)
+#define LS1X_WDT_TIMER                 LS1X_WDT_REG(0x8)
+
+#endif /* __ASM_MACH_LOONGSON1_REGS_WDT_H */
diff --git a/arch/mips/include/asm/mach-loongson1/war.h b/arch/mips/include/asm/mach-loongson1/war.h
new file mode 100644 (file)
index 0000000..e3680a8
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MACH_LOONGSON1_WAR_H
+#define __ASM_MACH_LOONGSON1_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR    0
+#define R4600_V1_HIT_CACHEOP_WAR       0
+#define R4600_V2_HIT_CACHEOP_WAR       0
+#define R5432_CP0_INTERRUPT_WAR                0
+#define BCM1250_M3_WAR                 0
+#define SIBYTE_1956_WAR                        0
+#define MIPS4K_ICACHE_REFILL_WAR       0
+#define MIPS_CACHE_SYNC_WAR            0
+#define TX49XX_ICACHE_INDEX_INV_WAR    0
+#define RM9000_CDEX_SMP_WAR            0
+#define ICACHE_REFILLS_WORKAROUND_WAR  0
+#define R10000_LLSC_WAR                        0
+#define MIPS34K_MISSED_ITLB_WAR                0
+
+#endif /* __ASM_MACH_LOONGSON1_WAR_H */
index d193fb68cf270d66e734fc7ef88613417cdb94be..966db4be377ca700d94795f10d3b345f8d250621 100644 (file)
@@ -48,7 +48,6 @@
 #define cpu_has_userlocal      1
 #define cpu_has_mips32r2       1
 #define cpu_has_mips64r2       1
-#define cpu_has_dc_aliases     1
 #else
 #error "Unknown Netlogic CPU"
 #endif
index 5e6912fdd0ed2bbe3a2333cb14709c71bb8db93b..490867b03c8f6cb9d1834ed87e590928830aec26 100644 (file)
@@ -9,7 +9,7 @@
 #define ioswabb(a, x)          (x)
 #define __mem_ioswabb(a, x)    (x)
 #if defined(CONFIG_TOSHIBA_RBTX4939) && \
-       (defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)) && \
+       IS_ENABLED(CONFIG_SMC91X) && \
        defined(__BIG_ENDIAN)
 #define NEEDS_TXX9_IOSWABW
 extern u16 (*ioswabw)(volatile u16 *a, u16 x);
index e71ff4c317f2d0bdd8df430b0f439286abb4559f..5b3cb8553e9abafa3d3bb18b4628d1064b1bff12 100644 (file)
@@ -28,6 +28,9 @@
 #define read_c0_vpeconf0()             __read_32bit_c0_register($1, 2)
 #define write_c0_vpeconf0(val)         __write_32bit_c0_register($1, 2, val)
 
+#define read_c0_vpeconf1()             __read_32bit_c0_register($1, 3)
+#define write_c0_vpeconf1(val)         __write_32bit_c0_register($1, 3, val)
+
 #define read_c0_tcstatus()             __read_32bit_c0_register($2, 1)
 #define write_c0_tcstatus(val)         __write_32bit_c0_register($2, 1, val)
 
 #define VPECONF0_XTC_SHIFT     21
 #define VPECONF0_XTC           (_ULCAST_(0xff) << VPECONF0_XTC_SHIFT)
 
+/* VPEConf1 fields (per VPE) */
+#define VPECONF1_NCP1_SHIFT    0
+#define VPECONF1_NCP1          (_ULCAST_(0xff) << VPECONF1_NCP1_SHIFT)
+#define VPECONF1_NCP2_SHIFT    10
+#define VPECONF1_NCP2          (_ULCAST_(0xff) << VPECONF1_NCP2_SHIFT)
+#define VPECONF1_NCX_SHIFT     20
+#define VPECONF1_NCX           (_ULCAST_(0xff) << VPECONF1_NCX_SHIFT)
+
 /* TCStatus fields (per TC) */
 #define TCSTATUS_TASID         (_ULCAST_(0xff))
 #define TCSTATUS_IXMT_SHIFT    10
@@ -350,6 +361,8 @@ do {                                                                        \
 #define write_vpe_c0_vpecontrol(val)   mttc0(1, 1, val)
 #define read_vpe_c0_vpeconf0()         mftc0(1, 2)
 #define write_vpe_c0_vpeconf0(val)     mttc0(1, 2, val)
+#define read_vpe_c0_vpeconf1()         mftc0(1, 3)
+#define write_vpe_c0_vpeconf1(val)     mttc0(1, 3, val)
 #define read_vpe_c0_count()            mftc0(9, 0)
 #define write_vpe_c0_count(val)                mttc0(9, 0, val)
 #define read_vpe_c0_status()           mftc0(12, 0)
index 530008048c6227fb653ccb8b66b0319c442ce8ea..7531ecd654d651df630d1d520e71f762c47547e3 100644 (file)
@@ -117,6 +117,8 @@ search_module_dbetables(unsigned long addr)
 #define MODULE_PROC_FAMILY "RM9000 "
 #elif defined CONFIG_CPU_SB1
 #define MODULE_PROC_FAMILY "SB1 "
+#elif defined CONFIG_CPU_LOONGSON1
+#define MODULE_PROC_FAMILY "LOONGSON1 "
 #elif defined CONFIG_CPU_LOONGSON2
 #define MODULE_PROC_FAMILY "LOONGSON2 "
 #elif defined CONFIG_CPU_CAVIUM_OCTEON
index bf7d41deb9be4c90e4125df042e85cdcab0124a1..7b63a6b722a0d276d6f4c67a49b2a6042a18bacc 100644 (file)
@@ -47,7 +47,9 @@
 #define CPU_BLOCKID_MAP                10
 
 #define LSU_DEFEATURE          0x304
-#define LSU_CERRLOG_REGID      0x09
+#define LSU_DEBUG_ADDR         0x305
+#define LSU_DEBUG_DATA0                0x306
+#define LSU_CERRLOG_REGID      0x309
 #define SCHED_DEFEATURE                0x700
 
 /* Offsets of interest from the 'MAP' Block */
index 86cc3391e50cf30755a4d013ff6f3f46a9269a7c..2c63f97546404ccd9f5431bddd7e250dcf17476d 100644 (file)
@@ -36,6 +36,9 @@
 #define __NLM_HAL_IOMAP_H__
 
 #define XLP_DEFAULT_IO_BASE             0x18000000
+#define XLP_DEFAULT_PCI_ECFG_BASE      XLP_DEFAULT_IO_BASE
+#define XLP_DEFAULT_PCI_CFG_BASE       0x1c000000
+
 #define NMI_BASE                       0xbfc00000
 #define        XLP_IO_CLK                      133333333
 
 #define        PCI_DEVICE_ID_NLM_PIC           0x1003
 #define        PCI_DEVICE_ID_NLM_PCIE          0x1004
 #define        PCI_DEVICE_ID_NLM_EHCI          0x1007
-#define        PCI_DEVICE_ID_NLM_ILK           0x1008
+#define        PCI_DEVICE_ID_NLM_OHCI          0x1008
 #define        PCI_DEVICE_ID_NLM_NAE           0x1009
 #define        PCI_DEVICE_ID_NLM_POE           0x100A
 #define        PCI_DEVICE_ID_NLM_FMN           0x100B
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h b/arch/mips/include/asm/netlogic/xlp-hal/pcibus.h
new file mode 100644 (file)
index 0000000..66c323d
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * All Rights Reserved
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the Broadcom
+ * license below:
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``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 BROADCOM 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.
+ */
+
+#ifndef __NLM_HAL_PCIBUS_H__
+#define        __NLM_HAL_PCIBUS_H__
+
+/* PCIE Memory and IO regions */
+#define        PCIE_MEM_BASE                   0xd0000000ULL
+#define        PCIE_MEM_LIMIT                  0xdfffffffULL
+#define        PCIE_IO_BASE                    0x14000000ULL
+#define        PCIE_IO_LIMIT                   0x15ffffffULL
+
+#define        PCIE_BRIDGE_CMD                 0x1
+#define        PCIE_BRIDGE_MSI_CAP             0x14
+#define        PCIE_BRIDGE_MSI_ADDRL           0x15
+#define        PCIE_BRIDGE_MSI_ADDRH           0x16
+#define        PCIE_BRIDGE_MSI_DATA            0x17
+
+/* XLP Global PCIE configuration space registers */
+#define        PCIE_BYTE_SWAP_MEM_BASE         0x247
+#define        PCIE_BYTE_SWAP_MEM_LIM          0x248
+#define        PCIE_BYTE_SWAP_IO_BASE          0x249
+#define        PCIE_BYTE_SWAP_IO_LIM           0x24A
+#define        PCIE_MSI_STATUS                 0x25A
+#define        PCIE_MSI_EN                     0x25B
+#define        PCIE_INT_EN0                    0x261
+
+/* PCIE_MSI_EN */
+#define        PCIE_MSI_VECTOR_INT_EN          0xFFFFFFFF
+
+/* PCIE_INT_EN0 */
+#define        PCIE_MSI_INT_EN                 (1 << 9)
+
+#ifndef __ASSEMBLY__
+
+#define        nlm_read_pcie_reg(b, r)         nlm_read_reg(b, r)
+#define        nlm_write_pcie_reg(b, r, v)     nlm_write_reg(b, r, v)
+#define        nlm_get_pcie_base(node, inst)   \
+                       nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, inst))
+#define        nlm_get_pcie_regbase(node, inst)        \
+                       (nlm_get_pcie_base(node, inst) + XLP_IO_PCI_HDRSZ)
+
+int xlp_pcie_link_irt(int link);
+#endif
+#endif /* __NLM_HAL_PCIBUS_H__ */
index b6628f7ccf74b027edc6f23a4ab5b3797a2792f5..ad8b80233a63b255b12a8227bce551a819711560 100644 (file)
 #define PIC_NUM_USB_IRTS               6
 #define PIC_IRT_USB_0_INDEX            115
 #define PIC_IRT_EHCI_0_INDEX           115
+#define PIC_IRT_OHCI_0_INDEX           116
+#define PIC_IRT_OHCI_1_INDEX           117
 #define PIC_IRT_EHCI_1_INDEX           118
+#define PIC_IRT_OHCI_2_INDEX           119
+#define PIC_IRT_OHCI_3_INDEX           120
 #define PIC_IRT_USB_INDEX(num)         ((num) + PIC_IRT_USB_0_INDEX)
 /* 115 to 120 */
 #define PIC_IRT_GDX_INDEX              121
diff --git a/arch/mips/include/asm/netlogic/xlp-hal/usb.h b/arch/mips/include/asm/netlogic/xlp-hal/usb.h
new file mode 100644 (file)
index 0000000..a9cd350
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * All Rights Reserved
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the Broadcom
+ * license below:
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``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 BROADCOM 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.
+ */
+
+#ifndef __NLM_HAL_USB_H__
+#define __NLM_HAL_USB_H__
+
+#define USB_CTL_0                      0x01
+#define USB_PHY_0                      0x0A
+#define USB_PHY_RESET                  0x01
+#define USB_PHY_PORT_RESET_0           0x10
+#define USB_PHY_PORT_RESET_1           0x20
+#define USB_CONTROLLER_RESET           0x01
+#define USB_INT_STATUS                 0x0E
+#define USB_INT_EN                     0x0F
+#define USB_PHY_INTERRUPT_EN           0x01
+#define USB_OHCI_INTERRUPT_EN          0x02
+#define USB_OHCI_INTERRUPT1_EN         0x04
+#define USB_OHCI_INTERRUPT2_EN         0x08
+#define USB_CTRL_INTERRUPT_EN          0x10
+
+#ifndef __ASSEMBLY__
+
+#define nlm_read_usb_reg(b, r)                 nlm_read_reg(b, r)
+#define nlm_write_usb_reg(b, r, v)             nlm_write_reg(b, r, v)
+#define nlm_get_usb_pcibase(node, inst)                \
+       nlm_pcicfg_base(XLP_IO_USB_OFFSET(node, inst))
+#define nlm_get_usb_hcd_base(node, inst)       \
+       nlm_xkphys_map_pcibar0(nlm_get_usb_pcibase(node, inst))
+#define nlm_get_usb_regbase(node, inst)                \
+       (nlm_get_usb_pcibase(node, inst) + XLP_IO_PCI_HDRSZ)
+
+#endif
+#endif /* __NLM_HAL_USB_H__ */
index 1540588e396dbee6600755a3bb3ad2417d8b962e..7e47209327a542b3c090560243690faebe8dda88 100644 (file)
 #ifndef _NLM_HAL_XLP_H
 #define _NLM_HAL_XLP_H
 
-#define PIC_UART_0_IRQ           17
-#define PIC_UART_1_IRQ           18
+#define PIC_UART_0_IRQ                 17
+#define PIC_UART_1_IRQ                 18
+#define PIC_PCIE_LINK_0_IRQ            19
+#define PIC_PCIE_LINK_1_IRQ            20
+#define PIC_PCIE_LINK_2_IRQ            21
+#define PIC_PCIE_LINK_3_IRQ            22
+#define PIC_EHCI_0_IRQ                 23
+#define PIC_EHCI_1_IRQ                 24
+#define PIC_OHCI_0_IRQ                 25
+#define PIC_OHCI_1_IRQ                 26
+#define PIC_OHCI_2_IRQ                 27
+#define PIC_OHCI_3_IRQ                 28
+#define PIC_MMC_IRQ                    29
+#define PIC_I2C_0_IRQ                  30
+#define PIC_I2C_1_IRQ                  31
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/mips/include/asm/netlogic/xlr/bridge.h b/arch/mips/include/asm/netlogic/xlr/bridge.h
new file mode 100644 (file)
index 0000000..2d02428
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * All Rights Reserved
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the Broadcom
+ * license below:
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``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 BROADCOM 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.
+ */
+#ifndef _ASM_NLM_BRIDGE_H_
+#define _ASM_NLM_BRIDGE_H_
+
+#define BRIDGE_DRAM_0_BAR              0
+#define BRIDGE_DRAM_1_BAR              1
+#define BRIDGE_DRAM_2_BAR              2
+#define BRIDGE_DRAM_3_BAR              3
+#define BRIDGE_DRAM_4_BAR              4
+#define BRIDGE_DRAM_5_BAR              5
+#define BRIDGE_DRAM_6_BAR              6
+#define BRIDGE_DRAM_7_BAR              7
+#define BRIDGE_DRAM_CHN_0_MTR_0_BAR    8
+#define BRIDGE_DRAM_CHN_0_MTR_1_BAR    9
+#define BRIDGE_DRAM_CHN_0_MTR_2_BAR    10
+#define BRIDGE_DRAM_CHN_0_MTR_3_BAR    11
+#define BRIDGE_DRAM_CHN_0_MTR_4_BAR    12
+#define BRIDGE_DRAM_CHN_0_MTR_5_BAR    13
+#define BRIDGE_DRAM_CHN_0_MTR_6_BAR    14
+#define BRIDGE_DRAM_CHN_0_MTR_7_BAR    15
+#define BRIDGE_DRAM_CHN_1_MTR_0_BAR    16
+#define BRIDGE_DRAM_CHN_1_MTR_1_BAR    17
+#define BRIDGE_DRAM_CHN_1_MTR_2_BAR    18
+#define BRIDGE_DRAM_CHN_1_MTR_3_BAR    19
+#define BRIDGE_DRAM_CHN_1_MTR_4_BAR    20
+#define BRIDGE_DRAM_CHN_1_MTR_5_BAR    21
+#define BRIDGE_DRAM_CHN_1_MTR_6_BAR    22
+#define BRIDGE_DRAM_CHN_1_MTR_7_BAR    23
+#define BRIDGE_CFG_BAR                 24
+#define BRIDGE_PHNX_IO_BAR             25
+#define BRIDGE_FLASH_BAR               26
+#define BRIDGE_SRAM_BAR                        27
+#define BRIDGE_HTMEM_BAR               28
+#define BRIDGE_HTINT_BAR               29
+#define BRIDGE_HTPIC_BAR               30
+#define BRIDGE_HTSM_BAR                        31
+#define BRIDGE_HTIO_BAR                        32
+#define BRIDGE_HTCFG_BAR               33
+#define BRIDGE_PCIXCFG_BAR             34
+#define BRIDGE_PCIXMEM_BAR             35
+#define BRIDGE_PCIXIO_BAR              36
+#define BRIDGE_DEVICE_MASK             37
+#define BRIDGE_AERR_INTR_LOG1          38
+#define BRIDGE_AERR_INTR_LOG2          39
+#define BRIDGE_AERR_INTR_LOG3          40
+#define BRIDGE_AERR_DEV_STAT           41
+#define BRIDGE_AERR1_LOG1              42
+#define BRIDGE_AERR1_LOG2              43
+#define BRIDGE_AERR1_LOG3              44
+#define BRIDGE_AERR1_DEV_STAT          45
+#define BRIDGE_AERR_INTR_EN            46
+#define BRIDGE_AERR_UPG                        47
+#define BRIDGE_AERR_CLEAR              48
+#define BRIDGE_AERR1_CLEAR             49
+#define BRIDGE_SBE_COUNTS              50
+#define BRIDGE_DBE_COUNTS              51
+#define BRIDGE_BITERR_INT_EN           52
+
+#define BRIDGE_SYS2IO_CREDITS          53
+#define BRIDGE_EVNT_CNT_CTRL1          54
+#define BRIDGE_EVNT_COUNTER1           55
+#define BRIDGE_EVNT_CNT_CTRL2          56
+#define BRIDGE_EVNT_COUNTER2           57
+#define BRIDGE_RESERVED1               58
+
+#define BRIDGE_DEFEATURE               59
+#define BRIDGE_SCRATCH0                        60
+#define BRIDGE_SCRATCH1                        61
+#define BRIDGE_SCRATCH2                        62
+#define BRIDGE_SCRATCH3                        63
+
+#endif
diff --git a/arch/mips/include/asm/netlogic/xlr/flash.h b/arch/mips/include/asm/netlogic/xlr/flash.h
new file mode 100644 (file)
index 0000000..f8aca54
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * All Rights Reserved
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the Broadcom
+ * license below:
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``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 BROADCOM 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.
+ */
+#ifndef _ASM_NLM_FLASH_H_
+#define _ASM_NLM_FLASH_H_
+
+#define FLASH_CSBASE_ADDR(cs)          (cs)
+#define FLASH_CSADDR_MASK(cs)          (0x10 + (cs))
+#define FLASH_CSDEV_PARM(cs)           (0x20 + (cs))
+#define FLASH_CSTIME_PARMA(cs)         (0x30 + (cs))
+#define FLASH_CSTIME_PARMB(cs)         (0x40 + (cs))
+
+#define FLASH_INT_MASK                 0x50
+#define FLASH_INT_STATUS               0x60
+#define FLASH_ERROR_STATUS             0x70
+#define FLASH_ERROR_ADDR               0x80
+
+#define FLASH_NAND_CLE(cs)             (0x90 + (cs))
+#define FLASH_NAND_ALE(cs)             (0xa0 + (cs))
+
+#define FLASH_NAND_CSDEV_PARAM         0x000041e6
+#define FLASH_NAND_CSTIME_PARAMA       0x4f400e22
+#define FLASH_NAND_CSTIME_PARAMB       0x000083cf
+
+#endif
index 51f6ad4aeb14397284f9ac47821293335b2641a7..8492e835b11072b8e054a6ea6948f8b22d5be6a6 100644 (file)
 #ifndef _ASM_NLM_GPIO_H
 #define _ASM_NLM_GPIO_H
 
-#define NETLOGIC_GPIO_INT_EN_REG               0
-#define NETLOGIC_GPIO_INPUT_INVERSION_REG      1
-#define NETLOGIC_GPIO_IO_DIR_REG               2
-#define NETLOGIC_GPIO_IO_DATA_WR_REG           3
-#define NETLOGIC_GPIO_IO_DATA_RD_REG           4
+#define GPIO_INT_EN_REG                        0
+#define GPIO_INPUT_INVERSION_REG       1
+#define GPIO_IO_DIR_REG                        2
+#define GPIO_IO_DATA_WR_REG            3
+#define GPIO_IO_DATA_RD_REG            4
 
-#define NETLOGIC_GPIO_SWRESET_REG              8
-#define NETLOGIC_GPIO_DRAM1_CNTRL_REG          9
-#define NETLOGIC_GPIO_DRAM1_RATIO_REG          10
-#define NETLOGIC_GPIO_DRAM1_RESET_REG          11
-#define NETLOGIC_GPIO_DRAM1_STATUS_REG         12
-#define NETLOGIC_GPIO_DRAM2_CNTRL_REG          13
-#define NETLOGIC_GPIO_DRAM2_RATIO_REG          14
-#define NETLOGIC_GPIO_DRAM2_RESET_REG          15
-#define NETLOGIC_GPIO_DRAM2_STATUS_REG         16
+#define GPIO_SWRESET_REG               8
+#define GPIO_DRAM1_CNTRL_REG           9
+#define GPIO_DRAM1_RATIO_REG           10
+#define GPIO_DRAM1_RESET_REG           11
+#define GPIO_DRAM1_STATUS_REG          12
+#define GPIO_DRAM2_CNTRL_REG           13
+#define GPIO_DRAM2_RATIO_REG           14
+#define GPIO_DRAM2_RESET_REG           15
+#define GPIO_DRAM2_STATUS_REG          16
 
-#define NETLOGIC_GPIO_PWRON_RESET_CFG_REG      21
-#define NETLOGIC_GPIO_BIST_ALL_GO_STATUS_REG   24
-#define NETLOGIC_GPIO_BIST_CPU_GO_STATUS_REG   25
-#define NETLOGIC_GPIO_BIST_DEV_GO_STATUS_REG   26
+#define GPIO_PWRON_RESET_CFG_REG       21
+#define GPIO_BIST_ALL_GO_STATUS_REG    24
+#define GPIO_BIST_CPU_GO_STATUS_REG    25
+#define GPIO_BIST_DEV_GO_STATUS_REG    26
 
-#define NETLOGIC_GPIO_FUSE_BANK_REG            35
-#define NETLOGIC_GPIO_CPU_RESET_REG            40
-#define NETLOGIC_GPIO_RNG_REG                  43
+#define GPIO_FUSE_BANK_REG             35
+#define GPIO_CPU_RESET_REG             40
+#define GPIO_RNG_REG                   43
 
-#define NETLOGIC_PWRON_RESET_PCMCIA_BOOT       17
-#define NETLOGIC_GPIO_LED_BITMAP       0x1700000
-#define NETLOGIC_GPIO_LED_0_SHIFT              20
-#define NETLOGIC_GPIO_LED_1_SHIFT              24
+#define PWRON_RESET_PCMCIA_BOOT                17
 
-#define NETLOGIC_GPIO_LED_OUTPUT_CODE_RESET    0x01
-#define NETLOGIC_GPIO_LED_OUTPUT_CODE_HARD_RESET 0x02
-#define NETLOGIC_GPIO_LED_OUTPUT_CODE_SOFT_RESET 0x03
-#define NETLOGIC_GPIO_LED_OUTPUT_CODE_MAIN     0x04
+#define GPIO_LED_BITMAP                        0x1700000
+#define GPIO_LED_0_SHIFT               20
+#define GPIO_LED_1_SHIFT               24
+
+#define GPIO_LED_OUTPUT_CODE_RESET     0x01
+#define GPIO_LED_OUTPUT_CODE_HARD_RESET 0x02
+#define GPIO_LED_OUTPUT_CODE_SOFT_RESET 0x03
+#define GPIO_LED_OUTPUT_CODE_MAIN      0x04
 
 #endif
diff --git a/arch/mips/include/asm/octeon/cvmx-helper-fpa.h b/arch/mips/include/asm/octeon/cvmx-helper-fpa.h
deleted file mode 100644 (file)
index 5ff8c93..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/***********************license start***************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2008 Cavium Networks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
- ***********************license end**************************************/
-
-/**
- * @file
- *
- * Helper functions for FPA setup.
- *
- */
-#ifndef __CVMX_HELPER_H_FPA__
-#define __CVMX_HELPER_H_FPA__
-
-/**
- * Allocate memory and initialize the FPA pools using memory
- * from cvmx-bootmem. Sizes of each element in the pools is
- * controlled by the cvmx-config.h header file. Specifying
- * zero for any parameter will cause that FPA pool to not be
- * setup. This is useful if you aren't using some of the
- * hardware and want to save memory.
- *
- * @packet_buffers:
- *               Number of packet buffers to allocate
- * @work_queue_entries:
- *               Number of work queue entries
- * @pko_buffers:
- *               PKO Command buffers. You should at minimum have two per
- *               each PKO queue.
- * @tim_buffers:
- *               TIM ring buffer command queues. At least two per timer bucket
- *               is recommened.
- * @dfa_buffers:
- *               DFA command buffer. A relatively small (32 for example)
- *               number should work.
- * Returns Zero on success, non-zero if out of memory
- */
-extern int cvmx_helper_initialize_fpa(int packet_buffers,
-                                     int work_queue_entries, int pko_buffers,
-                                     int tim_buffers, int dfa_buffers);
-
-#endif /* __CVMX_HELPER_H__ */
index 3169cd79f2ac251901e81ba366050b9c6e87eca5..0ac6b9f412bec4f998f3d6bdbc60190da35595f2 100644 (file)
@@ -61,8 +61,6 @@ typedef union {
        } s;
 } cvmx_helper_link_info_t;
 
-#include "cvmx-helper-fpa.h"
-
 #include <asm/octeon/cvmx-helper-errata.h>
 #include "cvmx-helper-loop.h"
 #include "cvmx-helper-npi.h"
index f72f768cd3a47b14b6be4397ba56a6c29103a9ae..1e2486e235735d91de52a82c05ddc34550e06b22 100644 (file)
@@ -215,11 +215,6 @@ struct octeon_cf_data {
        int             dma_engine;     /* -1 for no DMA */
 };
 
-struct octeon_i2c_data {
-       unsigned int    sys_freq;
-       unsigned int    i2c_freq;
-};
-
 extern void octeon_write_lcd(const char *s);
 extern void octeon_check_cpu_bist(void);
 extern int octeon_get_boot_debug_flag(void);
index 7206d445bab876e926cec6bd242309b893870007..8808bf548b99d2e0b4966b162f22ed4505d046e0 100644 (file)
@@ -20,9 +20,6 @@
 extern int early_init_dt_scan_memory_arch(unsigned long node,
        const char *uname, int depth, void *data);
 
-extern int reserve_mem_mach(unsigned long addr, unsigned long size);
-extern void free_mem_mach(unsigned long addr, unsigned long size);
-
 extern void device_tree_init(void);
 
 static inline unsigned long pci_address_to_pio(phys_addr_t address)
index c9736fc0632542d11920ab141ae69d2f7205579c..8935426a56ab69c4a0b444b6905819262b5a4f97 100644 (file)
@@ -33,6 +33,12 @@ typedef long asiduse;
 #endif
 #endif
 
+/*
+ * VPE Management information
+ */
+
+#define MAX_SMTC_VPES  MAX_SMTC_TLBS   /* FIXME: May not always be true. */
+
 extern asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS];
 
 struct mm_struct;
index 653a412c036ca7a6b372862d5ecc88a0038b1c89..3b92efef56d3c9fb139d374a4436d4398bf8c9d5 100644 (file)
@@ -687,7 +687,7 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n);
        __MODULE_JAL(__copy_user)                                       \
        : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)       \
        :                                                               \
-       : "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",         \
+       : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31",  \
          DADDI_SCRATCH, "memory");                                     \
        __cu_len_r;                                                     \
 })
@@ -797,7 +797,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
        ".set\treorder"                                                 \
        : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)       \
        :                                                               \
-       : "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",         \
+       : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31",  \
          DADDI_SCRATCH, "memory");                                     \
        __cu_len_r;                                                     \
 })
@@ -820,7 +820,7 @@ extern size_t __copy_user_inatomic(void *__to, const void *__from, size_t __n);
        ".set\treorder"                                                 \
        : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)       \
        :                                                               \
-       : "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",         \
+       : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31",  \
          DADDI_SCRATCH, "memory");                                     \
        __cu_len_r;                                                     \
 })
index 440a21dab575705412805809c57ce31a893825b3..3d9f75f7ffc9a7549af0e7ada587f951c9bd43ef 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (C) 2004, 2005, 2006, 2008  Thiemo Seufer
  * Copyright (C) 2005  Maciej W. Rozycki
  * Copyright (C) 2006  Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2012  MIPS Technologies, Inc.
  */
 
 #include <linux/types.h>
@@ -62,8 +63,10 @@ void __uasminit uasm_i##op(u32 **buf, unsigned int a, signed int b)
 
 Ip_u2u1s3(_addiu);
 Ip_u3u1u2(_addu);
-Ip_u2u1u3(_andi);
 Ip_u3u1u2(_and);
+Ip_u2u1u3(_andi);
+Ip_u1u2s3(_bbit0);
+Ip_u1u2s3(_bbit1);
 Ip_u1u2s3(_beq);
 Ip_u1u2s3(_beql);
 Ip_u1s2(_bgez);
@@ -72,55 +75,54 @@ Ip_u1s2(_bltz);
 Ip_u1s2(_bltzl);
 Ip_u1u2s3(_bne);
 Ip_u2s3u1(_cache);
-Ip_u1u2u3(_dmfc0);
-Ip_u1u2u3(_dmtc0);
 Ip_u2u1s3(_daddiu);
 Ip_u3u1u2(_daddu);
+Ip_u2u1msbu3(_dins);
+Ip_u2u1msbu3(_dinsm);
+Ip_u1u2u3(_dmfc0);
+Ip_u1u2u3(_dmtc0);
+Ip_u2u1u3(_drotr);
+Ip_u2u1u3(_drotr32);
 Ip_u2u1u3(_dsll);
 Ip_u2u1u3(_dsll32);
 Ip_u2u1u3(_dsra);
 Ip_u2u1u3(_dsrl);
 Ip_u2u1u3(_dsrl32);
-Ip_u2u1u3(_drotr);
-Ip_u2u1u3(_drotr32);
 Ip_u3u1u2(_dsubu);
 Ip_0(_eret);
 Ip_u1(_j);
 Ip_u1(_jal);
 Ip_u1(_jr);
 Ip_u2s3u1(_ld);
+Ip_u3u1u2(_ldx);
 Ip_u2s3u1(_ll);
 Ip_u2s3u1(_lld);
 Ip_u1s2(_lui);
 Ip_u2s3u1(_lw);
+Ip_u3u1u2(_lwx);
 Ip_u1u2u3(_mfc0);
 Ip_u1u2u3(_mtc0);
-Ip_u2u1u3(_ori);
 Ip_u3u1u2(_or);
+Ip_u2u1u3(_ori);
 Ip_u2s3u1(_pref);
 Ip_0(_rfe);
+Ip_u2u1u3(_rotr);
 Ip_u2s3u1(_sc);
 Ip_u2s3u1(_scd);
 Ip_u2s3u1(_sd);
 Ip_u2u1u3(_sll);
 Ip_u2u1u3(_sra);
 Ip_u2u1u3(_srl);
-Ip_u2u1u3(_rotr);
 Ip_u3u1u2(_subu);
 Ip_u2s3u1(_sw);
+Ip_u1(_syscall);
 Ip_0(_tlbp);
 Ip_0(_tlbr);
 Ip_0(_tlbwi);
 Ip_0(_tlbwr);
 Ip_u3u1u2(_xor);
 Ip_u2u1u3(_xori);
-Ip_u2u1msbu3(_dins);
-Ip_u2u1msbu3(_dinsm);
-Ip_u1(_syscall);
-Ip_u1u2s3(_bbit0);
-Ip_u1u2s3(_bbit1);
-Ip_u3u1u2(_lwx);
-Ip_u3u1u2(_ldx);
+
 
 /* Handle labels. */
 struct uasm_label {
@@ -145,37 +147,37 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
 
 /* convenience macros for instructions */
 #ifdef CONFIG_64BIT
+# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_daddiu(buf, rs, rt, val)
+# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_daddu(buf, rs, rt, rd)
+# define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off)
 # define UASM_i_LW(buf, rs, rt, off) uasm_i_ld(buf, rs, rt, off)
-# define UASM_i_SW(buf, rs, rt, off) uasm_i_sd(buf, rs, rt, off)
+# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_ldx(buf, rs, rt, rd)
+# define UASM_i_MFC0(buf, rt, rd...) uasm_i_dmfc0(buf, rt, rd)
+# define UASM_i_MTC0(buf, rt, rd...) uasm_i_dmtc0(buf, rt, rd)
+# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_drotr(buf, rs, rt, sh)
+# define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off)
 # define UASM_i_SLL(buf, rs, rt, sh) uasm_i_dsll(buf, rs, rt, sh)
 # define UASM_i_SRA(buf, rs, rt, sh) uasm_i_dsra(buf, rs, rt, sh)
 # define UASM_i_SRL(buf, rs, rt, sh) uasm_i_dsrl(buf, rs, rt, sh)
 # define UASM_i_SRL_SAFE(buf, rs, rt, sh) uasm_i_dsrl_safe(buf, rs, rt, sh)
-# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_drotr(buf, rs, rt, sh)
-# define UASM_i_MFC0(buf, rt, rd...) uasm_i_dmfc0(buf, rt, rd)
-# define UASM_i_MTC0(buf, rt, rd...) uasm_i_dmtc0(buf, rt, rd)
-# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_daddiu(buf, rs, rt, val)
-# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_daddu(buf, rs, rt, rd)
 # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd)
-# define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off)
-# define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off)
-# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_ldx(buf, rs, rt, rd)
+# define UASM_i_SW(buf, rs, rt, off) uasm_i_sd(buf, rs, rt, off)
 #else
+# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_addiu(buf, rs, rt, val)
+# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_addu(buf, rs, rt, rd)
+# define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off)
 # define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off)
-# define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off)
+# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_lwx(buf, rs, rt, rd)
+# define UASM_i_MFC0(buf, rt, rd...) uasm_i_mfc0(buf, rt, rd)
+# define UASM_i_MTC0(buf, rt, rd...) uasm_i_mtc0(buf, rt, rd)
+# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_rotr(buf, rs, rt, sh)
+# define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off)
 # define UASM_i_SLL(buf, rs, rt, sh) uasm_i_sll(buf, rs, rt, sh)
 # define UASM_i_SRA(buf, rs, rt, sh) uasm_i_sra(buf, rs, rt, sh)
 # define UASM_i_SRL(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh)
 # define UASM_i_SRL_SAFE(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh)
-# define UASM_i_ROTR(buf, rs, rt, sh) uasm_i_rotr(buf, rs, rt, sh)
-# define UASM_i_MFC0(buf, rt, rd...) uasm_i_mfc0(buf, rt, rd)
-# define UASM_i_MTC0(buf, rt, rd...) uasm_i_mtc0(buf, rt, rd)
-# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_addiu(buf, rs, rt, val)
-# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_addu(buf, rs, rt, rd)
 # define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd)
-# define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off)
-# define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off)
-# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_lwx(buf, rs, rt, rd)
+# define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off)
 #endif
 
 #define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off)
@@ -183,19 +185,10 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
 #define uasm_i_beqzl(buf, rs, off) uasm_i_beql(buf, rs, 0, off)
 #define uasm_i_bnez(buf, rs, off) uasm_i_bne(buf, rs, 0, off)
 #define uasm_i_bnezl(buf, rs, off) uasm_i_bnel(buf, rs, 0, off)
+#define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3)
 #define uasm_i_move(buf, a, b) UASM_i_ADDU(buf, a, 0, b)
 #define uasm_i_nop(buf) uasm_i_sll(buf, 0, 0, 0)
 #define uasm_i_ssnop(buf) uasm_i_sll(buf, 0, 0, 1)
-#define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3)
-
-static inline void uasm_i_dsrl_safe(u32 **p, unsigned int a1,
-                                   unsigned int a2, unsigned int a3)
-{
-       if (a3 < 32)
-               uasm_i_dsrl(p, a1, a2, a3);
-       else
-               uasm_i_dsrl32(p, a1, a2, a3 - 32);
-}
 
 static inline void uasm_i_drotr_safe(u32 **p, unsigned int a1,
                                     unsigned int a2, unsigned int a3)
@@ -215,6 +208,15 @@ static inline void uasm_i_dsll_safe(u32 **p, unsigned int a1,
                uasm_i_dsll32(p, a1, a2, a3 - 32);
 }
 
+static inline void uasm_i_dsrl_safe(u32 **p, unsigned int a1,
+                                   unsigned int a2, unsigned int a3)
+{
+       if (a3 < 32)
+               uasm_i_dsrl(p, a1, a2, a3);
+       else
+               uasm_i_dsrl32(p, a1, a2, a3 - 32);
+}
+
 /* Handle relocations. */
 struct uasm_reloc {
        u32 *addr;
@@ -234,16 +236,16 @@ void uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab,
 int uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr);
 
 /* Convenience functions for labeled branches. */
-void uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
 void uasm_il_b(u32 **p, struct uasm_reloc **r, int lid);
+void uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg,
+                  unsigned int bit, int lid);
+void uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg,
+                  unsigned int bit, int lid);
 void uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
 void uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
 void uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1,
                 unsigned int reg2, int lid);
 void uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
-void uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
-void uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
-void uasm_il_bbit0(u32 **p, struct uasm_reloc **r, unsigned int reg,
-                  unsigned int bit, int lid);
-void uasm_il_bbit1(u32 **p, struct uasm_reloc **r, unsigned int reg,
-                  unsigned int bit, int lid);
index d8dad5340ea30d22eac825883012a14341fbf157..bebbde01be92870cf06ff40ee373b1e6dab71ccb 100644 (file)
 #ifndef __ASSEMBLY__
 
 #define __ARCH_OMIT_COMPAT_SYS_GETDENTS64
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
index 9a91fe9de69675ff1d74140bc658257637356090..9a3d9de4d04ef219faee3f832027c1416e92e61c 100644 (file)
@@ -140,6 +140,7 @@ static void qi_lb60_nand_ident(struct platform_device *pdev,
 static struct jz_nand_platform_data qi_lb60_nand_pdata = {
        .ident_callback = qi_lb60_nand_ident,
        .busy_gpio = 94,
+       .banks = { 1 },
 };
 
 /* Keyboard*/
index 10929e2bc6d82a77714243175073f8ef31a60fcf..e342ed4cbd4378c84749ae7e77406a131cec7c1c 100644 (file)
@@ -157,11 +157,29 @@ static struct resource jz4740_nand_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               .name   = "bank",
+               .name   = "bank1",
                .start  = 0x18000000,
                .end    = 0x180C0000 - 1,
                .flags = IORESOURCE_MEM,
        },
+       {
+               .name   = "bank2",
+               .start  = 0x14000000,
+               .end    = 0x140C0000 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name   = "bank3",
+               .start  = 0x0C000000,
+               .end    = 0x0C0C0000 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name   = "bank4",
+               .start  = 0x08000000,
+               .end    = 0x080C0000 - 1,
+               .flags = IORESOURCE_MEM,
+       },
 };
 
 struct platform_device jz4740_nand_device = {
index 5f1fb95c0d0daf980bc20194be8bb4c6f35f002d..6c0da5afcf17ef1fdcd97d70f83dff183fcd57f3 100644 (file)
@@ -21,6 +21,9 @@
 #include <asm/mach-jz4740/base.h>
 #include <asm/mach-jz4740/timer.h>
 
+#include "reset.h"
+#include "clock.h"
+
 static void jz4740_halt(void)
 {
        while (1) {
@@ -53,21 +56,57 @@ static void jz4740_restart(char *command)
        jz4740_halt();
 }
 
-#define JZ_REG_RTC_CTRL                0x00
-#define JZ_REG_RTC_HIBERNATE   0x20
+#define JZ_REG_RTC_CTRL                        0x00
+#define JZ_REG_RTC_HIBERNATE           0x20
+#define JZ_REG_RTC_WAKEUP_FILTER       0x24
+#define JZ_REG_RTC_RESET_COUNTER       0x28
 
-#define JZ_RTC_CTRL_WRDY       BIT(7)
+#define JZ_RTC_CTRL_WRDY               BIT(7)
+#define JZ_RTC_WAKEUP_FILTER_MASK      0x0000FFE0
+#define JZ_RTC_RESET_COUNTER_MASK      0x00000FE0
 
-static void jz4740_power_off(void)
+static inline void jz4740_rtc_wait_ready(void __iomem *rtc_base)
 {
-       void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x24);
        uint32_t ctrl;
 
        do {
                ctrl = readl(rtc_base + JZ_REG_RTC_CTRL);
        } while (!(ctrl & JZ_RTC_CTRL_WRDY));
+}
 
+static void jz4740_power_off(void)
+{
+       void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x38);
+       unsigned long wakeup_filter_ticks;
+       unsigned long reset_counter_ticks;
+
+       /*
+        * Set minimum wakeup pin assertion time: 100 ms.
+        * Range is 0 to 2 sec if RTC is clocked at 32 kHz.
+        */
+       wakeup_filter_ticks = (100 * jz4740_clock_bdata.rtc_rate) / 1000;
+       if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK)
+               wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK;
+       else
+               wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK;
+       jz4740_rtc_wait_ready(rtc_base);
+       writel(wakeup_filter_ticks, rtc_base + JZ_REG_RTC_WAKEUP_FILTER);
+
+       /*
+        * Set reset pin low-level assertion time after wakeup: 60 ms.
+        * Range is 0 to 125 ms if RTC is clocked at 32 kHz.
+        */
+       reset_counter_ticks = (60 * jz4740_clock_bdata.rtc_rate) / 1000;
+       if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK)
+               reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK;
+       else
+               reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK;
+       jz4740_rtc_wait_ready(rtc_base);
+       writel(reset_counter_ticks, rtc_base + JZ_REG_RTC_RESET_COUNTER);
+
+       jz4740_rtc_wait_ready(rtc_base);
        writel(1, rtc_base + JZ_REG_RTC_HIBERNATE);
+
        jz4740_halt();
 }
 
index f4630e1082ab676a96e052e504995e86716be012..1b51046191e85a77dfb56aa284b96e66b035b083 100644 (file)
@@ -190,6 +190,7 @@ void __init check_wait(void)
        case CPU_CAVIUM_OCTEON_PLUS:
        case CPU_CAVIUM_OCTEON2:
        case CPU_JZRISC:
+       case CPU_LOONGSON1:
        case CPU_XLR:
        case CPU_XLP:
                cpu_wait = r4k_wait;
@@ -330,6 +331,154 @@ static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
 #endif
 }
 
+static char unknown_isa[] __cpuinitdata = KERN_ERR \
+       "Unsupported ISA type, c0.config0: %d.";
+
+static inline unsigned int decode_config0(struct cpuinfo_mips *c)
+{
+       unsigned int config0;
+       int isa;
+
+       config0 = read_c0_config();
+
+       if (((config0 & MIPS_CONF_MT) >> 7) == 1)
+               c->options |= MIPS_CPU_TLB;
+       isa = (config0 & MIPS_CONF_AT) >> 13;
+       switch (isa) {
+       case 0:
+               switch ((config0 & MIPS_CONF_AR) >> 10) {
+               case 0:
+                       c->isa_level = MIPS_CPU_ISA_M32R1;
+                       break;
+               case 1:
+                       c->isa_level = MIPS_CPU_ISA_M32R2;
+                       break;
+               default:
+                       goto unknown;
+               }
+               break;
+       case 2:
+               switch ((config0 & MIPS_CONF_AR) >> 10) {
+               case 0:
+                       c->isa_level = MIPS_CPU_ISA_M64R1;
+                       break;
+               case 1:
+                       c->isa_level = MIPS_CPU_ISA_M64R2;
+                       break;
+               default:
+                       goto unknown;
+               }
+               break;
+       default:
+               goto unknown;
+       }
+
+       return config0 & MIPS_CONF_M;
+
+unknown:
+       panic(unknown_isa, config0);
+}
+
+static inline unsigned int decode_config1(struct cpuinfo_mips *c)
+{
+       unsigned int config1;
+
+       config1 = read_c0_config1();
+
+       if (config1 & MIPS_CONF1_MD)
+               c->ases |= MIPS_ASE_MDMX;
+       if (config1 & MIPS_CONF1_WR)
+               c->options |= MIPS_CPU_WATCH;
+       if (config1 & MIPS_CONF1_CA)
+               c->ases |= MIPS_ASE_MIPS16;
+       if (config1 & MIPS_CONF1_EP)
+               c->options |= MIPS_CPU_EJTAG;
+       if (config1 & MIPS_CONF1_FP) {
+               c->options |= MIPS_CPU_FPU;
+               c->options |= MIPS_CPU_32FPR;
+       }
+       if (cpu_has_tlb)
+               c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1;
+
+       return config1 & MIPS_CONF_M;
+}
+
+static inline unsigned int decode_config2(struct cpuinfo_mips *c)
+{
+       unsigned int config2;
+
+       config2 = read_c0_config2();
+
+       if (config2 & MIPS_CONF2_SL)
+               c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
+
+       return config2 & MIPS_CONF_M;
+}
+
+static inline unsigned int decode_config3(struct cpuinfo_mips *c)
+{
+       unsigned int config3;
+
+       config3 = read_c0_config3();
+
+       if (config3 & MIPS_CONF3_SM)
+               c->ases |= MIPS_ASE_SMARTMIPS;
+       if (config3 & MIPS_CONF3_DSP)
+               c->ases |= MIPS_ASE_DSP;
+       if (config3 & MIPS_CONF3_VINT)
+               c->options |= MIPS_CPU_VINT;
+       if (config3 & MIPS_CONF3_VEIC)
+               c->options |= MIPS_CPU_VEIC;
+       if (config3 & MIPS_CONF3_MT)
+               c->ases |= MIPS_ASE_MIPSMT;
+       if (config3 & MIPS_CONF3_ULRI)
+               c->options |= MIPS_CPU_ULRI;
+
+       return config3 & MIPS_CONF_M;
+}
+
+static inline unsigned int decode_config4(struct cpuinfo_mips *c)
+{
+       unsigned int config4;
+
+       config4 = read_c0_config4();
+
+       if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT
+           && cpu_has_tlb)
+               c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
+
+       c->kscratch_mask = (config4 >> 16) & 0xff;
+
+       return config4 & MIPS_CONF_M;
+}
+
+static void __cpuinit decode_configs(struct cpuinfo_mips *c)
+{
+       int ok;
+
+       /* MIPS32 or MIPS64 compliant CPU.  */
+       c->options = MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER |
+                    MIPS_CPU_DIVEC | MIPS_CPU_LLSC | MIPS_CPU_MCHECK;
+
+       c->scache.flags = MIPS_CACHE_NOT_PRESENT;
+
+       ok = decode_config0(c);                 /* Read Config registers.  */
+       BUG_ON(!ok);                            /* Arch spec violation!  */
+       if (ok)
+               ok = decode_config1(c);
+       if (ok)
+               ok = decode_config2(c);
+       if (ok)
+               ok = decode_config3(c);
+       if (ok)
+               ok = decode_config4(c);
+
+       mips_probe_watch_registers(c);
+
+       if (cpu_has_mips_r2)
+               c->core = read_c0_ebase() & 0x3ff;
+}
+
 #define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \
                | MIPS_CPU_COUNTER)
 
@@ -638,155 +787,19 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                             MIPS_CPU_32FPR;
                c->tlbsize = 64;
                break;
-       }
-}
-
-static char unknown_isa[] __cpuinitdata = KERN_ERR \
-       "Unsupported ISA type, c0.config0: %d.";
+       case PRID_IMP_LOONGSON1:
+               decode_configs(c);
 
-static inline unsigned int decode_config0(struct cpuinfo_mips *c)
-{
-       unsigned int config0;
-       int isa;
+               c->cputype = CPU_LOONGSON1;
 
-       config0 = read_c0_config();
-
-       if (((config0 & MIPS_CONF_MT) >> 7) == 1)
-               c->options |= MIPS_CPU_TLB;
-       isa = (config0 & MIPS_CONF_AT) >> 13;
-       switch (isa) {
-       case 0:
-               switch ((config0 & MIPS_CONF_AR) >> 10) {
-               case 0:
-                       c->isa_level = MIPS_CPU_ISA_M32R1;
-                       break;
-               case 1:
-                       c->isa_level = MIPS_CPU_ISA_M32R2;
+               switch (c->processor_id & PRID_REV_MASK) {
+               case PRID_REV_LOONGSON1B:
+                       __cpu_name[cpu] = "Loongson 1B";
                        break;
-               default:
-                       goto unknown;
                }
-               break;
-       case 2:
-               switch ((config0 & MIPS_CONF_AR) >> 10) {
-               case 0:
-                       c->isa_level = MIPS_CPU_ISA_M64R1;
-                       break;
-               case 1:
-                       c->isa_level = MIPS_CPU_ISA_M64R2;
-                       break;
-               default:
-                       goto unknown;
-               }
-               break;
-       default:
-               goto unknown;
-       }
-
-       return config0 & MIPS_CONF_M;
-
-unknown:
-       panic(unknown_isa, config0);
-}
 
-static inline unsigned int decode_config1(struct cpuinfo_mips *c)
-{
-       unsigned int config1;
-
-       config1 = read_c0_config1();
-
-       if (config1 & MIPS_CONF1_MD)
-               c->ases |= MIPS_ASE_MDMX;
-       if (config1 & MIPS_CONF1_WR)
-               c->options |= MIPS_CPU_WATCH;
-       if (config1 & MIPS_CONF1_CA)
-               c->ases |= MIPS_ASE_MIPS16;
-       if (config1 & MIPS_CONF1_EP)
-               c->options |= MIPS_CPU_EJTAG;
-       if (config1 & MIPS_CONF1_FP) {
-               c->options |= MIPS_CPU_FPU;
-               c->options |= MIPS_CPU_32FPR;
+               break;
        }
-       if (cpu_has_tlb)
-               c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1;
-
-       return config1 & MIPS_CONF_M;
-}
-
-static inline unsigned int decode_config2(struct cpuinfo_mips *c)
-{
-       unsigned int config2;
-
-       config2 = read_c0_config2();
-
-       if (config2 & MIPS_CONF2_SL)
-               c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
-
-       return config2 & MIPS_CONF_M;
-}
-
-static inline unsigned int decode_config3(struct cpuinfo_mips *c)
-{
-       unsigned int config3;
-
-       config3 = read_c0_config3();
-
-       if (config3 & MIPS_CONF3_SM)
-               c->ases |= MIPS_ASE_SMARTMIPS;
-       if (config3 & MIPS_CONF3_DSP)
-               c->ases |= MIPS_ASE_DSP;
-       if (config3 & MIPS_CONF3_VINT)
-               c->options |= MIPS_CPU_VINT;
-       if (config3 & MIPS_CONF3_VEIC)
-               c->options |= MIPS_CPU_VEIC;
-       if (config3 & MIPS_CONF3_MT)
-               c->ases |= MIPS_ASE_MIPSMT;
-       if (config3 & MIPS_CONF3_ULRI)
-               c->options |= MIPS_CPU_ULRI;
-
-       return config3 & MIPS_CONF_M;
-}
-
-static inline unsigned int decode_config4(struct cpuinfo_mips *c)
-{
-       unsigned int config4;
-
-       config4 = read_c0_config4();
-
-       if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT
-           && cpu_has_tlb)
-               c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
-
-       c->kscratch_mask = (config4 >> 16) & 0xff;
-
-       return config4 & MIPS_CONF_M;
-}
-
-static void __cpuinit decode_configs(struct cpuinfo_mips *c)
-{
-       int ok;
-
-       /* MIPS32 or MIPS64 compliant CPU.  */
-       c->options = MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER |
-                    MIPS_CPU_DIVEC | MIPS_CPU_LLSC | MIPS_CPU_MCHECK;
-
-       c->scache.flags = MIPS_CACHE_NOT_PRESENT;
-
-       ok = decode_config0(c);                 /* Read Config registers.  */
-       BUG_ON(!ok);                            /* Arch spec violation!  */
-       if (ok)
-               ok = decode_config1(c);
-       if (ok)
-               ok = decode_config2(c);
-       if (ok)
-               ok = decode_config3(c);
-       if (ok)
-               ok = decode_config4(c);
-
-       mips_probe_watch_registers(c);
-
-       if (cpu_has_mips_r2)
-               c->core = read_c0_ebase() & 0x3ff;
 }
 
 static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
index eb5e394a4650bbe9f0814e51bc00e1b8523c57f1..2f28d3b55687eac42469051c34cb9a6749b21473 100644 (file)
@@ -1559,6 +1559,11 @@ init_hw_perf_events(void)
                mipspmu.general_event_map = &mipsxxcore_event_map;
                mipspmu.cache_event_map = &mipsxxcore_cache_map;
                break;
+       case CPU_LOONGSON1:
+               mipspmu.name = "mips/loongson1";
+               mipspmu.general_event_map = &mipsxxcore_event_map;
+               mipspmu.cache_event_map = &mipsxxcore_cache_map;
+               break;
        case CPU_CAVIUM_OCTEON:
        case CPU_CAVIUM_OCTEON_PLUS:
        case CPU_CAVIUM_OCTEON2:
index f11b2bbb826d223d10eefffb810c9bcdb67eb017..028f6f837ef9c975697cd763fa685126a5be6b48 100644 (file)
@@ -35,16 +35,6 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
        return add_memory_region(base, size, BOOT_MEM_RAM);
 }
 
-int __init reserve_mem_mach(unsigned long addr, unsigned long size)
-{
-       return reserve_bootmem(addr, size, BOOTMEM_DEFAULT);
-}
-
-void __init free_mem_mach(unsigned long addr, unsigned long size)
-{
-       return free_bootmem(addr, size);
-}
-
 void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
 {
        return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS));
@@ -77,25 +67,6 @@ void __init early_init_devtree(void *params)
        of_scan_flat_dt(early_init_dt_scan_memory_arch, NULL);
 }
 
-void __init device_tree_init(void)
-{
-       unsigned long base, size;
-
-       if (!initial_boot_params)
-               return;
-
-       base = virt_to_phys((void *)initial_boot_params);
-       size = be32_to_cpu(initial_boot_params->totalsize);
-
-       /* Before we do anything, lets reserve the dt blob */
-       reserve_mem_mach(base, size);
-
-       unflatten_device_tree();
-
-       /* free the space reserved for the dt blob */
-       free_mem_mach(base, size);
-}
-
 void __init __dt_setup_arch(struct boot_param_header *bph)
 {
        if (be32_to_cpu(bph->magic) != OF_DT_HEADER) {
index 1268392f1d2786bc3abb91fdb9a88ad84fa85ec9..31637d8c87381f04b02bcae714e8b2165952fc9c 100644 (file)
@@ -102,7 +102,9 @@ asmlinkage __cpuinit void start_secondary(void)
 
 #ifdef CONFIG_MIPS_MT_SMTC
        /* Only do cpu_probe for first TC of CPU */
-       if ((read_c0_tcbind() & TCBIND_CURTC) == 0)
+       if ((read_c0_tcbind() & TCBIND_CURTC) != 0)
+               __cpu_name[smp_processor_id()] = __cpu_name[0];
+       else
 #endif /* CONFIG_MIPS_MT_SMTC */
        cpu_probe();
        cpu_report();
index 15b5f3cfd20c48b9424dd5364d29cf1aeff77d4a..1d47843d3cc0211d3259930ef48596316afc2cfc 100644 (file)
@@ -86,6 +86,13 @@ struct smtc_ipi_q IPIQ[NR_CPUS];
 static struct smtc_ipi_q freeIPIq;
 
 
+/*
+ * Number of FPU contexts for each VPE
+ */
+
+static int smtc_nconf1[MAX_SMTC_VPES];
+
+
 /* Forward declarations */
 
 void ipi_decode(struct smtc_ipi *);
@@ -174,9 +181,9 @@ static int __init tintq(char *str)
 
 __setup("tintq=", tintq);
 
-static int imstuckcount[2][8];
+static int imstuckcount[MAX_SMTC_VPES][8];
 /* vpemask represents IM/IE bits of per-VPE Status registers, low-to-high */
-static int vpemask[2][8] = {
+static int vpemask[MAX_SMTC_VPES][8] = {
        {0, 0, 1, 0, 0, 0, 0, 1},
        {0, 0, 0, 0, 0, 0, 0, 1}
 };
@@ -331,6 +338,22 @@ int __init smtc_build_cpu_map(int start_cpu_slot)
 
 static void smtc_tc_setup(int vpe, int tc, int cpu)
 {
+       static int cp1contexts[MAX_SMTC_VPES];
+
+       /*
+        * Make a local copy of the available FPU contexts in order
+        * to keep track of TCs that can have one.
+        */
+       if (tc == 1)
+       {
+               /*
+                * FIXME: Multi-core SMTC hasn't been tested and the
+                *        maximum number of VPEs may change.
+                */
+               cp1contexts[0] = smtc_nconf1[0] - 1;
+               cp1contexts[1] = smtc_nconf1[1];
+       }
+
        settc(tc);
        write_tc_c0_tchalt(TCHALT_H);
        mips_ihb();
@@ -343,22 +366,29 @@ static void smtc_tc_setup(int vpe, int tc, int cpu)
         * an active IPI queue.
         */
        write_tc_c0_tccontext((sizeof(struct smtc_ipi_q) * cpu) << 16);
-       /* Bind tc to vpe */
+
+       /* Bind TC to VPE. */
        write_tc_c0_tcbind(vpe);
+
        /* In general, all TCs should have the same cpu_data indications. */
        memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips));
-       /* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */
-       if (cpu_data[0].cputype == CPU_34K ||
-           cpu_data[0].cputype == CPU_1004K)
+
+       /* Check to see if there is a FPU context available for this TC. */
+       if (!cp1contexts[vpe])
                cpu_data[cpu].options &= ~MIPS_CPU_FPU;
+       else
+               cp1contexts[vpe]--;
+
+       /* Store the TC and VPE into the cpu_data structure. */
        cpu_data[cpu].vpe_id = vpe;
        cpu_data[cpu].tc_id = tc;
-       /* Multi-core SMTC hasn't been tested, but be prepared */
+
+       /* FIXME: Multi-core SMTC hasn't been tested, but be prepared. */
        cpu_data[cpu].core = (read_vpe_c0_ebase() >> 1) & 0xff;
 }
 
 /*
- * Tweak to get Count registes in as close a sync as possible.  The
+ * Tweak to get Count registers synced as closely as possible. The
  * value seems good for 34K-class cores.
  */
 
@@ -466,6 +496,24 @@ void smtc_prepare_cpus(int cpus)
        smtc_configure_tlb();
 
        for (tc = 0, vpe = 0 ; (vpe < nvpe) && (tc < ntc) ; vpe++) {
+               /* Get number of CP1 contexts for each VPE. */
+               if (tc == 0)
+               {
+                       /*
+                        * Do not call settc() for TC0 or the FPU context
+                        * value will be incorrect. Besides, we know that
+                        * we are TC0 anyway.
+                        */
+                       smtc_nconf1[0] = ((read_vpe_c0_vpeconf1() &
+                               VPECONF1_NCP1) >> VPECONF1_NCP1_SHIFT);
+                       if (nvpe == 2)
+                       {
+                               settc(1);
+                               smtc_nconf1[1] = ((read_vpe_c0_vpeconf1() &
+                                       VPECONF1_NCP1) >> VPECONF1_NCP1_SHIFT);
+                               settc(0);
+                       }
+               }
                if (tcpervpe[vpe] == 0)
                        continue;
                if (vpe != 0)
@@ -479,6 +527,18 @@ void smtc_prepare_cpus(int cpus)
                         */
                        if (tc != 0) {
                                smtc_tc_setup(vpe, tc, cpu);
+                               if (vpe != 0) {
+                                       /*
+                                        * Set MVP bit (possibly again).  Do it
+                                        * here to catch CPUs that have no TCs
+                                        * bound to the VPE at reset.  In that
+                                        * case, a TC must be bound to the VPE
+                                        * before we can set VPEControl[MVP]
+                                        */
+                                       write_vpe_c0_vpeconf0(
+                                               read_vpe_c0_vpeconf0() |
+                                               VPECONF0_MVP);
+                               }
                                cpu++;
                        }
                        printk(" %d", tc);
index c3c29354370345ae74c25dce1e4e7e7da9263316..9be3df1fa8a461dc4e1e5563582f483e4ed7c103 100644 (file)
@@ -1253,6 +1253,7 @@ static inline void parity_protection_init(void)
 
        case CPU_5KC:
        case CPU_5KE:
+       case CPU_LOONGSON1:
                write_c0_ecc(0x80000000);
                back_to_back_c0_hazard();
                /* Set the PE bit (bit 31) in the c0_errctl register. */
index 2a7c74fc15fcef917d183201d9f6eac9046fcbf7..399a50a541d4471a9e68bd4b0f18b00d512d5e67 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for MIPS-specific library files..
 #
 
-lib-y  += csum_partial.o delay.o memcpy.o memcpy-inatomic.o memset.o \
+lib-y  += csum_partial.o delay.o memcpy.o memset.o \
           strlen_user.o strncpy_user.o strnlen_user.o uncached.o
 
 obj-y                  += iomap.o
diff --git a/arch/mips/lib/memcpy-inatomic.S b/arch/mips/lib/memcpy-inatomic.S
deleted file mode 100644 (file)
index 68853a0..0000000
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Unified implementation of memcpy, memmove and the __copy_user backend.
- *
- * Copyright (C) 1998, 99, 2000, 01, 2002 Ralf Baechle (ralf@gnu.org)
- * Copyright (C) 1999, 2000, 01, 2002 Silicon Graphics, Inc.
- * Copyright (C) 2002 Broadcom, Inc.
- *   memcpy/copy_user author: Mark Vandevoorde
- * Copyright (C) 2007  Maciej W. Rozycki
- *
- * Mnemonic names for arguments to memcpy/__copy_user
- */
-
-/*
- * Hack to resolve longstanding prefetch issue
- *
- * Prefetching may be fatal on some systems if we're prefetching beyond the
- * end of memory on some systems.  It's also a seriously bad idea on non
- * dma-coherent systems.
- */
-#ifdef CONFIG_DMA_NONCOHERENT
-#undef CONFIG_CPU_HAS_PREFETCH
-#endif
-#ifdef CONFIG_MIPS_MALTA
-#undef CONFIG_CPU_HAS_PREFETCH
-#endif
-
-#include <asm/asm.h>
-#include <asm/asm-offsets.h>
-#include <asm/regdef.h>
-
-#define dst a0
-#define src a1
-#define len a2
-
-/*
- * Spec
- *
- * memcpy copies len bytes from src to dst and sets v0 to dst.
- * It assumes that
- *   - src and dst don't overlap
- *   - src is readable
- *   - dst is writable
- * memcpy uses the standard calling convention
- *
- * __copy_user copies up to len bytes from src to dst and sets a2 (len) to
- * the number of uncopied bytes due to an exception caused by a read or write.
- * __copy_user assumes that src and dst don't overlap, and that the call is
- * implementing one of the following:
- *   copy_to_user
- *     - src is readable  (no exceptions when reading src)
- *   copy_from_user
- *     - dst is writable  (no exceptions when writing dst)
- * __copy_user uses a non-standard calling convention; see
- * include/asm-mips/uaccess.h
- *
- * When an exception happens on a load, the handler must
- # ensure that all of the destination buffer is overwritten to prevent
- * leaking information to user mode programs.
- */
-
-/*
- * Implementation
- */
-
-/*
- * The exception handler for loads requires that:
- *  1- AT contain the address of the byte just past the end of the source
- *     of the copy,
- *  2- src_entry <= src < AT, and
- *  3- (dst - src) == (dst_entry - src_entry),
- * The _entry suffix denotes values when __copy_user was called.
- *
- * (1) is set up up by uaccess.h and maintained by not writing AT in copy_user
- * (2) is met by incrementing src by the number of bytes copied
- * (3) is met by not doing loads between a pair of increments of dst and src
- *
- * The exception handlers for stores adjust len (if necessary) and return.
- * These handlers do not need to overwrite any data.
- *
- * For __rmemcpy and memmove an exception is always a kernel bug, therefore
- * they're not protected.
- */
-
-#define EXC(inst_reg,addr,handler)             \
-9:     inst_reg, addr;                         \
-       .section __ex_table,"a";                \
-       PTR     9b, handler;                    \
-       .previous
-
-/*
- * Only on the 64-bit kernel we can made use of 64-bit registers.
- */
-#ifdef CONFIG_64BIT
-#define USE_DOUBLE
-#endif
-
-#ifdef USE_DOUBLE
-
-#define LOAD   ld
-#define LOADL  ldl
-#define LOADR  ldr
-#define STOREL sdl
-#define STORER sdr
-#define STORE  sd
-#define ADD    daddu
-#define SUB    dsubu
-#define SRL    dsrl
-#define SRA    dsra
-#define SLL    dsll
-#define SLLV   dsllv
-#define SRLV   dsrlv
-#define NBYTES 8
-#define LOG_NBYTES 3
-
-/*
- * As we are sharing code base with the mips32 tree (which use the o32 ABI
- * register definitions). We need to redefine the register definitions from
- * the n64 ABI register naming to the o32 ABI register naming.
- */
-#undef t0
-#undef t1
-#undef t2
-#undef t3
-#define t0     $8
-#define t1     $9
-#define t2     $10
-#define t3     $11
-#define t4     $12
-#define t5     $13
-#define t6     $14
-#define t7     $15
-
-#else
-
-#define LOAD   lw
-#define LOADL  lwl
-#define LOADR  lwr
-#define STOREL swl
-#define STORER swr
-#define STORE  sw
-#define ADD    addu
-#define SUB    subu
-#define SRL    srl
-#define SLL    sll
-#define SRA    sra
-#define SLLV   sllv
-#define SRLV   srlv
-#define NBYTES 4
-#define LOG_NBYTES 2
-
-#endif /* USE_DOUBLE */
-
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
-#define LDFIRST LOADR
-#define LDREST  LOADL
-#define STFIRST STORER
-#define STREST  STOREL
-#define SHIFT_DISCARD SLLV
-#else
-#define LDFIRST LOADL
-#define LDREST  LOADR
-#define STFIRST STOREL
-#define STREST  STORER
-#define SHIFT_DISCARD SRLV
-#endif
-
-#define FIRST(unit) ((unit)*NBYTES)
-#define REST(unit)  (FIRST(unit)+NBYTES-1)
-#define UNIT(unit)  FIRST(unit)
-
-#define ADDRMASK (NBYTES-1)
-
-       .text
-       .set    noreorder
-#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
-       .set    noat
-#else
-       .set    at=v1
-#endif
-
-/*
- * A combined memcpy/__copy_user
- * __copy_user sets len to 0 for success; else to an upper bound of
- * the number of uncopied bytes.
- * memcpy sets v0 to dst.
- */
-       .align  5
-LEAF(__copy_user_inatomic)
-       /*
-        * Note: dst & src may be unaligned, len may be 0
-        * Temps
-        */
-#define rem t8
-
-       /*
-        * The "issue break"s below are very approximate.
-        * Issue delays for dcache fills will perturb the schedule, as will
-        * load queue full replay traps, etc.
-        *
-        * If len < NBYTES use byte operations.
-        */
-       PREF(   0, 0(src) )
-       PREF(   1, 0(dst) )
-       sltu    t2, len, NBYTES
-       and     t1, dst, ADDRMASK
-       PREF(   0, 1*32(src) )
-       PREF(   1, 1*32(dst) )
-       bnez    t2, .Lcopy_bytes_checklen
-        and    t0, src, ADDRMASK
-       PREF(   0, 2*32(src) )
-       PREF(   1, 2*32(dst) )
-       bnez    t1, .Ldst_unaligned
-        nop
-       bnez    t0, .Lsrc_unaligned_dst_aligned
-       /*
-        * use delay slot for fall-through
-        * src and dst are aligned; need to compute rem
-        */
-.Lboth_aligned:
-        SRL    t0, len, LOG_NBYTES+3           # +3 for 8 units/iter
-       beqz    t0, .Lcleanup_both_aligned      # len < 8*NBYTES
-        and    rem, len, (8*NBYTES-1)          # rem = len % (8*NBYTES)
-       PREF(   0, 3*32(src) )
-       PREF(   1, 3*32(dst) )
-       .align  4
-1:
-EXC(   LOAD    t0, UNIT(0)(src),       .Ll_exc)
-EXC(   LOAD    t1, UNIT(1)(src),       .Ll_exc_copy)
-EXC(   LOAD    t2, UNIT(2)(src),       .Ll_exc_copy)
-EXC(   LOAD    t3, UNIT(3)(src),       .Ll_exc_copy)
-       SUB     len, len, 8*NBYTES
-EXC(   LOAD    t4, UNIT(4)(src),       .Ll_exc_copy)
-EXC(   LOAD    t7, UNIT(5)(src),       .Ll_exc_copy)
-       STORE   t0, UNIT(0)(dst)
-       STORE   t1, UNIT(1)(dst)
-EXC(   LOAD    t0, UNIT(6)(src),       .Ll_exc_copy)
-EXC(   LOAD    t1, UNIT(7)(src),       .Ll_exc_copy)
-       ADD     src, src, 8*NBYTES
-       ADD     dst, dst, 8*NBYTES
-       STORE   t2, UNIT(-6)(dst)
-       STORE   t3, UNIT(-5)(dst)
-       STORE   t4, UNIT(-4)(dst)
-       STORE   t7, UNIT(-3)(dst)
-       STORE   t0, UNIT(-2)(dst)
-       STORE   t1, UNIT(-1)(dst)
-       PREF(   0, 8*32(src) )
-       PREF(   1, 8*32(dst) )
-       bne     len, rem, 1b
-        nop
-
-       /*
-        * len == rem == the number of bytes left to copy < 8*NBYTES
-        */
-.Lcleanup_both_aligned:
-       beqz    len, .Ldone
-        sltu   t0, len, 4*NBYTES
-       bnez    t0, .Lless_than_4units
-        and    rem, len, (NBYTES-1)    # rem = len % NBYTES
-       /*
-        * len >= 4*NBYTES
-        */
-EXC(   LOAD    t0, UNIT(0)(src),       .Ll_exc)
-EXC(   LOAD    t1, UNIT(1)(src),       .Ll_exc_copy)
-EXC(   LOAD    t2, UNIT(2)(src),       .Ll_exc_copy)
-EXC(   LOAD    t3, UNIT(3)(src),       .Ll_exc_copy)
-       SUB     len, len, 4*NBYTES
-       ADD     src, src, 4*NBYTES
-       STORE   t0, UNIT(0)(dst)
-       STORE   t1, UNIT(1)(dst)
-       STORE   t2, UNIT(2)(dst)
-       STORE   t3, UNIT(3)(dst)
-       .set    reorder                         /* DADDI_WAR */
-       ADD     dst, dst, 4*NBYTES
-       beqz    len, .Ldone
-       .set    noreorder
-.Lless_than_4units:
-       /*
-        * rem = len % NBYTES
-        */
-       beq     rem, len, .Lcopy_bytes
-        nop
-1:
-EXC(   LOAD    t0, 0(src),             .Ll_exc)
-       ADD     src, src, NBYTES
-       SUB     len, len, NBYTES
-       STORE   t0, 0(dst)
-       .set    reorder                         /* DADDI_WAR */
-       ADD     dst, dst, NBYTES
-       bne     rem, len, 1b
-       .set    noreorder
-
-       /*
-        * src and dst are aligned, need to copy rem bytes (rem < NBYTES)
-        * A loop would do only a byte at a time with possible branch
-        * mispredicts.  Can't do an explicit LOAD dst,mask,or,STORE
-        * because can't assume read-access to dst.  Instead, use
-        * STREST dst, which doesn't require read access to dst.
-        *
-        * This code should perform better than a simple loop on modern,
-        * wide-issue mips processors because the code has fewer branches and
-        * more instruction-level parallelism.
-        */
-#define bits t2
-       beqz    len, .Ldone
-        ADD    t1, dst, len    # t1 is just past last byte of dst
-       li      bits, 8*NBYTES
-       SLL     rem, len, 3     # rem = number of bits to keep
-EXC(   LOAD    t0, 0(src),             .Ll_exc)
-       SUB     bits, bits, rem # bits = number of bits to discard
-       SHIFT_DISCARD t0, t0, bits
-       STREST  t0, -1(t1)
-       jr      ra
-        move   len, zero
-.Ldst_unaligned:
-       /*
-        * dst is unaligned
-        * t0 = src & ADDRMASK
-        * t1 = dst & ADDRMASK; T1 > 0
-        * len >= NBYTES
-        *
-        * Copy enough bytes to align dst
-        * Set match = (src and dst have same alignment)
-        */
-#define match rem
-EXC(   LDFIRST t3, FIRST(0)(src),      .Ll_exc)
-       ADD     t2, zero, NBYTES
-EXC(   LDREST  t3, REST(0)(src),       .Ll_exc_copy)
-       SUB     t2, t2, t1      # t2 = number of bytes copied
-       xor     match, t0, t1
-       STFIRST t3, FIRST(0)(dst)
-       beq     len, t2, .Ldone
-        SUB    len, len, t2
-       ADD     dst, dst, t2
-       beqz    match, .Lboth_aligned
-        ADD    src, src, t2
-
-.Lsrc_unaligned_dst_aligned:
-       SRL     t0, len, LOG_NBYTES+2    # +2 for 4 units/iter
-       PREF(   0, 3*32(src) )
-       beqz    t0, .Lcleanup_src_unaligned
-        and    rem, len, (4*NBYTES-1)   # rem = len % 4*NBYTES
-       PREF(   1, 3*32(dst) )
-1:
-/*
- * Avoid consecutive LD*'s to the same register since some mips
- * implementations can't issue them in the same cycle.
- * It's OK to load FIRST(N+1) before REST(N) because the two addresses
- * are to the same unit (unless src is aligned, but it's not).
- */
-EXC(   LDFIRST t0, FIRST(0)(src),      .Ll_exc)
-EXC(   LDFIRST t1, FIRST(1)(src),      .Ll_exc_copy)
-       SUB     len, len, 4*NBYTES
-EXC(   LDREST  t0, REST(0)(src),       .Ll_exc_copy)
-EXC(   LDREST  t1, REST(1)(src),       .Ll_exc_copy)
-EXC(   LDFIRST t2, FIRST(2)(src),      .Ll_exc_copy)
-EXC(   LDFIRST t3, FIRST(3)(src),      .Ll_exc_copy)
-EXC(   LDREST  t2, REST(2)(src),       .Ll_exc_copy)
-EXC(   LDREST  t3, REST(3)(src),       .Ll_exc_copy)
-       PREF(   0, 9*32(src) )          # 0 is PREF_LOAD  (not streamed)
-       ADD     src, src, 4*NBYTES
-#ifdef CONFIG_CPU_SB1
-       nop                             # improves slotting
-#endif
-       STORE   t0, UNIT(0)(dst)
-       STORE   t1, UNIT(1)(dst)
-       STORE   t2, UNIT(2)(dst)
-       STORE   t3, UNIT(3)(dst)
-       PREF(   1, 9*32(dst) )          # 1 is PREF_STORE (not streamed)
-       .set    reorder                         /* DADDI_WAR */
-       ADD     dst, dst, 4*NBYTES
-       bne     len, rem, 1b
-       .set    noreorder
-
-.Lcleanup_src_unaligned:
-       beqz    len, .Ldone
-        and    rem, len, NBYTES-1  # rem = len % NBYTES
-       beq     rem, len, .Lcopy_bytes
-        nop
-1:
-EXC(   LDFIRST t0, FIRST(0)(src),      .Ll_exc)
-EXC(   LDREST  t0, REST(0)(src),       .Ll_exc_copy)
-       ADD     src, src, NBYTES
-       SUB     len, len, NBYTES
-       STORE   t0, 0(dst)
-       .set    reorder                         /* DADDI_WAR */
-       ADD     dst, dst, NBYTES
-       bne     len, rem, 1b
-       .set    noreorder
-
-.Lcopy_bytes_checklen:
-       beqz    len, .Ldone
-        nop
-.Lcopy_bytes:
-       /* 0 < len < NBYTES  */
-#define COPY_BYTE(N)                   \
-EXC(   lb      t0, N(src), .Ll_exc);   \
-       SUB     len, len, 1;            \
-       beqz    len, .Ldone;            \
-        sb     t0, N(dst)
-
-       COPY_BYTE(0)
-       COPY_BYTE(1)
-#ifdef USE_DOUBLE
-       COPY_BYTE(2)
-       COPY_BYTE(3)
-       COPY_BYTE(4)
-       COPY_BYTE(5)
-#endif
-EXC(   lb      t0, NBYTES-2(src), .Ll_exc)
-       SUB     len, len, 1
-       jr      ra
-        sb     t0, NBYTES-2(dst)
-.Ldone:
-       jr      ra
-        nop
-       END(__copy_user_inatomic)
-
-.Ll_exc_copy:
-       /*
-        * Copy bytes from src until faulting load address (or until a
-        * lb faults)
-        *
-        * When reached by a faulting LDFIRST/LDREST, THREAD_BUADDR($28)
-        * may be more than a byte beyond the last address.
-        * Hence, the lb below may get an exception.
-        *
-        * Assumes src < THREAD_BUADDR($28)
-        */
-       LOAD    t0, TI_TASK($28)
-        nop
-       LOAD    t0, THREAD_BUADDR(t0)
-1:
-EXC(   lb      t1, 0(src),     .Ll_exc)
-       ADD     src, src, 1
-       sb      t1, 0(dst)      # can't fault -- we're copy_from_user
-       .set    reorder                         /* DADDI_WAR */
-       ADD     dst, dst, 1
-       bne     src, t0, 1b
-       .set    noreorder
-.Ll_exc:
-       LOAD    t0, TI_TASK($28)
-        nop
-       LOAD    t0, THREAD_BUADDR(t0)   # t0 is just past last good address
-        nop
-       SUB     len, AT, t0             # len number of uncopied bytes
-       jr      ra
-        nop
index 56a1f85a1ce807504a95d54d49b3d3cab46b33a6..65192c06781e6d876767e6110e2c104e5b0e7a08 100644 (file)
        .set    at=v1
 #endif
 
+/*
+ * t6 is used as a flag to note inatomic mode.
+ */
+LEAF(__copy_user_inatomic)
+       b       __copy_user_common
+        li     t6, 1
+       END(__copy_user_inatomic)
+
 /*
  * A combined memcpy/__copy_user
  * __copy_user sets len to 0 for success; else to an upper bound of
@@ -193,6 +201,8 @@ LEAF(memcpy)                                        /* a0=dst a1=src a2=len */
        move    v0, dst                         /* return value */
 .L__memcpy:
 FEXPORT(__copy_user)
+       li      t6, 0   /* not inatomic */
+__copy_user_common:
        /*
         * Note: dst & src may be unaligned, len may be 0
         * Temps
@@ -458,6 +468,7 @@ EXC(        lb      t1, 0(src),     .Ll_exc)
        LOAD    t0, THREAD_BUADDR(t0)   # t0 is just past last good address
         nop
        SUB     len, AT, t0             # len number of uncopied bytes
+       bnez    t6, .Ldone      /* Skip the zeroing part if inatomic */
        /*
         * Here's where we rely on src and dst being incremented in tandem,
         *   See (3) above.
diff --git a/arch/mips/loongson1/Kconfig b/arch/mips/loongson1/Kconfig
new file mode 100644 (file)
index 0000000..237fa21
--- /dev/null
@@ -0,0 +1,21 @@
+if MACH_LOONGSON1
+
+choice
+       prompt "Machine Type"
+
+config LOONGSON1_LS1B
+       bool "Loongson LS1B board"
+       select CEVT_R4K
+       select CSRC_R4K
+       select SYS_HAS_CPU_LOONGSON1B
+       select DMA_NONCOHERENT
+       select BOOT_ELF32
+       select IRQ_CPU
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_LITTLE_ENDIAN
+       select SYS_SUPPORTS_HIGHMEM
+       select SYS_HAS_EARLY_PRINTK
+
+endchoice
+
+endif # MACH_LOONGSON1
diff --git a/arch/mips/loongson1/Makefile b/arch/mips/loongson1/Makefile
new file mode 100644 (file)
index 0000000..9719c75
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Common code for all Loongson 1 based systems
+#
+
+obj-$(CONFIG_MACH_LOONGSON1) += common/
+
+#
+# Loongson LS1B board
+#
+
+obj-$(CONFIG_LOONGSON1_LS1B)  += ls1b/
diff --git a/arch/mips/loongson1/Platform b/arch/mips/loongson1/Platform
new file mode 100644 (file)
index 0000000..99bdefe
--- /dev/null
@@ -0,0 +1,7 @@
+cflags-$(CONFIG_CPU_LOONGSON1)  += \
+       $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
+       -Wa,-mips32r2 -Wa,--trap
+
+platform-$(CONFIG_MACH_LOONGSON1)      += loongson1/
+cflags-$(CONFIG_MACH_LOONGSON1)                += -I$(srctree)/arch/mips/include/asm/mach-loongson1
+load-$(CONFIG_LOONGSON1_LS1B)          += 0xffffffff80100000
diff --git a/arch/mips/loongson1/common/Makefile b/arch/mips/loongson1/common/Makefile
new file mode 100644 (file)
index 0000000..b279770
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for common code of loongson1 based machines.
+#
+
+obj-y  += clock.o irq.o platform.o prom.o reset.o setup.o
diff --git a/arch/mips/loongson1/common/clock.c b/arch/mips/loongson1/common/clock.c
new file mode 100644 (file)
index 0000000..2d98fb0
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/clock.h>
+#include <asm/time.h>
+
+#include <loongson1.h>
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+
+struct clk *clk_get(struct device *dev, const char *name)
+{
+       struct clk *c;
+       struct clk *ret = NULL;
+
+       mutex_lock(&clocks_mutex);
+       list_for_each_entry(c, &clocks, node) {
+               if (!strcmp(c->name, name)) {
+                       ret = c;
+                       break;
+               }
+       }
+       mutex_unlock(&clocks_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(clk_get);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+static void pll_clk_init(struct clk *clk)
+{
+       u32 pll;
+
+       pll = __raw_readl(LS1X_CLK_PLL_FREQ);
+       clk->rate = (12 + (pll & 0x3f)) * 33 / 2
+                       + ((pll >> 8) & 0x3ff) * 33 / 1024 / 2;
+       clk->rate *= 1000000;
+}
+
+static void cpu_clk_init(struct clk *clk)
+{
+       u32 pll, ctrl;
+
+       pll = clk_get_rate(clk->parent);
+       ctrl = __raw_readl(LS1X_CLK_PLL_DIV) & DIV_CPU;
+       clk->rate = pll / (ctrl >> DIV_CPU_SHIFT);
+}
+
+static void ddr_clk_init(struct clk *clk)
+{
+       u32 pll, ctrl;
+
+       pll = clk_get_rate(clk->parent);
+       ctrl = __raw_readl(LS1X_CLK_PLL_DIV) & DIV_DDR;
+       clk->rate = pll / (ctrl >> DIV_DDR_SHIFT);
+}
+
+static void dc_clk_init(struct clk *clk)
+{
+       u32 pll, ctrl;
+
+       pll = clk_get_rate(clk->parent);
+       ctrl = __raw_readl(LS1X_CLK_PLL_DIV) & DIV_DC;
+       clk->rate = pll / (ctrl >> DIV_DC_SHIFT);
+}
+
+static struct clk_ops pll_clk_ops = {
+       .init   = pll_clk_init,
+};
+
+static struct clk_ops cpu_clk_ops = {
+       .init   = cpu_clk_init,
+};
+
+static struct clk_ops ddr_clk_ops = {
+       .init   = ddr_clk_init,
+};
+
+static struct clk_ops dc_clk_ops = {
+       .init   = dc_clk_init,
+};
+
+static struct clk pll_clk = {
+       .name   = "pll",
+       .ops    = &pll_clk_ops,
+};
+
+static struct clk cpu_clk = {
+       .name   = "cpu",
+       .parent = &pll_clk,
+       .ops    = &cpu_clk_ops,
+};
+
+static struct clk ddr_clk = {
+       .name   = "ddr",
+       .parent = &pll_clk,
+       .ops    = &ddr_clk_ops,
+};
+
+static struct clk dc_clk = {
+       .name   = "dc",
+       .parent = &pll_clk,
+       .ops    = &dc_clk_ops,
+};
+
+int clk_register(struct clk *clk)
+{
+       mutex_lock(&clocks_mutex);
+       list_add(&clk->node, &clocks);
+       if (clk->ops->init)
+               clk->ops->init(clk);
+       mutex_unlock(&clocks_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+static struct clk *ls1x_clks[] = {
+       &pll_clk,
+       &cpu_clk,
+       &ddr_clk,
+       &dc_clk,
+};
+
+int __init ls1x_clock_init(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ls1x_clks); i++)
+               clk_register(ls1x_clks[i]);
+
+       return 0;
+}
+
+void __init plat_time_init(void)
+{
+       struct clk *clk;
+
+       /* Initialize LS1X clocks */
+       ls1x_clock_init();
+
+       /* setup mips r4k timer */
+       clk = clk_get(NULL, "cpu");
+       if (IS_ERR(clk))
+               panic("unable to get dc clock, err=%ld", PTR_ERR(clk));
+
+       mips_hpt_frequency = clk_get_rate(clk) / 2;
+}
diff --git a/arch/mips/loongson1/common/irq.c b/arch/mips/loongson1/common/irq.c
new file mode 100644 (file)
index 0000000..41bc8ff
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/irq_cpu.h>
+
+#include <loongson1.h>
+#include <irq.h>
+
+#define LS1X_INTC_REG(n, x) \
+               ((void __iomem *)KSEG1ADDR(LS1X_INTC_BASE + (n * 0x18) + (x)))
+
+#define LS1X_INTC_INTISR(n)            LS1X_INTC_REG(n, 0x0)
+#define LS1X_INTC_INTIEN(n)            LS1X_INTC_REG(n, 0x4)
+#define LS1X_INTC_INTSET(n)            LS1X_INTC_REG(n, 0x8)
+#define LS1X_INTC_INTCLR(n)            LS1X_INTC_REG(n, 0xc)
+#define LS1X_INTC_INTPOL(n)            LS1X_INTC_REG(n, 0x10)
+#define LS1X_INTC_INTEDGE(n)           LS1X_INTC_REG(n, 0x14)
+
+static void ls1x_irq_ack(struct irq_data *d)
+{
+       unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
+       unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
+
+       __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
+                       | (1 << bit), LS1X_INTC_INTCLR(n));
+}
+
+static void ls1x_irq_mask(struct irq_data *d)
+{
+       unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
+       unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
+
+       __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
+                       & ~(1 << bit), LS1X_INTC_INTIEN(n));
+}
+
+static void ls1x_irq_mask_ack(struct irq_data *d)
+{
+       unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
+       unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
+
+       __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
+                       & ~(1 << bit), LS1X_INTC_INTIEN(n));
+       __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
+                       | (1 << bit), LS1X_INTC_INTCLR(n));
+}
+
+static void ls1x_irq_unmask(struct irq_data *d)
+{
+       unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
+       unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
+
+       __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
+                       | (1 << bit), LS1X_INTC_INTIEN(n));
+}
+
+static struct irq_chip ls1x_irq_chip = {
+       .name           = "LS1X-INTC",
+       .irq_ack        = ls1x_irq_ack,
+       .irq_mask       = ls1x_irq_mask,
+       .irq_mask_ack   = ls1x_irq_mask_ack,
+       .irq_unmask     = ls1x_irq_unmask,
+};
+
+static void ls1x_irq_dispatch(int n)
+{
+       u32 int_status, irq;
+
+       /* Get pending sources, masked by current enables */
+       int_status = __raw_readl(LS1X_INTC_INTISR(n)) &
+                       __raw_readl(LS1X_INTC_INTIEN(n));
+
+       if (int_status) {
+               irq = LS1X_IRQ(n, __ffs(int_status));
+               do_IRQ(irq);
+       }
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+       unsigned int pending;
+
+       pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+       if (pending & CAUSEF_IP7)
+               do_IRQ(TIMER_IRQ);
+       else if (pending & CAUSEF_IP2)
+               ls1x_irq_dispatch(0); /* INT0 */
+       else if (pending & CAUSEF_IP3)
+               ls1x_irq_dispatch(1); /* INT1 */
+       else if (pending & CAUSEF_IP4)
+               ls1x_irq_dispatch(2); /* INT2 */
+       else if (pending & CAUSEF_IP5)
+               ls1x_irq_dispatch(3); /* INT3 */
+       else if (pending & CAUSEF_IP6)
+               ls1x_irq_dispatch(4); /* INT4 */
+       else
+               spurious_interrupt();
+
+}
+
+struct irqaction cascade_irqaction = {
+       .handler = no_action,
+       .name = "cascade",
+       .flags = IRQF_NO_THREAD,
+};
+
+static void __init ls1x_irq_init(int base)
+{
+       int n;
+
+       /* Disable interrupts and clear pending,
+        * setup all IRQs as high level triggered
+        */
+       for (n = 0; n < 4; n++) {
+               __raw_writel(0x0, LS1X_INTC_INTIEN(n));
+               __raw_writel(0xffffffff, LS1X_INTC_INTCLR(n));
+               __raw_writel(0xffffffff, LS1X_INTC_INTPOL(n));
+               /* set DMA0, DMA1 and DMA2 to edge trigger */
+               __raw_writel(n ? 0x0 : 0xe000, LS1X_INTC_INTEDGE(n));
+       }
+
+
+       for (n = base; n < LS1X_IRQS; n++) {
+               irq_set_chip_and_handler(n, &ls1x_irq_chip,
+                                        handle_level_irq);
+       }
+
+       setup_irq(INT0_IRQ, &cascade_irqaction);
+       setup_irq(INT1_IRQ, &cascade_irqaction);
+       setup_irq(INT2_IRQ, &cascade_irqaction);
+       setup_irq(INT3_IRQ, &cascade_irqaction);
+}
+
+void __init arch_init_irq(void)
+{
+       mips_cpu_irq_init();
+       ls1x_irq_init(LS1X_IRQ_BASE);
+}
diff --git a/arch/mips/loongson1/common/platform.c b/arch/mips/loongson1/common/platform.c
new file mode 100644 (file)
index 0000000..e92d59c
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/phy.h>
+#include <linux/serial_8250.h>
+#include <linux/stmmac.h>
+#include <asm-generic/sizes.h>
+
+#include <loongson1.h>
+
+#define LS1X_UART(_id)                                         \
+       {                                                       \
+               .mapbase        = LS1X_UART ## _id ## _BASE,    \
+               .irq            = LS1X_UART ## _id ## _IRQ,     \
+               .iotype         = UPIO_MEM,                     \
+               .flags          = UPF_IOREMAP | UPF_FIXED_TYPE, \
+               .type           = PORT_16550A,                  \
+       }
+
+static struct plat_serial8250_port ls1x_serial8250_port[] = {
+       LS1X_UART(0),
+       LS1X_UART(1),
+       LS1X_UART(2),
+       LS1X_UART(3),
+       {},
+};
+
+struct platform_device ls1x_uart_device = {
+       .name           = "serial8250",
+       .id             = PLAT8250_DEV_PLATFORM,
+       .dev            = {
+               .platform_data = ls1x_serial8250_port,
+       },
+};
+
+void __init ls1x_serial_setup(void)
+{
+       struct clk *clk;
+       struct plat_serial8250_port *p;
+
+       clk = clk_get(NULL, "dc");
+       if (IS_ERR(clk))
+               panic("unable to get dc clock, err=%ld", PTR_ERR(clk));
+
+       for (p = ls1x_serial8250_port; p->flags != 0; ++p)
+               p->uartclk = clk_get_rate(clk);
+}
+
+/* Synopsys Ethernet GMAC */
+static struct resource ls1x_eth0_resources[] = {
+       [0] = {
+               .start  = LS1X_GMAC0_BASE,
+               .end    = LS1X_GMAC0_BASE + SZ_64K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .name   = "macirq",
+               .start  = LS1X_GMAC0_IRQ,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = {
+       .bus_id         = 0,
+       .phy_mask       = 0,
+};
+
+static struct plat_stmmacenet_data ls1x_eth_data = {
+       .bus_id         = 0,
+       .phy_addr       = -1,
+       .mdio_bus_data  = &ls1x_mdio_bus_data,
+       .has_gmac       = 1,
+       .tx_coe         = 1,
+};
+
+struct platform_device ls1x_eth0_device = {
+       .name           = "stmmaceth",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(ls1x_eth0_resources),
+       .resource       = ls1x_eth0_resources,
+       .dev            = {
+               .platform_data = &ls1x_eth_data,
+       },
+};
+
+/* USB EHCI */
+static u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ls1x_ehci_resources[] = {
+       [0] = {
+               .start  = LS1X_EHCI_BASE,
+               .end    = LS1X_EHCI_BASE + SZ_32K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = LS1X_EHCI_IRQ,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device ls1x_ehci_device = {
+       .name           = "ls1x-ehci",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(ls1x_ehci_resources),
+       .resource       = ls1x_ehci_resources,
+       .dev            = {
+               .dma_mask = &ls1x_ehci_dmamask,
+       },
+};
+
+/* Real Time Clock */
+struct platform_device ls1x_rtc_device = {
+       .name           = "ls1x-rtc",
+       .id             = -1,
+};
diff --git a/arch/mips/loongson1/common/prom.c b/arch/mips/loongson1/common/prom.c
new file mode 100644 (file)
index 0000000..1f8e49f
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * Modified from arch/mips/pnx833x/common/prom.c.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/serial_reg.h>
+#include <asm/bootinfo.h>
+
+#include <loongson1.h>
+#include <prom.h>
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+unsigned long memsize, highmemsize;
+
+char *prom_getenv(char *envname)
+{
+       char **env = prom_envp;
+       int i;
+
+       i = strlen(envname);
+
+       while (*env) {
+               if (strncmp(envname, *env, i) == 0 && *(*env+i) == '=')
+                       return *env + i + 1;
+               env++;
+       }
+
+       return 0;
+}
+
+static inline unsigned long env_or_default(char *env, unsigned long dfl)
+{
+       char *str = prom_getenv(env);
+       return str ? simple_strtol(str, 0, 0) : dfl;
+}
+
+void __init prom_init_cmdline(void)
+{
+       char *c = &(arcs_cmdline[0]);
+       int i;
+
+       for (i = 1; i < prom_argc; i++) {
+               strcpy(c, prom_argv[i]);
+               c += strlen(prom_argv[i]);
+               if (i < prom_argc-1)
+                       *c++ = ' ';
+       }
+       *c = 0;
+}
+
+void __init prom_init(void)
+{
+       prom_argc = fw_arg0;
+       prom_argv = (char **)fw_arg1;
+       prom_envp = (char **)fw_arg2;
+
+       prom_init_cmdline();
+
+       memsize = env_or_default("memsize", DEFAULT_MEMSIZE);
+       highmemsize = env_or_default("highmemsize", 0x0);
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+#define PORT(offset)   (u8 *)(KSEG1ADDR(LS1X_UART0_BASE + offset))
+
+void __init prom_putchar(char c)
+{
+       int timeout;
+
+       timeout = 1024;
+
+       while (((readb(PORT(UART_LSR)) & UART_LSR_THRE) == 0)
+                       && (timeout-- > 0))
+               ;
+
+       writeb(c, PORT(UART_TX));
+}
diff --git a/arch/mips/loongson1/common/reset.c b/arch/mips/loongson1/common/reset.c
new file mode 100644 (file)
index 0000000..fb979a7
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/pm.h>
+#include <asm/reboot.h>
+
+#include <loongson1.h>
+
+static void ls1x_restart(char *command)
+{
+       __raw_writel(0x1, LS1X_WDT_EN);
+       __raw_writel(0x5000000, LS1X_WDT_TIMER);
+       __raw_writel(0x1, LS1X_WDT_SET);
+}
+
+static void ls1x_halt(void)
+{
+       while (1) {
+               if (cpu_wait)
+                       cpu_wait();
+       }
+}
+
+static void ls1x_power_off(void)
+{
+       ls1x_halt();
+}
+
+static int __init ls1x_reboot_setup(void)
+{
+       _machine_restart = ls1x_restart;
+       _machine_halt = ls1x_halt;
+       pm_power_off = ls1x_power_off;
+
+       return 0;
+}
+
+arch_initcall(ls1x_reboot_setup);
diff --git a/arch/mips/loongson1/common/setup.c b/arch/mips/loongson1/common/setup.c
new file mode 100644 (file)
index 0000000..62128cc
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <asm/bootinfo.h>
+
+#include <prom.h>
+
+void __init plat_mem_setup(void)
+{
+       add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM);
+}
+
+const char *get_system_type(void)
+{
+       unsigned int processor_id = (&current_cpu_data)->processor_id;
+
+       switch (processor_id & PRID_REV_MASK) {
+       case PRID_REV_LOONGSON1B:
+               return "LOONGSON LS1B";
+       default:
+               return "LOONGSON (unknown)";
+       }
+}
diff --git a/arch/mips/loongson1/ls1b/Makefile b/arch/mips/loongson1/ls1b/Makefile
new file mode 100644 (file)
index 0000000..891eac4
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for loongson1B based machines.
+#
+
+obj-y += board.o
diff --git a/arch/mips/loongson1/ls1b/board.c b/arch/mips/loongson1/ls1b/board.c
new file mode 100644 (file)
index 0000000..295b1be
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <platform.h>
+
+#include <linux/serial_8250.h>
+#include <loongson1.h>
+
+static struct platform_device *ls1b_platform_devices[] __initdata = {
+       &ls1x_uart_device,
+       &ls1x_eth0_device,
+       &ls1x_ehci_device,
+       &ls1x_rtc_device,
+};
+
+static int __init ls1b_platform_init(void)
+{
+       int err;
+
+       ls1x_serial_setup();
+
+       err = platform_add_devices(ls1b_platform_devices,
+                                  ARRAY_SIZE(ls1b_platform_devices));
+       return err;
+}
+
+arch_initcall(ls1b_platform_init);
index 5fa185151fc8c29b121415db015b4bb878a5b7c1..64a28e819064c437dbfc2bd6f90f6f560a54d89b 100644 (file)
@@ -58,18 +58,16 @@ enum fields {
 
 enum opcode {
        insn_invalid,
-       insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
-       insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
-       insn_bne, insn_cache, insn_daddu, insn_daddiu, insn_dmfc0,
-       insn_dmtc0, insn_dsll, insn_dsll32, insn_dsra, insn_dsrl,
-       insn_dsrl32, insn_drotr, insn_drotr32, insn_dsubu, insn_eret,
-       insn_j, insn_jal, insn_jr, insn_ld, insn_ll, insn_lld,
-       insn_lui, insn_lw, insn_mfc0, insn_mtc0, insn_or, insn_ori,
-       insn_pref, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
-       insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, insn_tlbp,
+       insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1,
+       insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
+       insn_bne, insn_cache, insn_daddiu, insn_daddu, insn_dins, insn_dinsm,
+       insn_dmfc0, insn_dmtc0, insn_drotr, insn_drotr32, insn_dsll,
+       insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, insn_dsubu, insn_eret,
+       insn_j, insn_jal, insn_jr, insn_ld, insn_ldx, insn_ll, insn_lld,
+       insn_lui, insn_lw, insn_lwx, insn_mfc0, insn_mtc0, insn_or, insn_ori,
+       insn_pref, insn_rfe, insn_rotr, insn_sc, insn_scd, insn_sd, insn_sll,
+       insn_sra, insn_srl, insn_subu, insn_sw, insn_syscall, insn_tlbp,
        insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori,
-       insn_dins, insn_dinsm, insn_syscall, insn_bbit0, insn_bbit1,
-       insn_lwx, insn_ldx
 };
 
 struct insn {
@@ -90,65 +88,65 @@ struct insn {
 static struct insn insn_table[] __uasminitdata = {
        { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
        { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
-       { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
        { insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
-       { insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+       { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
+       { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+       { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
        { insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-       { insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
+       { insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
        { insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
-       { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
+       { insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
        { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
+       { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
        { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
        { insn_cache,  M(cache_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
        { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
        { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
+       { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
+       { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
        { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
        { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
-       { insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
+       { insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE },
+       { insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE },
        { insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
+       { insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
        { insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
-       { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
        { insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
-       { insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE },
-       { insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE },
+       { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
        { insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
        { insn_eret,  M(cop0_op, cop_op, 0, 0, 0, eret_op),  0 },
-       { insn_j,  M(j_op, 0, 0, 0, 0, 0),  JIMM },
        { insn_jal,  M(jal_op, 0, 0, 0, 0, 0),  JIMM },
+       { insn_j,  M(j_op, 0, 0, 0, 0, 0),  JIMM },
        { insn_jr,  M(spec_op, 0, 0, 0, 0, jr_op),  RS },
        { insn_ld,  M(ld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_ll,  M(ll_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD },
        { insn_lld,  M(lld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_ll,  M(ll_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
        { insn_lui,  M(lui_op, 0, 0, 0, 0, 0),  RT | SIMM },
        { insn_lw,  M(lw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD },
        { insn_mfc0,  M(cop0_op, mfc_op, 0, 0, 0, 0),  RT | RD | SET},
        { insn_mtc0,  M(cop0_op, mtc_op, 0, 0, 0, 0),  RT | RD | SET},
-       { insn_or,  M(spec_op, 0, 0, 0, 0, or_op),  RS | RT | RD },
        { insn_ori,  M(ori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
+       { insn_or,  M(spec_op, 0, 0, 0, 0, or_op),  RS | RT | RD },
        { insn_pref,  M(pref_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
        { insn_rfe,  M(cop0_op, cop_op, 0, 0, 0, rfe_op),  0 },
-       { insn_sc,  M(sc_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_rotr,  M(spec_op, 1, 0, 0, 0, srl_op),  RT | RD | RE },
        { insn_scd,  M(scd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_sc,  M(sc_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
        { insn_sd,  M(sd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
        { insn_sll,  M(spec_op, 0, 0, 0, 0, sll_op),  RT | RD | RE },
        { insn_sra,  M(spec_op, 0, 0, 0, 0, sra_op),  RT | RD | RE },
        { insn_srl,  M(spec_op, 0, 0, 0, 0, srl_op),  RT | RD | RE },
-       { insn_rotr,  M(spec_op, 1, 0, 0, 0, srl_op),  RT | RD | RE },
        { insn_subu,  M(spec_op, 0, 0, 0, 0, subu_op),  RS | RT | RD },
        { insn_sw,  M(sw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
        { insn_tlbp,  M(cop0_op, cop_op, 0, 0, 0, tlbp_op),  0 },
        { insn_tlbr,  M(cop0_op, cop_op, 0, 0, 0, tlbr_op),  0 },
        { insn_tlbwi,  M(cop0_op, cop_op, 0, 0, 0, tlbwi_op),  0 },
        { insn_tlbwr,  M(cop0_op, cop_op, 0, 0, 0, tlbwr_op),  0 },
-       { insn_xor,  M(spec_op, 0, 0, 0, 0, xor_op),  RS | RT | RD },
        { insn_xori,  M(xori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
-       { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
-       { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
-       { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
-       { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-       { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-       { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD },
-       { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD },
+       { insn_xor,  M(spec_op, 0, 0, 0, 0, xor_op),  RS | RT | RD },
        { insn_invalid, 0, 0 }
 };
 
index f193f7b3bd81ce15b23c80fb6acce438be838649..1902fa22d277dc2cdd8ccd1ccad583a71d8cdc7a 100644 (file)
@@ -54,7 +54,7 @@ void prom_putchar(char c)
 #elif defined(CONFIG_CPU_XLR)
        uartbase = nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET);
 #endif
-       while (nlm_read_reg(uartbase, UART_LSR) == 0)
+       while ((nlm_read_reg(uartbase, UART_LSR) & UART_LSR_THRE) == 0)
                ;
        nlm_write_reg(uartbase, UART_TX, c);
 }
index c138b1a6dec3c9af46df99ff0c627d02514c54c9..a13355cc97eb4cdcc4df0020007e5ad9c0935e58 100644 (file)
                        XLP_IO_SYS_OFFSET(node) + XLP_IO_PCI_HDRSZ + \
                        SYS_CPU_NONCOHERENT_MODE * 4
 
-.macro __config_lsu
-       li      t0, LSU_DEFEATURE
-       mfcr    t1, t0
+#define        XLP_AX_WORKAROUND       /* enable Ax silicon workarounds */
 
-       lui     t2, 0x4080  /* Enable Unaligned Access, L2HPE */
-       or      t1, t1, t2
-       li      t2, ~0xe    /* S1RCM */
+/* Enable XLP features and workarounds in the LSU */
+.macro xlp_config_lsu
+       li      t0, LSU_DEFEATURE
+       mfcr    t1, t0
+
+       lui     t2, 0x4080      /* Enable Unaligned Access, L2HPE */
+       or      t1, t1, t2
+#ifdef XLP_AX_WORKAROUND
+       li      t2, ~0xe        /* S1RCM */
        and     t1, t1, t2
-       mtcr    t1, t0
+#endif
+       mtcr    t1, t0
 
-       li      t0, SCHED_DEFEATURE
-       lui     t1, 0x0100  /* Experimental: Disable BRU accepting ALU ops */
-       mtcr    t1, t0
+#ifdef XLP_AX_WORKAROUND
+       li      t0, SCHED_DEFEATURE
+       lui     t1, 0x0100      /* Disable BRU accepting ALU ops */
+       mtcr    t1, t0
+#endif
+.endm
+
+/*
+ * This is the code that will be copied to the reset entry point for
+ * XLR and XLP. The XLP cores start here when they are woken up. This
+ * is also the NMI entry point.
+ */
+.macro xlp_flush_l1_dcache
+       li      t0, LSU_DEBUG_DATA0
+       li      t1, LSU_DEBUG_ADDR
+       li      t2, 0           /* index */
+       li      t3, 0x1000      /* loop count */
+1:
+       sll     v0, t2, 5
+       mtcr    zero, t0
+       ori     v1, v0, 0x3     /* way0 | write_enable | write_active */
+       mtcr    v1, t1
+2:
+       mfcr    v1, t1
+       andi    v1, 0x1         /* wait for write_active == 0 */
+       bnez    v1, 2b
+       nop
+       mtcr    zero, t0
+       ori     v1, v0, 0x7     /* way1 | write_enable | write_active */
+       mtcr    v1, t1
+3:
+       mfcr    v1, t1
+       andi    v1, 0x1         /* wait for write_active == 0 */
+       bnez    v1, 3b
+       nop
+       addi    t2, 1
+       bne     t3, t2, 1b
+       nop
 .endm
 
 /*
  * The cores can come start when they are woken up. This is also the NMI
  * entry, so check that first.
  *
- * The data corresponding to reset is stored at RESET_DATA_PHYS location,
- * this will have the thread mask (used when core is woken up) and the
- * current NMI handler in case we reached here for an NMI.
+ * The data corresponding to reset/NMI is stored at RESET_DATA_PHYS
+ * location, this will have the thread mask (used when core is woken up)
+ * and the current NMI handler in case we reached here for an NMI.
  *
  * When a core or thread is newly woken up, it loops in a 'wait'. When
  * the CPU really needs waking up, we send an NMI to it, with the NMI
 FEXPORT(nlm_reset_entry)
        dmtc0   k0, $22, 6
        dmtc0   k1, $22, 7
-       mfc0    k0, CP0_STATUS
-       li      k1, 0x80000
-       and     k1, k0, k1
-       beqz    k1, 1f         /* go to real reset entry */
+       mfc0    k0, CP0_STATUS
+       li      k1, 0x80000
+       and     k1, k0, k1
+       beqz    k1, 1f          /* go to real reset entry */
        nop
-       li      k1, CKSEG1ADDR(RESET_DATA_PHYS)   /* NMI */
+       li      k1, CKSEG1ADDR(RESET_DATA_PHYS) /* NMI */
        ld      k0, BOOT_NMI_HANDLER(k1)
        jr      k0
        nop
@@ -114,21 +154,25 @@ FEXPORT(nlm_reset_entry)
        li      t2, SYS_CPU_COHERENT_BASE(0)
        add     t2, t2, t3              /* t2 <- SYS offset for node */
        lw      t1, 0(t2)
-       and     t1, t1, t0
-       sw      t1, 0(t2)
+       and     t1, t1, t0
+       sw      t1, 0(t2)
 
        /* read back to ensure complete */
-       lw      t1, 0(t2)
+       lw      t1, 0(t2)
        sync
 
        /* Configure LSU on Non-0 Cores. */
-       __config_lsu
+       xlp_config_lsu
+       /* FALL THROUGH */
 
 /*
  * Wake up sibling threads from the initial thread in
  * a core.
  */
 EXPORT(nlm_boot_siblings)
+       /* core L1D flush before enable threads */
+       xlp_flush_l1_dcache
+       /* Enable hw threads by writing to MAP_THREADMODE of the core */
        li      t0, CKSEG1ADDR(RESET_DATA_PHYS)
        lw      t1, BOOT_THREAD_MODE(t0)        /* t1 <- thread mode */
        li      t0, ((CPU_BLOCKID_MAP << 8) | MAP_THREADMODE)
@@ -139,31 +183,28 @@ EXPORT(nlm_boot_siblings)
        /*
         * The new hardware thread starts at the next instruction
         * For all the cases other than core 0 thread 0, we will
-         * jump to the secondary wait function.
-         */
+       * jump to the secondary wait function.
+       */
        mfc0    v0, CP0_EBASE, 1
        andi    v0, 0x7f                /* v0 <- node/core */
 
-#if 1
-       /* A0 errata - Write MMU_SETUP after changing thread mode register. */
+       /* Init MMU in the first thread after changing THREAD_MODE
+        * register (Ax Errata?)
+        */
        andi    v1, v0, 0x3             /* v1 <- thread id */
        bnez    v1, 2f
        nop
 
-        li     t0, MMU_SETUP
-        li     t1, 0
-        mtcr   t1, t0
-       ehb
-#endif
+       li      t0, MMU_SETUP
+       li      t1, 0
+       mtcr    t1, t0
+       _ehb
 
-2:     beqz    v0, 4f
+2:     beqz    v0, 4f          /* boot cpu (cpuid == 0)? */
        nop
 
        /* setup status reg */
-       mfc0    t1, CP0_STATUS
-       li      t0, ST0_BEV
-       or      t1, t0
-       xor     t1, t0
+       move    t1, zero
 #ifdef CONFIG_64BIT
        ori     t1, ST0_KX
 #endif
@@ -183,9 +224,9 @@ EXPORT(nlm_boot_siblings)
         * For the boot CPU, we have to restore registers and
         * return
         */
-4:     dmfc0   t0, $4, 2       /* restore SP from UserLocal */
+4:     dmfc0   t0, $4, 2       /* restore SP from UserLocal */
        li      t1, 0xfadebeef
-       dmtc0   t1, $4, 2       /* restore SP from UserLocal */
+       dmtc0   t1, $4, 2       /* restore SP from UserLocal */
        PTR_SUBU sp, t0, PT_SIZE
        RESTORE_ALL
        jr   ra
@@ -193,7 +234,7 @@ EXPORT(nlm_boot_siblings)
 EXPORT(nlm_reset_entry_end)
 
 FEXPORT(xlp_boot_core0_siblings)       /* "Master" cpu starts from here */
-       __config_lsu
+       xlp_config_lsu
        dmtc0   sp, $4, 2               /* SP saved in UserLocal */
        SAVE_ALL
        sync
@@ -210,6 +251,12 @@ FEXPORT(xlp_boot_core0_siblings)   /* "Master" cpu starts from here */
 
        __CPUINIT
 NESTED(nlm_boot_secondary_cpus, 16, sp)
+       /* Initialize CP0 Status */
+       move    t1, zero
+#ifdef CONFIG_64BIT
+       ori     t1, ST0_KX
+#endif
+       mtc0    t1, CP0_STATUS
        PTR_LA  t1, nlm_next_sp
        PTR_L   sp, 0(t1)
        PTR_LA  t1, nlm_next_gp
@@ -234,36 +281,36 @@ END(nlm_boot_secondary_cpus)
  */
        __CPUINIT
 NESTED(nlm_rmiboot_preboot, 16, sp)
-       mfc0    t0, $15, 1      # read ebase
-       andi    t0, 0x1f        # t0 has the processor_id()
-       andi    t2, t0, 0x3     # thread no
-       sll     t0, 2           # offset in cpu array
+       mfc0    t0, $15, 1      /* read ebase */
+       andi    t0, 0x1f        /* t0 has the processor_id() */
+       andi    t2, t0, 0x3     /* thread num */
+       sll     t0, 2           /* offset in cpu array */
 
-       PTR_LA  t1, nlm_cpu_ready # mark CPU ready
+       PTR_LA  t1, nlm_cpu_ready /* mark CPU ready */
        PTR_ADDU t1, t0
        li      t3, 1
        sw      t3, 0(t1)
 
-       bnez    t2, 1f          # skip thread programming
-       nop                     # for non zero hw threads
+       bnez    t2, 1f          /* skip thread programming */
+       nop                     /* for thread id != 0 */
 
        /*
-        * MMU setup only for first thread in core
+        * XLR MMU setup only for first thread in core
         */
        li      t0, 0x400
        mfcr    t1, t0
-       li      t2, 6           # XLR thread mode mask
+       li      t2, 6           /* XLR thread mode mask */
        nor     t3, t2, zero
-       and     t2, t1, t2      # t2 - current thread mode
+       and     t2, t1, t2      /* t2 - current thread mode */
        li      v0, CKSEG1ADDR(RESET_DATA_PHYS)
-       lw      v1, BOOT_THREAD_MODE(v0) # v1 - new thread mode
+       lw      v1, BOOT_THREAD_MODE(v0) /* v1 - new thread mode */
        sll     v1, 1
-       beq     v1, t2, 1f      # same as request value
-       nop                     # nothing to do */
+       beq     v1, t2, 1f      /* same as request value */
+       nop                     /* nothing to do */
 
-       and     t2, t1, t3      # mask out old thread mode
-       or      t1, t2, v1      # put in new value
-       mtcr    t1, t0          # update core control
+       and     t2, t1, t3      /* mask out old thread mode */
+       or      t1, t2, v1      /* put in new value */
+       mtcr    t1, t0          /* update core control */
 
 1:     wait
        j       1b
index b93ed83474ecec308585e811b66bf32c59da2410..6b4b972218f040ab9e13b33b6a9b5bd9bee6f2e9 100644 (file)
@@ -1,2 +1,4 @@
 obj-y                          += setup.o platform.o nlm_hal.o
+obj-$(CONFIG_OF)               += of.o
 obj-$(CONFIG_SMP)              += wakeup.o
+obj-$(CONFIG_USB)              += usb-init.o
index 9428e7125fed5d08f8f7161479187e51f8c288c3..6c65ac7019125d5cbfedbb72727fcf4c9614dd2f 100644 (file)
@@ -69,6 +69,32 @@ int nlm_irq_to_irt(int irq)
                return PIC_IRT_UART_0_INDEX;
        case PIC_UART_1_IRQ:
                return PIC_IRT_UART_1_INDEX;
+       case PIC_PCIE_LINK_0_IRQ:
+              return PIC_IRT_PCIE_LINK_0_INDEX;
+       case PIC_PCIE_LINK_1_IRQ:
+              return PIC_IRT_PCIE_LINK_1_INDEX;
+       case PIC_PCIE_LINK_2_IRQ:
+              return PIC_IRT_PCIE_LINK_2_INDEX;
+       case PIC_PCIE_LINK_3_IRQ:
+              return PIC_IRT_PCIE_LINK_3_INDEX;
+       case PIC_EHCI_0_IRQ:
+              return PIC_IRT_EHCI_0_INDEX;
+       case PIC_EHCI_1_IRQ:
+              return PIC_IRT_EHCI_1_INDEX;
+       case PIC_OHCI_0_IRQ:
+              return PIC_IRT_OHCI_0_INDEX;
+       case PIC_OHCI_1_IRQ:
+              return PIC_IRT_OHCI_1_INDEX;
+       case PIC_OHCI_2_IRQ:
+              return PIC_IRT_OHCI_2_INDEX;
+       case PIC_OHCI_3_IRQ:
+              return PIC_IRT_OHCI_3_INDEX;
+       case PIC_MMC_IRQ:
+              return PIC_IRT_MMC_INDEX;
+       case PIC_I2C_0_IRQ:
+               return PIC_IRT_I2C_0_INDEX;
+       case PIC_I2C_1_IRQ:
+               return PIC_IRT_I2C_1_INDEX;
        default:
                return -1;
        }
@@ -81,6 +107,32 @@ int nlm_irt_to_irq(int irt)
                return PIC_UART_0_IRQ;
        case PIC_IRT_UART_1_INDEX:
                return PIC_UART_1_IRQ;
+       case PIC_IRT_PCIE_LINK_0_INDEX:
+              return PIC_PCIE_LINK_0_IRQ;
+       case PIC_IRT_PCIE_LINK_1_INDEX:
+              return PIC_PCIE_LINK_1_IRQ;
+       case PIC_IRT_PCIE_LINK_2_INDEX:
+              return PIC_PCIE_LINK_2_IRQ;
+       case PIC_IRT_PCIE_LINK_3_INDEX:
+              return PIC_PCIE_LINK_3_IRQ;
+       case PIC_IRT_EHCI_0_INDEX:
+               return PIC_EHCI_0_IRQ;
+       case PIC_IRT_EHCI_1_INDEX:
+               return PIC_EHCI_1_IRQ;
+       case PIC_IRT_OHCI_0_INDEX:
+               return PIC_OHCI_0_IRQ;
+       case PIC_IRT_OHCI_1_INDEX:
+               return PIC_OHCI_1_IRQ;
+       case PIC_IRT_OHCI_2_INDEX:
+               return PIC_OHCI_2_IRQ;
+       case PIC_IRT_OHCI_3_INDEX:
+               return PIC_OHCI_3_IRQ;
+       case PIC_IRT_MMC_INDEX:
+              return PIC_MMC_IRQ;
+       case PIC_IRT_I2C_0_INDEX:
+               return PIC_I2C_0_IRQ;
+       case PIC_IRT_I2C_1_INDEX:
+               return PIC_I2C_1_IRQ;
        default:
                return -1;
        }
diff --git a/arch/mips/netlogic/xlp/of.c b/arch/mips/netlogic/xlp/of.c
new file mode 100644 (file)
index 0000000..8e3921c
--- /dev/null
@@ -0,0 +1,34 @@
+#include <linux/bootmem.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of_fdt.h>
+#include <asm/byteorder.h>
+
+static int __init reserve_mem_mach(unsigned long addr, unsigned long size)
+{
+       return reserve_bootmem(addr, size, BOOTMEM_DEFAULT);
+}
+
+void __init free_mem_mach(unsigned long addr, unsigned long size)
+{
+       return free_bootmem(addr, size);
+}
+
+void __init device_tree_init(void)
+{
+       unsigned long base, size;
+
+       if (!initial_boot_params)
+               return;
+
+       base = virt_to_phys((void *)initial_boot_params);
+       size = be32_to_cpu(initial_boot_params->totalsize);
+
+       /* Before we do anything, lets reserve the dt blob */
+       reserve_mem_mach(base, size);
+
+       unflatten_device_tree();
+
+       /* free the space reserved for the dt blob */
+       free_mem_mach(base, size);
+}
index 1f5e4cba891d08bbfdbed4331fa99433860a9179..2c510d5854476d6a8b8a8c25e6ab4eb00ff183a9 100644 (file)
@@ -53,7 +53,7 @@
 
 static unsigned int nlm_xlp_uart_in(struct uart_port *p, int offset)
 {
-        return nlm_read_reg(p->iobase, offset);
+       return nlm_read_reg(p->iobase, offset);
 }
 
 static void nlm_xlp_uart_out(struct uart_port *p, int offset, int value)
index b3df7c2aad1e144fe8be92584272b14aed53973f..3dec9f28b65be488d6ac2ce63ca7f1dbe0e7e80f 100644 (file)
@@ -41,6 +41,8 @@
 #include <asm/bootinfo.h>
 
 #include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
 
 #include <asm/netlogic/haldefs.h>
 #include <asm/netlogic/common.h>
@@ -109,3 +111,17 @@ void __init prom_init(void)
        register_smp_ops(&nlm_smp_ops);
 #endif
 }
+
+static struct of_device_id __initdata xlp_ids[] = {
+       { .compatible = "simple-bus", },
+       {},
+};
+
+int __init xlp8xx_ds_publish_devices(void)
+{
+       if (!of_have_populated_dt())
+               return 0;
+       return of_platform_bus_probe(NULL, xlp_ids, NULL);
+}
+
+device_initcall(xlp8xx_ds_publish_devices);
diff --git a/arch/mips/netlogic/xlp/usb-init.c b/arch/mips/netlogic/xlp/usb-init.c
new file mode 100644 (file)
index 0000000..dbe083a
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * All Rights Reserved
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the Broadcom
+ * license below:
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``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 BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/usb.h>
+
+static void nlm_usb_intr_en(int node, int port)
+{
+       uint32_t val;
+       uint64_t port_addr;
+
+       port_addr = nlm_get_usb_regbase(node, port);
+       val = nlm_read_usb_reg(port_addr, USB_INT_EN);
+       val = USB_CTRL_INTERRUPT_EN  | USB_OHCI_INTERRUPT_EN |
+               USB_OHCI_INTERRUPT1_EN | USB_CTRL_INTERRUPT_EN  |
+               USB_OHCI_INTERRUPT_EN | USB_OHCI_INTERRUPT2_EN;
+       nlm_write_usb_reg(port_addr, USB_INT_EN, val);
+}
+
+static void nlm_usb_hw_reset(int node, int port)
+{
+       uint64_t port_addr;
+       uint32_t val;
+
+       /* reset USB phy */
+       port_addr = nlm_get_usb_regbase(node, port);
+       val = nlm_read_usb_reg(port_addr, USB_PHY_0);
+       val &= ~(USB_PHY_RESET | USB_PHY_PORT_RESET_0 | USB_PHY_PORT_RESET_1);
+       nlm_write_usb_reg(port_addr, USB_PHY_0, val);
+
+       mdelay(100);
+       val = nlm_read_usb_reg(port_addr, USB_CTL_0);
+       val &= ~(USB_CONTROLLER_RESET);
+       val |= 0x4;
+       nlm_write_usb_reg(port_addr, USB_CTL_0, val);
+}
+
+static int __init nlm_platform_usb_init(void)
+{
+       pr_info("Initializing USB Interface\n");
+       nlm_usb_hw_reset(0, 0);
+       nlm_usb_hw_reset(0, 3);
+
+       /* Enable PHY interrupts */
+       nlm_usb_intr_en(0, 0);
+       nlm_usb_intr_en(0, 3);
+
+       return 0;
+}
+
+arch_initcall(nlm_platform_usb_init);
+
+static u64 xlp_usb_dmamask = ~(u32)0;
+
+/* Fixup the IRQ for USB devices which is exist on XLP SOC PCIE bus */
+static void nlm_usb_fixup_final(struct pci_dev *dev)
+{
+       dev->dev.dma_mask               = &xlp_usb_dmamask;
+       dev->dev.coherent_dma_mask      = DMA_BIT_MASK(64);
+       switch (dev->devfn) {
+       case 0x10:
+              dev->irq = PIC_EHCI_0_IRQ;
+              break;
+       case 0x11:
+              dev->irq = PIC_OHCI_0_IRQ;
+              break;
+       case 0x12:
+              dev->irq = PIC_OHCI_1_IRQ;
+              break;
+       case 0x13:
+              dev->irq = PIC_EHCI_1_IRQ;
+              break;
+       case 0x14:
+              dev->irq = PIC_OHCI_2_IRQ;
+              break;
+       case 0x15:
+              dev->irq = PIC_OHCI_3_IRQ;
+              break;
+       }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_EHCI,
+               nlm_usb_fixup_final);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_OHCI,
+               nlm_usb_fixup_final);
index f01e4d7a060031e57de49439e3967067c71d4546..c287dea87570922cb1c973b58ae75b5c26d9b8d5 100644 (file)
@@ -1,2 +1,2 @@
-obj-y                          += setup.o platform.o
+obj-y                          += setup.o platform.o platform-flash.o
 obj-$(CONFIG_SMP)              += wakeup.o
diff --git a/arch/mips/netlogic/xlr/platform-flash.c b/arch/mips/netlogic/xlr/platform-flash.c
new file mode 100644 (file)
index 0000000..340ab16
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2011, Netlogic Microsystems.
+ * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/resource.h>
+#include <linux/spi/flash.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/flash.h>
+#include <asm/netlogic/xlr/bridge.h>
+#include <asm/netlogic/xlr/gpio.h>
+#include <asm/netlogic/xlr/xlr.h>
+
+/*
+ * Default NOR partition layout
+ */
+static struct mtd_partition xlr_nor_parts[] = {
+       {
+               .name = "User FS",
+               .offset = 0x800000,
+               .size   = MTDPART_SIZ_FULL,
+       }
+};
+
+/*
+ * Default NAND partition layout
+ */
+static struct mtd_partition xlr_nand_parts[] = {
+       {
+               .name   = "Root Filesystem",
+               .offset = 64 * 64 * 2048,
+               .size   = 432 * 64 * 2048,
+       },
+       {
+               .name   = "Home Filesystem",
+               .offset = MTDPART_OFS_APPEND,
+               .size   = MTDPART_SIZ_FULL,
+       },
+};
+
+/* Use PHYSMAP flash for NOR */
+struct physmap_flash_data xlr_nor_data = {
+       .width          = 2,
+       .parts          = xlr_nor_parts,
+       .nr_parts       = ARRAY_SIZE(xlr_nor_parts),
+};
+
+static struct resource xlr_nor_res[] = {
+       {
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device xlr_nor_dev = {
+       .name   = "physmap-flash",
+       .dev    = {
+               .platform_data  = &xlr_nor_data,
+       },
+       .num_resources  = ARRAY_SIZE(xlr_nor_res),
+       .resource       = xlr_nor_res,
+};
+
+const char *xlr_part_probes[] = { "cmdlinepart", NULL };
+
+/*
+ * Use "gen_nand" driver for NAND flash
+ *
+ * There seems to be no way to store a private pointer containing
+ * platform specific info in gen_nand drivier. We will use a global
+ * struct for now, since we currently have only one NAND chip per board.
+ */
+struct xlr_nand_flash_priv {
+       int cs;
+       uint64_t flash_mmio;
+};
+
+static struct xlr_nand_flash_priv nand_priv;
+
+static void xlr_nand_ctrl(struct mtd_info *mtd, int cmd,
+               unsigned int ctrl)
+{
+       if (ctrl & NAND_CLE)
+               nlm_write_reg(nand_priv.flash_mmio,
+                       FLASH_NAND_CLE(nand_priv.cs), cmd);
+       else if (ctrl & NAND_ALE)
+               nlm_write_reg(nand_priv.flash_mmio,
+                       FLASH_NAND_ALE(nand_priv.cs), cmd);
+}
+
+struct platform_nand_data xlr_nand_data = {
+       .chip = {
+               .nr_chips       = 1,
+               .nr_partitions  = ARRAY_SIZE(xlr_nand_parts),
+               .chip_delay     = 50,
+               .partitions     = xlr_nand_parts,
+               .part_probe_types = xlr_part_probes,
+       },
+       .ctrl = {
+               .cmd_ctrl       = xlr_nand_ctrl,
+       },
+};
+
+static struct resource xlr_nand_res[] = {
+       {
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device xlr_nand_dev = {
+       .name           = "gen_nand",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(xlr_nand_res),
+       .resource       = xlr_nand_res,
+       .dev            = {
+               .platform_data  = &xlr_nand_data,
+       }
+};
+
+/*
+ * XLR/XLS supports upto 8 devices on its FLASH interface. The value in
+ * FLASH_BAR (on the MEM/IO bridge) gives the base for mapping all the
+ * flash devices.
+ * Under this, each flash device has an offset and size given by the
+ * CSBASE_ADDR and CSBASE_MASK registers for the device.
+ *
+ * The CSBASE_ registers are expected to be setup by the bootloader.
+ */
+static void setup_flash_resource(uint64_t flash_mmio,
+       uint64_t flash_map_base, int cs, struct resource *res)
+{
+       u32 base, mask;
+
+       base = nlm_read_reg(flash_mmio, FLASH_CSBASE_ADDR(cs));
+       mask = nlm_read_reg(flash_mmio, FLASH_CSADDR_MASK(cs));
+
+       res->start = flash_map_base + ((unsigned long)base << 16);
+       res->end = res->start + (mask + 1) * 64 * 1024;
+}
+
+static int __init xlr_flash_init(void)
+{
+       uint64_t gpio_mmio, flash_mmio, flash_map_base;
+       u32 gpio_resetcfg, flash_bar;
+       int cs, boot_nand, boot_nor;
+
+       /* Flash address bits 39:24 is in bridge flash BAR */
+       flash_bar = nlm_read_reg(nlm_io_base, BRIDGE_FLASH_BAR);
+       flash_map_base = (flash_bar & 0xffff0000) << 8;
+
+       gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET);
+       flash_mmio = nlm_mmio_base(NETLOGIC_IO_FLASH_OFFSET);
+
+       /* Get the chip reset config */
+       gpio_resetcfg = nlm_read_reg(gpio_mmio, GPIO_PWRON_RESET_CFG_REG);
+
+       /* Check for boot flash type */
+       boot_nor = boot_nand = 0;
+       if (nlm_chip_is_xls()) {
+               /* On XLS, check boot from NAND bit (GPIO reset reg bit 16) */
+               if (gpio_resetcfg & (1 << 16))
+                       boot_nand = 1;
+
+               /* check boot from PCMCIA, (GPIO reset reg bit 15 */
+               if ((gpio_resetcfg & (1 << 15)) == 0)
+                       boot_nor = 1;   /* not set, booted from NOR */
+       } else { /* XLR */
+               /* check boot from PCMCIA (bit 16 in GPIO reset on XLR) */
+               if ((gpio_resetcfg & (1 << 16)) == 0)
+                       boot_nor = 1;   /* not set, booted from NOR */
+       }
+
+       /* boot flash at chip select 0 */
+       cs = 0;
+
+       if (boot_nand) {
+               nand_priv.cs = cs;
+               nand_priv.flash_mmio = flash_mmio;
+               setup_flash_resource(flash_mmio, flash_map_base, cs,
+                        xlr_nand_res);
+
+               /* Initialize NAND flash at CS 0 */
+               nlm_write_reg(flash_mmio, FLASH_CSDEV_PARM(cs),
+                               FLASH_NAND_CSDEV_PARAM);
+               nlm_write_reg(flash_mmio, FLASH_CSTIME_PARMA(cs),
+                               FLASH_NAND_CSTIME_PARAMA);
+               nlm_write_reg(flash_mmio, FLASH_CSTIME_PARMB(cs),
+                               FLASH_NAND_CSTIME_PARAMB);
+
+               pr_info("ChipSelect %d: NAND Flash %pR\n", cs, xlr_nand_res);
+               return platform_device_register(&xlr_nand_dev);
+       }
+
+       if (boot_nor) {
+               setup_flash_resource(flash_mmio, flash_map_base, cs,
+                       xlr_nor_res);
+               pr_info("ChipSelect %d: NOR Flash %pR\n", cs, xlr_nor_res);
+               return platform_device_register(&xlr_nor_dev);
+       }
+       return 0;
+}
+
+arch_initcall(xlr_flash_init);
index eab64b45dffdb197510ee23683667365cbf81d9c..71b44d82621db706844aacfb52f698128a6f58b6 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/resource.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
+#include <linux/i2c.h>
 
 #include <asm/netlogic/haldefs.h>
 #include <asm/netlogic/xlr/iomap.h>
@@ -97,3 +98,142 @@ static int __init nlm_uart_init(void)
 }
 
 arch_initcall(nlm_uart_init);
+
+#ifdef CONFIG_USB
+/* Platform USB devices, only on XLS chips */
+static u64 xls_usb_dmamask = ~(u32)0;
+#define USB_PLATFORM_DEV(n, i, irq)                                    \
+       {                                                               \
+               .name           = n,                                    \
+               .id             = i,                                    \
+               .num_resources  = 2,                                    \
+               .dev            = {                                     \
+                       .dma_mask       = &xls_usb_dmamask,             \
+                       .coherent_dma_mask = 0xffffffff,                \
+               },                                                      \
+               .resource       = (struct resource[]) {                 \
+                       {                                               \
+                               .flags = IORESOURCE_MEM,                \
+                       },                                              \
+                       {                                               \
+                               .start  = irq,                          \
+                               .end    = irq,                          \
+                               .flags = IORESOURCE_IRQ,                \
+                       },                                              \
+               },                                                      \
+       }
+
+static struct platform_device xls_usb_ehci_device =
+                        USB_PLATFORM_DEV("ehci-xls", 0, PIC_USB_IRQ);
+static struct platform_device xls_usb_ohci_device_0 =
+                        USB_PLATFORM_DEV("ohci-xls-0", 1, PIC_USB_IRQ);
+static struct platform_device xls_usb_ohci_device_1 =
+                        USB_PLATFORM_DEV("ohci-xls-1", 2, PIC_USB_IRQ);
+
+static struct platform_device *xls_platform_devices[] = {
+       &xls_usb_ehci_device,
+       &xls_usb_ohci_device_0,
+       &xls_usb_ohci_device_1,
+};
+
+int xls_platform_usb_init(void)
+{
+       uint64_t usb_mmio, gpio_mmio;
+       unsigned long memres;
+       uint32_t val;
+
+       if (!nlm_chip_is_xls())
+               return 0;
+
+       gpio_mmio = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET);
+       usb_mmio  = nlm_mmio_base(NETLOGIC_IO_USB_1_OFFSET);
+
+       /* Clear Rogue Phy INTs */
+       nlm_write_reg(usb_mmio, 49, 0x10000000);
+       /* Enable all interrupts */
+       nlm_write_reg(usb_mmio, 50, 0x1f000000);
+
+       /* Enable ports */
+       nlm_write_reg(usb_mmio,  1, 0x07000500);
+
+       val = nlm_read_reg(gpio_mmio, 21);
+       if (((val >> 22) & 0x01) == 0) {
+               pr_info("Detected USB Device mode - Not supported!\n");
+               nlm_write_reg(usb_mmio,  0, 0x01000000);
+               return 0;
+       }
+
+       pr_info("Detected USB Host mode - Adding XLS USB devices.\n");
+       /* Clear reset, host mode */
+       nlm_write_reg(usb_mmio,  0, 0x02000000);
+
+       /* Memory resource for various XLS usb ports */
+       usb_mmio = nlm_mmio_base(NETLOGIC_IO_USB_0_OFFSET);
+       memres = CPHYSADDR((unsigned long)usb_mmio);
+       xls_usb_ehci_device.resource[0].start = memres;
+       xls_usb_ehci_device.resource[0].end = memres + 0x400 - 1;
+
+       memres += 0x400;
+       xls_usb_ohci_device_0.resource[0].start = memres;
+       xls_usb_ohci_device_0.resource[0].end = memres + 0x400 - 1;
+
+       memres += 0x400;
+       xls_usb_ohci_device_1.resource[0].start = memres;
+       xls_usb_ohci_device_1.resource[0].end = memres + 0x400 - 1;
+
+       return platform_add_devices(xls_platform_devices,
+                               ARRAY_SIZE(xls_platform_devices));
+}
+
+arch_initcall(xls_platform_usb_init);
+#endif
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info nlm_i2c_board_info1[] __initdata = {
+       /* All XLR boards have this RTC and Max6657 Temp Chip */
+       [0] = {
+               .type   = "ds1374",
+               .addr   = 0x68
+       },
+       [1] = {
+               .type   = "lm90",
+               .addr   = 0x4c
+       },
+};
+
+static struct resource i2c_resources[] = {
+       [0] = {
+               .start  = 0,    /* filled at init */
+               .end    = 0,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device nlm_xlr_i2c_1 = {
+       .name           = "xlr-i2cbus",
+       .id             = 1,
+       .num_resources  = 1,
+       .resource       = i2c_resources,
+};
+
+static int __init nlm_i2c_init(void)
+{
+       int err = 0;
+       unsigned int offset;
+
+       /* I2C bus 0 does not have any useful devices, configure only bus 1 */
+       offset = NETLOGIC_IO_I2C_1_OFFSET;
+       nlm_xlr_i2c_1.resource[0].start = CPHYSADDR(nlm_mmio_base(offset));
+       nlm_xlr_i2c_1.resource[0].end = nlm_xlr_i2c_1.resource[0].start + 0xfff;
+
+       platform_device_register(&nlm_xlr_i2c_1);
+
+       err = i2c_register_board_info(1, nlm_i2c_board_info1,
+                               ARRAY_SIZE(nlm_i2c_board_info1));
+       if (err < 0)
+               pr_err("nlm-i2c: cannot register board I2C devices\n");
+       return err;
+}
+
+arch_initcall(nlm_i2c_init);
+#endif
index c9d066dedc4ec4f79601bd3a7cd1a60be4316f5b..81b1d311834f521bbd9c1b15d2bf7dbed1568011 100644 (file)
@@ -85,7 +85,7 @@ static void nlm_linux_exit(void)
 
        gpiobase = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET);
        /* trigger a chip reset by writing 1 to GPIO_SWRESET_REG */
-       nlm_write_reg(gpiobase, NETLOGIC_GPIO_SWRESET_REG, 1);
+       nlm_write_reg(gpiobase, GPIO_SWRESET_REG, 1);
        for ( ; ; )
                cpu_wait();
 }
index b6e378211a2c940021fb2e7befb342b90b1b1777..f80480a5a0328b3a79d45950c2679577d0345e4a 100644 (file)
@@ -85,6 +85,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
        case CPU_34K:
        case CPU_1004K:
        case CPU_74K:
+       case CPU_LOONGSON1:
        case CPU_SB1:
        case CPU_SB1A:
        case CPU_R10000:
index 4d80a856048d19261e3af077ff1ff5344b3b26d2..28ea1a4cc576c0bb8e566a63a7d4d0caf9221692 100644 (file)
@@ -339,12 +339,6 @@ static int __init mipsxx_init(void)
                break;
 
        case CPU_1004K:
-#if 0
-               /* FIXME: report as 34K for now */
-               op_model_mipsxx_ops.cpu_type = "mips/1004K";
-               break;
-#endif
-
        case CPU_34K:
                op_model_mipsxx_ops.cpu_type = "mips/34K";
                break;
@@ -374,6 +368,10 @@ static int __init mipsxx_init(void)
                op_model_mipsxx_ops.cpu_type = "mips/sb1";
                break;
 
+       case CPU_LOONGSON1:
+               op_model_mipsxx_ops.cpu_type = "mips/loongson1";
+               break;
+
        default:
                printk(KERN_ERR "Profiling unsupported for this CPU\n");
 
index c703f43a9914bee08452c9db536b53b82fc9f037..e13a71cbc3c7550d5f9980f59ad1afe5d684dd27 100644 (file)
@@ -59,6 +59,7 @@ obj-$(CONFIG_WR_PPMC)         += fixup-wrppmc.o
 obj-$(CONFIG_MIKROTIK_RB532)   += pci-rc32434.o ops-rc32434.o fixup-rc32434.o
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += pci-octeon.o pcie-octeon.o
 obj-$(CONFIG_CPU_XLR)          += pci-xlr.o
+obj-$(CONFIG_CPU_XLP)          += pci-xlp.o
 
 ifdef CONFIG_PCI_MSI
 obj-$(CONFIG_CPU_CAVIUM_OCTEON)        += msi-octeon.o
index 9553b14002dda51a757cf06ccb0bca5483b86c1a..3e7ce65d776c83ff32a935d38320153c913f54b9 100644 (file)
@@ -37,7 +37,7 @@
 #define VIA_COBALT_BRD_ID_REG  0x94
 #define VIA_COBALT_BRD_REG_to_ID(reg)  ((unsigned char)(reg) >> 4)
 
-static void qube_raq_galileo_early_fixup(struct pci_dev *dev)
+static void __devinit qube_raq_galileo_early_fixup(struct pci_dev *dev)
 {
        if (dev->devfn == PCI_DEVFN(0, 0) &&
                (dev->class >> 8) == PCI_CLASS_MEMORY_OTHER) {
@@ -51,7 +51,7 @@ static void qube_raq_galileo_early_fixup(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,
         qube_raq_galileo_early_fixup);
 
-static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
+static void __devinit qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
 {
        unsigned short cfgword;
        unsigned char lt;
@@ -74,7 +74,7 @@ static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,
         qube_raq_via_bmIDE_fixup);
 
-static void qube_raq_galileo_fixup(struct pci_dev *dev)
+static void __devinit qube_raq_galileo_fixup(struct pci_dev *dev)
 {
        if (dev->devfn != PCI_DEVFN(0, 0))
                return;
@@ -129,7 +129,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,
 
 int cobalt_board_id;
 
-static void qube_raq_via_board_id_fixup(struct pci_dev *dev)
+static void __devinit qube_raq_via_board_id_fixup(struct pci_dev *dev)
 {
        u8 id;
        int retval;
index 70073c98ed320dc6f88f457028c8b9cd094e93ab..819622f93e9cec97a620d24941dcb80549f000ca 100644 (file)
@@ -101,3 +101,17 @@ static void __devinit malta_piix_func1_fixup(struct pci_dev *pdev)
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,
         malta_piix_func1_fixup);
+
+/* Enable PCI 2.1 compatibility in PIIX4 */
+static void __devinit quirk_dlcsetup(struct pci_dev *dev)
+{
+       u8 odlc, ndlc;
+
+       (void) pci_read_config_byte(dev, 0x82, &odlc);
+       /* Enable passive releases and delayed transaction */
+       ndlc = odlc | 7;
+       (void) pci_write_config_byte(dev, 0x82, ndlc);
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
+       quirk_dlcsetup);
index 3d86823d03a0a5cc158f8d2d7c2bbe7374ee5ca5..76bb1be99d432bc935af5ee93698093dafa42d8a 100644 (file)
@@ -47,7 +47,7 @@ int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
        return irq + GROUP4_IRQ_BASE + 4;
 }
 
-static void rc32434_pci_early_fixup(struct pci_dev *dev)
+static void __devinit rc32434_pci_early_fixup(struct pci_dev *dev)
 {
        if (PCI_SLOT(dev->devfn) == 6 && dev->bus->number == 0) {
                /* disable prefetched memory range */
index 822ae179bc56539ea9b9895822fbae12ae0e364b..65c7bd1004860d3e3eb7490d98f78c4718e5be81 100644 (file)
@@ -411,7 +411,7 @@ struct pci_ops bcm63xx_cb_ops = {
  * only one IO window, so it  cannot be shared by PCI and cardbus, use
  * fixup to choose and detect unhandled configuration
  */
-static void bcm63xx_fixup(struct pci_dev *dev)
+static void __devinit bcm63xx_fixup(struct pci_dev *dev)
 {
        static int io_window = -1;
        int i, found, new_io_window;
@@ -465,3 +465,64 @@ static void bcm63xx_fixup(struct pci_dev *dev)
 
 DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, bcm63xx_fixup);
 #endif
+
+static int bcm63xx_pcie_can_access(struct pci_bus *bus, int devfn)
+{
+       switch (bus->number) {
+       case PCIE_BUS_BRIDGE:
+               return (PCI_SLOT(devfn) == 0);
+       case PCIE_BUS_DEVICE:
+               if (PCI_SLOT(devfn) == 0)
+                       return bcm_pcie_readl(PCIE_DLSTATUS_REG)
+                                       & DLSTATUS_PHYLINKUP;
+       default:
+               return false;
+       }
+}
+
+static int bcm63xx_pcie_read(struct pci_bus *bus, unsigned int devfn,
+                            int where, int size, u32 *val)
+{
+       u32 data;
+       u32 reg = where & ~3;
+
+       if (!bcm63xx_pcie_can_access(bus, devfn))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       if (bus->number == PCIE_BUS_DEVICE)
+               reg += PCIE_DEVICE_OFFSET;
+
+       data = bcm_pcie_readl(reg);
+
+       *val = postprocess_read(data, where, size);
+
+       return PCIBIOS_SUCCESSFUL;
+
+}
+
+static int bcm63xx_pcie_write(struct pci_bus *bus, unsigned int devfn,
+                             int where, int size, u32 val)
+{
+       u32 data;
+       u32 reg = where & ~3;
+
+       if (!bcm63xx_pcie_can_access(bus, devfn))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       if (bus->number == PCIE_BUS_DEVICE)
+               reg += PCIE_DEVICE_OFFSET;
+
+
+       data = bcm_pcie_readl(reg);
+
+       data = preprocess_write(data, val, where, size);
+       bcm_pcie_writel(data, reg);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+struct pci_ops bcm63xx_pcie_ops = {
+       .read   = bcm63xx_pcie_read,
+       .write  = bcm63xx_pcie_write
+};
index 39eb7c417e2fadf4b1d3999f9b2af9c91934de84..8a48139d219cc2c8918f3f5597333683c3e0ea65 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <asm/bootinfo.h>
 
 #include "pci-bcm63xx.h"
@@ -71,6 +72,26 @@ struct pci_controller bcm63xx_cb_controller = {
 };
 #endif
 
+static struct resource bcm_pcie_mem_resource = {
+       .name   = "bcm63xx PCIe memory space",
+       .start  = BCM_PCIE_MEM_BASE_PA,
+       .end    = BCM_PCIE_MEM_END_PA,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct resource bcm_pcie_io_resource = {
+       .name   = "bcm63xx PCIe IO space",
+       .start  = 0,
+       .end    = 0,
+       .flags  = 0,
+};
+
+struct pci_controller bcm63xx_pcie_controller = {
+       .pci_ops        = &bcm63xx_pcie_ops,
+       .io_resource    = &bcm_pcie_io_resource,
+       .mem_resource   = &bcm_pcie_mem_resource,
+};
+
 static u32 bcm63xx_int_cfg_readl(u32 reg)
 {
        u32 tmp;
@@ -94,17 +115,99 @@ static void bcm63xx_int_cfg_writel(u32 val, u32 reg)
 
 void __iomem *pci_iospace_start;
 
-static int __init bcm63xx_pci_init(void)
+static void __init bcm63xx_reset_pcie(void)
 {
-       unsigned int mem_size;
        u32 val;
 
-       if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358() && !BCMCPU_IS_6368())
-               return -ENODEV;
+       /* enable clock */
+       val = bcm_perf_readl(PERF_CKCTL_REG);
+       val |= CKCTL_6328_PCIE_EN;
+       bcm_perf_writel(val, PERF_CKCTL_REG);
+
+       /* enable SERDES */
+       val = bcm_misc_readl(MISC_SERDES_CTRL_REG);
+       val |= SERDES_PCIE_EN | SERDES_PCIE_EXD_EN;
+       bcm_misc_writel(val, MISC_SERDES_CTRL_REG);
+
+       /* reset the PCIe core */
+       val = bcm_perf_readl(PERF_SOFTRESET_6328_REG);
+
+       val &= ~SOFTRESET_6328_PCIE_MASK;
+       val &= ~SOFTRESET_6328_PCIE_CORE_MASK;
+       val &= ~SOFTRESET_6328_PCIE_HARD_MASK;
+       val &= ~SOFTRESET_6328_PCIE_EXT_MASK;
+       bcm_perf_writel(val, PERF_SOFTRESET_6328_REG);
+       mdelay(10);
+
+       val |= SOFTRESET_6328_PCIE_MASK;
+       val |= SOFTRESET_6328_PCIE_CORE_MASK;
+       val |= SOFTRESET_6328_PCIE_HARD_MASK;
+       bcm_perf_writel(val, PERF_SOFTRESET_6328_REG);
+       mdelay(10);
+
+       val |= SOFTRESET_6328_PCIE_EXT_MASK;
+       bcm_perf_writel(val, PERF_SOFTRESET_6328_REG);
+       mdelay(200);
+}
 
-       if (!bcm63xx_pci_enabled)
-               return -ENODEV;
+static int __init bcm63xx_register_pcie(void)
+{
+       u32 val;
 
+       bcm63xx_reset_pcie();
+
+       /* configure the PCIe bridge */
+       val = bcm_pcie_readl(PCIE_BRIDGE_OPT1_REG);
+       val |= OPT1_RD_BE_OPT_EN;
+       val |= OPT1_RD_REPLY_BE_FIX_EN;
+       val |= OPT1_PCIE_BRIDGE_HOLE_DET_EN;
+       val |= OPT1_L1_INT_STATUS_MASK_POL;
+       bcm_pcie_writel(val, PCIE_BRIDGE_OPT1_REG);
+
+       /* setup the interrupts */
+       val = bcm_pcie_readl(PCIE_BRIDGE_RC_INT_MASK_REG);
+       val |= PCIE_RC_INT_A | PCIE_RC_INT_B | PCIE_RC_INT_C | PCIE_RC_INT_D;
+       bcm_pcie_writel(val, PCIE_BRIDGE_RC_INT_MASK_REG);
+
+       val = bcm_pcie_readl(PCIE_BRIDGE_OPT2_REG);
+       /* enable credit checking and error checking */
+       val |= OPT2_TX_CREDIT_CHK_EN;
+       val |= OPT2_UBUS_UR_DECODE_DIS;
+
+       /* set device bus/func for the pcie device */
+       val |= (PCIE_BUS_DEVICE << OPT2_CFG_TYPE1_BUS_NO_SHIFT);
+       val |= OPT2_CFG_TYPE1_BD_SEL;
+       bcm_pcie_writel(val, PCIE_BRIDGE_OPT2_REG);
+
+       /* setup class code as bridge */
+       val = bcm_pcie_readl(PCIE_IDVAL3_REG);
+       val &= ~IDVAL3_CLASS_CODE_MASK;
+       val |= (PCI_CLASS_BRIDGE_PCI << IDVAL3_SUBCLASS_SHIFT);
+       bcm_pcie_writel(val, PCIE_IDVAL3_REG);
+
+       /* disable bar1 size */
+       val = bcm_pcie_readl(PCIE_CONFIG2_REG);
+       val &= ~CONFIG2_BAR1_SIZE_MASK;
+       bcm_pcie_writel(val, PCIE_CONFIG2_REG);
+
+       /* set bar0 to little endian */
+       val = (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_BASE_SHIFT;
+       val |= (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_MASK_SHIFT;
+       val |= BASEMASK_REMAP_EN;
+       bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_BASEMASK_REG);
+
+       val = (BCM_PCIE_MEM_BASE_PA >> 20) << REBASE_ADDR_BASE_SHIFT;
+       bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_REBASE_ADDR_REG);
+
+       register_pci_controller(&bcm63xx_pcie_controller);
+
+       return 0;
+}
+
+static int __init bcm63xx_register_pci(void)
+{
+       unsigned int mem_size;
+       u32 val;
        /*
         * configuration  access are  done through  IO space,  remap 4
         * first bytes to access it from CPU.
@@ -221,4 +324,22 @@ static int __init bcm63xx_pci_init(void)
        return 0;
 }
 
+
+static int __init bcm63xx_pci_init(void)
+{
+       if (!bcm63xx_pci_enabled)
+               return -ENODEV;
+
+       switch (bcm63xx_get_cpu_id()) {
+       case BCM6328_CPU_ID:
+               return bcm63xx_register_pcie();
+       case BCM6348_CPU_ID:
+       case BCM6358_CPU_ID:
+       case BCM6368_CPU_ID:
+               return bcm63xx_register_pci();
+       default:
+               return -ENODEV;
+       }
+}
+
 arch_initcall(bcm63xx_pci_init);
index a6e594ef3d6a371300907d141bbfab1a5e0365d7..e6736d558ac746ea7125d831c8644479ca464c91 100644 (file)
  */
 #define CARDBUS_PCI_IDSEL      0x8
 
+
+#define PCIE_BUS_BRIDGE                0
+#define PCIE_BUS_DEVICE                1
+
 /*
  * defined in ops-bcm63xx.c
  */
 extern struct pci_ops bcm63xx_pci_ops;
 extern struct pci_ops bcm63xx_cb_ops;
+extern struct pci_ops bcm63xx_pcie_ops;
 
 /*
  * defined in pci-bcm63xx.c
diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c
new file mode 100644 (file)
index 0000000..140557a
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * All Rights Reserved
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the Broadcom
+ * license below:
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``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 BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/msi.h>
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/haldefs.h>
+
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/pic.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/pcibus.h>
+#include <asm/netlogic/xlp-hal/bridge.h>
+
+static void *pci_config_base;
+
+#define        pci_cfg_addr(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off))
+
+/* PCI ops */
+static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn,
+       int where)
+{
+       u32 data;
+       u32 *cfgaddr;
+
+       cfgaddr = (u32 *)(pci_config_base +
+                       pci_cfg_addr(bus->number, devfn, where & ~3));
+       data = *cfgaddr;
+       return data;
+}
+
+static inline void pci_cfg_write_32bit(struct pci_bus *bus, unsigned int devfn,
+       int where, u32 data)
+{
+       u32 *cfgaddr;
+
+       cfgaddr = (u32 *)(pci_config_base +
+                       pci_cfg_addr(bus->number, devfn, where & ~3));
+       *cfgaddr = data;
+}
+
+static int nlm_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+       int where, int size, u32 *val)
+{
+       u32 data;
+
+       if ((size == 2) && (where & 1))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       else if ((size == 4) && (where & 3))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       data = pci_cfg_read_32bit(bus, devfn, where);
+
+       if (size == 1)
+               *val = (data >> ((where & 3) << 3)) & 0xff;
+       else if (size == 2)
+               *val = (data >> ((where & 3) << 3)) & 0xffff;
+       else
+               *val = data;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int nlm_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+               int where, int size, u32 val)
+{
+       u32 data;
+
+       if ((size == 2) && (where & 1))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       else if ((size == 4) && (where & 3))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       data = pci_cfg_read_32bit(bus, devfn, where);
+
+       if (size == 1)
+               data = (data & ~(0xff << ((where & 3) << 3))) |
+                       (val << ((where & 3) << 3));
+       else if (size == 2)
+               data = (data & ~(0xffff << ((where & 3) << 3))) |
+                       (val << ((where & 3) << 3));
+       else
+               data = val;
+
+       pci_cfg_write_32bit(bus, devfn, where, data);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops nlm_pci_ops = {
+       .read  = nlm_pcibios_read,
+       .write = nlm_pcibios_write
+};
+
+static struct resource nlm_pci_mem_resource = {
+       .name           = "XLP PCI MEM",
+       .start          = 0xd0000000UL, /* 256MB PCI mem @ 0xd000_0000 */
+       .end            = 0xdfffffffUL,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct resource nlm_pci_io_resource = {
+       .name           = "XLP IO MEM",
+       .start          = 0x14000000UL, /* 64MB PCI IO @ 0x1000_0000 */
+       .end            = 0x17ffffffUL,
+       .flags          = IORESOURCE_IO,
+};
+
+struct pci_controller nlm_pci_controller = {
+       .index          = 0,
+       .pci_ops        = &nlm_pci_ops,
+       .mem_resource   = &nlm_pci_mem_resource,
+       .mem_offset     = 0x00000000UL,
+       .io_resource    = &nlm_pci_io_resource,
+       .io_offset      = 0x00000000UL,
+};
+
+static int get_irq_vector(const struct pci_dev *dev)
+{
+       /*
+        * For XLP PCIe, there is an IRQ per Link, find out which
+        * link the device is on to assign interrupts
+       */
+       if (dev->bus->self == NULL)
+               return 0;
+
+       switch  (dev->bus->self->devfn) {
+       case 0x8:
+               return PIC_PCIE_LINK_0_IRQ;
+       case 0x9:
+               return PIC_PCIE_LINK_1_IRQ;
+       case 0xa:
+               return PIC_PCIE_LINK_2_IRQ;
+       case 0xb:
+               return PIC_PCIE_LINK_3_IRQ;
+       }
+       WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn);
+       return 0;
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       return get_irq_vector(dev);
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
+
+static int xlp_enable_pci_bswap(void)
+{
+       uint64_t pciebase, sysbase;
+       int node, i;
+       u32 reg;
+
+       /* Chip-0 so node set to 0 */
+       node = 0;
+       sysbase = nlm_get_bridge_regbase(node);
+       /*
+        *  Enable byte swap in hardware. Program each link's PCIe SWAP regions
+        * from the link's address ranges.
+        */
+       for (i = 0; i < 4; i++) {
+               pciebase = nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, i));
+               if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff)
+                       continue;
+
+               reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEMEM_BASE0 + i);
+               nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_MEM_BASE, reg);
+
+               reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEMEM_LIMIT0 + i);
+               nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_MEM_LIM,
+                       reg | 0xfff);
+
+               reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_BASE0 + i);
+               nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_BASE, reg);
+
+               reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_LIMIT0 + i);
+               nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff);
+       }
+       return 0;
+}
+
+static int __init pcibios_init(void)
+{
+       /* Firmware assigns PCI resources */
+       pci_set_flags(PCI_PROBE_ONLY);
+       pci_config_base = ioremap(XLP_DEFAULT_PCI_ECFG_BASE, 64 << 20);
+
+       /* Extend IO port for memory mapped io */
+       ioport_resource.start =  0;
+       ioport_resource.end   = ~0;
+
+       xlp_enable_pci_bswap();
+       set_io_port_base(CKSEG1);
+       nlm_pci_controller.io_map_base = CKSEG1;
+
+       register_pci_controller(&nlm_pci_controller);
+       pr_info("XLP PCIe Controller %pR%pR.\n", &nlm_pci_io_resource,
+               &nlm_pci_mem_resource);
+
+       return 0;
+}
+arch_initcall(pcibios_init);
index 172af1cd58672e137924e88dae7f37dcf82393be..18af021d289ac83f5930098d20b9d880ae680780 100644 (file)
@@ -375,7 +375,3 @@ static int __init pcibios_init(void)
 }
 
 arch_initcall(pcibios_init);
-
-struct pci_fixup pcibios_fixups[] = {
-       {0}
-};
index 644eb7c3210ff4b794eb4e80c50dedaaba3eabc2..4b328ac430509b73095b24eb806a80003e7124ab 100644 (file)
@@ -91,7 +91,7 @@ void __init pnx833x_board_setup(void)
        pnx833x_gpio_select_function_alt(32);
        pnx833x_gpio_select_function_alt(33);
 
-#if defined(CONFIG_MTD_NAND_PLATFORM) || defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
+#if IS_ENABLED(CONFIG_MTD_NAND_PLATFORM)
        /* Setup MIU for NAND access on CS0...
         *
         * (it seems that we must also configure CS1 for reliable operation,
@@ -117,7 +117,7 @@ void __init pnx833x_board_setup(void)
        pnx833x_gpio_select_output(5);
        pnx833x_gpio_write(1, 5);
 
-#elif defined(CONFIG_MTD_CFI) || defined(CONFIG_MTD_CFI_MODULE)
+#elif IS_ENABLED(CONFIG_MTD_CFI)
 
        /* Set up MIU for 16-bit NOR access on CS0 and CS1... */
 
index 125db323ab1ec684819c980d5b7a8e2a8f846e00..4efd9185f294643d28aefe755c52c9d52e071f84 100644 (file)
@@ -304,7 +304,7 @@ static void __devinit quirk_slc90e66_bridge(struct pci_dev *dev)
        smsc_fdc37m81x_config_end();
 }
 
-static void quirk_slc90e66_ide(struct pci_dev *dev)
+static void __devinit quirk_slc90e66_ide(struct pci_dev *dev)
 {
        unsigned char dat;
        int regs[2] = {0x41, 0x43};
@@ -339,7 +339,7 @@ static void quirk_slc90e66_ide(struct pci_dev *dev)
 }
 #endif /* CONFIG_TOSHIBA_FPCIB0 */
 
-static void tc35815_fixup(struct pci_dev *dev)
+static void __devinit tc35815_fixup(struct pci_dev *dev)
 {
        /* This device may have PM registers but not they are not suported. */
        if (dev->pm_cap) {
@@ -348,7 +348,7 @@ static void tc35815_fixup(struct pci_dev *dev)
        }
 }
 
-static void final_fixup(struct pci_dev *dev)
+static void __devinit final_fixup(struct pci_dev *dev)
 {
        unsigned char bist;
 
index ae77a7916c03665c5ca03735f18f57822cff1814..560fe89917537972050d9ed8ee09e78a2df736f8 100644 (file)
@@ -632,7 +632,7 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr,
                                    unsigned long size,
                                    const struct physmap_flash_data *pdata)
 {
-#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+#if IS_ENABLED(CONFIG_MTD_PHYSMAP)
        struct resource res = {
                .start = addr,
                .end = addr + size - 1,
@@ -670,8 +670,7 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr,
 void __init txx9_ndfmc_init(unsigned long baseaddr,
                            const struct txx9ndfmc_platform_data *pdata)
 {
-#if defined(CONFIG_MTD_NAND_TXX9NDFMC) || \
-       defined(CONFIG_MTD_NAND_TXX9NDFMC_MODULE)
+#if IS_ENABLED(CONFIG_MTD_NAND_TXX9NDFMC)
        struct resource res = {
                .start = baseaddr,
                .end = baseaddr + 0x1000 - 1,
@@ -687,7 +686,7 @@ void __init txx9_ndfmc_init(unsigned long baseaddr,
 #endif
 }
 
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#if IS_ENABLED(CONFIG_LEDS_GPIO)
 static DEFINE_SPINLOCK(txx9_iocled_lock);
 
 #define TXX9_IOCLED_MAXLEDS 8
@@ -810,7 +809,7 @@ void __init txx9_iocled_init(unsigned long baseaddr,
 void __init txx9_dmac_init(int id, unsigned long baseaddr, int irq,
                           const struct txx9dmac_platform_data *pdata)
 {
-#if defined(CONFIG_TXX9_DMAC) || defined(CONFIG_TXX9_DMAC_MODULE)
+#if IS_ENABLED(CONFIG_TXX9_DMAC)
        struct resource res[] = {
                {
                        .start = baseaddr,
@@ -866,8 +865,7 @@ void __init txx9_aclc_init(unsigned long baseaddr, int irq,
                           unsigned int dma_chan_out,
                           unsigned int dma_chan_in)
 {
-#if defined(CONFIG_SND_SOC_TXX9ACLC) || \
-       defined(CONFIG_SND_SOC_TXX9ACLC_MODULE)
+#if IS_ENABLED(CONFIG_SND_SOC_TXX9ACLC)
        unsigned int dma_base = dmac_id * TXX9_DMA_MAX_NR_CHANNELS;
        struct resource res[] = {
                {
index 6567895d1f5975315b6f6f141fc4b419e617e9f7..5ff7a9584daf4d4c9cc1fa9c14ae126319a0279d 100644 (file)
@@ -317,7 +317,7 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask)
        }
 }
 
-#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)
+#if IS_ENABLED(CONFIG_TC35815)
 static u32 tx4939_get_eth_speed(struct net_device *dev)
 {
        struct ethtool_cmd cmd;
index 2ad8973ba13d732d8a5770473de98197cf33fe1f..e15641d930922403743cec832774bc347dd06511 100644 (file)
@@ -40,8 +40,7 @@ static void __init rbtx4939_time_init(void)
        tx4939_time_init(0);
 }
 
-#if defined(__BIG_ENDIAN) && \
-       (defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE))
+#if defined(__BIG_ENDIAN) && IS_ENABLED(CONFIG_SMC91X)
 #define HAVE_RBTX4939_IOSWAB
 #define IS_CE1_ADDR(addr) \
        ((((unsigned long)(addr) - IO_BASE) & 0xfff00000) == TXX9_CE(1))
@@ -187,7 +186,7 @@ static void __init rbtx4939_update_ioc_pen(void)
 
 #define RBTX4939_MAX_7SEGLEDS  8
 
-#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+#if IS_ENABLED(CONFIG_LEDS_CLASS)
 static u8 led_val[RBTX4939_MAX_7SEGLEDS];
 struct rbtx4939_led_data {
        struct led_classdev cdev;
@@ -263,7 +262,7 @@ static inline void rbtx4939_led_setup(void)
 
 static void __rbtx4939_7segled_putc(unsigned int pos, unsigned char val)
 {
-#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+#if IS_ENABLED(CONFIG_LEDS_CLASS)
        unsigned long flags;
        local_irq_save(flags);
        /* bit7: reserved for LED class */
@@ -287,7 +286,7 @@ static void rbtx4939_7segled_putc(unsigned int pos, unsigned char val)
        __rbtx4939_7segled_putc(pos, val);
 }
 
-#if defined(CONFIG_MTD_RBTX4939) || defined(CONFIG_MTD_RBTX4939_MODULE)
+#if IS_ENABLED(CONFIG_MTD_RBTX4939)
 /* special mapping for boot rom */
 static unsigned long rbtx4939_flash_fixup_ofs(unsigned long ofs)
 {
@@ -463,7 +462,7 @@ static void __init rbtx4939_device_init(void)
                .flags = SMC91X_USE_16BIT,
        };
        struct platform_device *pdev;
-#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)
+#if IS_ENABLED(CONFIG_TC35815)
        int i, j;
        unsigned char ethaddr[2][6];
        u8 bdipsw = readb(rbtx4939_bdipsw_addr) & 0x0f;
index 687f9b4a2ed6cc5fba93f7eda6288a6d10fc7b57..5cfb086b39034417208a3efd4a708c5835c91db7 100644 (file)
@@ -3,6 +3,7 @@ config MN10300
        select HAVE_OPROFILE
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
+       select ARCH_WANT_IPC_PARSE_VERSION
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_KGDB
        select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER
diff --git a/arch/mn10300/include/asm/ipc.h b/arch/mn10300/include/asm/ipc.h
deleted file mode 100644 (file)
index a46e3d9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ipc.h>
index 9051f921cbc7a94252212b625f1161759d054965..866eb14749d7701cb4dafce5566d8aa00df18fe6 100644 (file)
 /*
  * specify the deprecated syscalls we want to support on this arch
  */
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_OLD_STAT
 #define __ARCH_WANT_STAT64
index 3f35c38d7b6498505c1563eef1a8e39adc41ba1f..0922959663a0fd92f0799761500164042e63d74b 100644 (file)
@@ -13,7 +13,6 @@ generic-y += cacheflush.h
 generic-y += checksum.h
 generic-y += cmpxchg.h
 generic-y += cmpxchg-local.h
-generic-y += cpumask.h
 generic-y += cputime.h
 generic-y += current.h
 generic-y += device.h
@@ -43,7 +42,6 @@ generic-y += percpu.h
 generic-y += poll.h
 generic-y += posix_types.h
 generic-y += resource.h
-generic-y += rmap.h
 generic-y += scatterlist.h
 generic-y += sections.h
 generic-y += segment.h
index 9a5d3cdc3e12f16e3dcbd2060e214dbc8ef23881..352f416269ce245c515e25e0cc5cbcf5a446d2a6 100644 (file)
@@ -115,11 +115,13 @@ config PPC
        select HAVE_OPROFILE
        select HAVE_SYSCALL_WRAPPERS if PPC64
        select GENERIC_ATOMIC64 if PPC32
+       select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
        select HAVE_GENERIC_HARDIRQS
+       select ARCH_WANT_IPC_PARSE_VERSION
        select SPARSE_IRQ
        select IRQ_PER_CPU
        select IRQ_DOMAIN
index 852e5b27485d4c76b64430c7322a87d23a3189e2..57573bd52caa89243c3379440ae54e89977aec94 100644 (file)
@@ -56,7 +56,7 @@
                ranges = <0x0 0x0 0xffe00000 0x100000>;
        };
 
-       pci0: pcie@ffe08000 {
+       pci2: pcie@ffe08000 {
                reg = <0 0xffe08000 0 0x1000>;
                status = "disabled";
        };
@@ -76,7 +76,7 @@
                };
        };
 
-       pci2: pcie@ffe0a000 {
+       pci0: pcie@ffe0a000 {
                reg = <0 0xffe0a000 0 0x1000>;
                ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000
                          0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
index b5a56ca51cf7d920dc83536601299c0cc17d4788..470247ea68b4d4237d9ab08255fa6e2ecf12d65e 100644 (file)
@@ -56,7 +56,7 @@
                ranges = <0x0 0xf 0xffe00000 0x100000>;
        };
 
-       pci0: pcie@fffe08000 {
+       pci2: pcie@fffe08000 {
                reg = <0xf 0xffe08000 0 0x1000>;
                status = "disabled";
        };
@@ -76,7 +76,7 @@
                };
        };
 
-       pci2: pcie@fffe0a000 {
+       pci0: pcie@fffe0a000 {
                reg = <0xf 0xffe0a000 0 0x1000>;
                ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
                          0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
index 22a215e94162362be8525740d0836a14efca4cb9..6cdcadc80c3074db1a667a0a52f952e5ce7558c8 100644 (file)
@@ -58,7 +58,7 @@
                                #size-cells = <1>;
                                compatible = "spansion,s25sl12801";
                                reg = <0>;
-                               spi-max-frequency = <40000000>; /* input clock */
+                               spi-max-frequency = <35000000>; /* input clock */
                                partition@u-boot {
                                        label = "u-boot";
                                        reg = <0x00000000 0x00100000>;
index 62678e365ca0768e0566329eb957f0058a04897d..78160874809a1e1e5faf8b049baec80a7bd24545 100644 (file)
@@ -27,7 +27,10 @@ extern void *dma_direct_alloc_coherent(struct device *dev, size_t size,
 extern void dma_direct_free_coherent(struct device *dev, size_t size,
                                     void *vaddr, dma_addr_t dma_handle,
                                     struct dma_attrs *attrs);
-
+extern int dma_direct_mmap_coherent(struct device *dev,
+                                   struct vm_area_struct *vma,
+                                   void *cpu_addr, dma_addr_t handle,
+                                   size_t size, struct dma_attrs *attrs);
 
 #ifdef CONFIG_NOT_COHERENT_CACHE
 /*
@@ -207,11 +210,8 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 
-extern int dma_mmap_coherent(struct device *, struct vm_area_struct *,
-                            void *, dma_addr_t, size_t);
 #define ARCH_HAS_DMA_MMAP_COHERENT
 
-
 static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
                enum dma_data_direction direction)
 {
index d3d1b5efd7eb1204405fde26c701e7c52b925fd9..bd377a368611913b55e2ef272da6772540f39215 100644 (file)
 #include <linux/compiler.h>
 #include <linux/linkage.h>
 
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
index bcfdcd22c766f43ebb29dbe495641892215b1cda..2d7bb8ced136c1e618d1e25229553a70512dc927 100644 (file)
@@ -109,6 +109,7 @@ static u64 dma_iommu_get_required_mask(struct device *dev)
 struct dma_map_ops dma_iommu_ops = {
        .alloc                  = dma_iommu_alloc_coherent,
        .free                   = dma_iommu_free_coherent,
+       .mmap                   = dma_direct_mmap_coherent,
        .map_sg                 = dma_iommu_map_sg,
        .unmap_sg               = dma_iommu_unmap_sg,
        .dma_supported          = dma_iommu_dma_supported,
index 4ab88dafb235c8b29955bf1a70a3e04aa255db5a..46943651da23ba25b3e1093ea346fb31e154243c 100644 (file)
@@ -49,6 +49,7 @@ static u64 swiotlb_powerpc_get_required(struct device *dev)
 struct dma_map_ops swiotlb_dma_ops = {
        .alloc = dma_direct_alloc_coherent,
        .free = dma_direct_free_coherent,
+       .mmap = dma_direct_mmap_coherent,
        .map_sg = swiotlb_map_sg_attrs,
        .unmap_sg = swiotlb_unmap_sg_attrs,
        .dma_supported = swiotlb_dma_supported,
index 289be751cd756b71220d90fb7d3820824976bd83..355b9d84b0f8149efd45ed9b5b0035c3b70fac11 100644 (file)
@@ -67,6 +67,24 @@ void dma_direct_free_coherent(struct device *dev, size_t size,
 #endif
 }
 
+int dma_direct_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+                            void *cpu_addr, dma_addr_t handle, size_t size,
+                            struct dma_attrs *attrs)
+{
+       unsigned long pfn;
+
+#ifdef CONFIG_NOT_COHERENT_CACHE
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       pfn = __dma_get_coherent_pfn((unsigned long)cpu_addr);
+#else
+       pfn = page_to_pfn(virt_to_page(cpu_addr));
+#endif
+       return remap_pfn_range(vma, vma->vm_start,
+                              pfn + vma->vm_pgoff,
+                              vma->vm_end - vma->vm_start,
+                              vma->vm_page_prot);
+}
+
 static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
                             int nents, enum dma_data_direction direction,
                             struct dma_attrs *attrs)
@@ -156,6 +174,7 @@ static inline void dma_direct_sync_single(struct device *dev,
 struct dma_map_ops dma_direct_ops = {
        .alloc                          = dma_direct_alloc_coherent,
        .free                           = dma_direct_free_coherent,
+       .mmap                           = dma_direct_mmap_coherent,
        .map_sg                         = dma_direct_map_sg,
        .unmap_sg                       = dma_direct_unmap_sg,
        .dma_supported                  = dma_direct_dma_supported,
@@ -219,20 +238,3 @@ static int __init dma_init(void)
 }
 fs_initcall(dma_init);
 
-int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
-                     void *cpu_addr, dma_addr_t handle, size_t size)
-{
-       unsigned long pfn;
-
-#ifdef CONFIG_NOT_COHERENT_CACHE
-       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-       pfn = __dma_get_coherent_pfn((unsigned long)cpu_addr);
-#else
-       pfn = page_to_pfn(virt_to_page(cpu_addr));
-#endif
-       return remap_pfn_range(vma, vma->vm_start,
-                              pfn + vma->vm_pgoff,
-                              vma->vm_end - vma->vm_start,
-                              vma->vm_page_prot);
-}
-EXPORT_SYMBOL_GPL(dma_mmap_coherent);
index 3052a931f2b5caca2d32f200a3c844823a73f3b9..02b32216bbc3bb28de3a22b307f6f19aab2cd0a9 100644 (file)
@@ -611,6 +611,7 @@ static u64 vio_dma_get_required_mask(struct device *dev)
 struct dma_map_ops vio_dma_mapping_ops = {
        .alloc             = vio_dma_iommu_alloc_coherent,
        .free              = vio_dma_iommu_free_coherent,
+       .mmap              = dma_direct_mmap_coherent,
        .map_sg            = vio_dma_iommu_map_sg,
        .unmap_sg          = vio_dma_iommu_unmap_sg,
        .map_page          = vio_dma_iommu_map_page,
index ab523f3c1731a0ecf57e3fec538442875d1107ef..9ecf6e35cd8de0de4fe148a7527524a46256c900 100644 (file)
@@ -67,7 +67,6 @@ kvmppc_skip_Hinterrupt:
 #elif defined(CONFIG_PPC_BOOK3S_32)
 
 #define FUNC(name)             name
-#define MTMSR_EERI(reg)                mtmsr   (reg)
 
 .macro INTERRUPT_TRAMPOLINE intno
 
index 89ee02c54561d1802fd72a49afaedd88fc9e2368..3c732acf331dcda708bbc8cc08b28567f5596c44 100644 (file)
@@ -208,6 +208,7 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
        u8 __iomem *lbc_lcs0_ba = NULL;
        u8 __iomem *lbc_lcs1_ba = NULL;
        phys_addr_t cs0_addr, cs1_addr;
+       u32 br0, or0, br1, or1;
        const __be32 *iprop;
        unsigned int num_laws;
        u8 b;
@@ -256,11 +257,70 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
        }
        num_laws = be32_to_cpup(iprop);
 
-       cs0_addr = lbc_br_to_phys(ecm, num_laws, in_be32(&lbc->bank[0].br));
-       cs1_addr = lbc_br_to_phys(ecm, num_laws, in_be32(&lbc->bank[1].br));
+       /*
+        * Indirect mode requires both BR0 and BR1 to be set to "GPCM",
+        * otherwise writes to these addresses won't actually appear on the
+        * local bus, and so the PIXIS won't see them.
+        *
+        * In FCM mode, writes go to the NAND controller, which does not pass
+        * them to the localbus directly.  So we force BR0 and BR1 into GPCM
+        * mode, since we don't care about what's behind the localbus any
+        * more.
+        */
+       br0 = in_be32(&lbc->bank[0].br);
+       br1 = in_be32(&lbc->bank[1].br);
+       or0 = in_be32(&lbc->bank[0].or);
+       or1 = in_be32(&lbc->bank[1].or);
+
+       /* Make sure CS0 and CS1 are programmed */
+       if (!(br0 & BR_V) || !(br1 & BR_V)) {
+               pr_err("p1022ds: CS0 and/or CS1 is not programmed\n");
+               goto exit;
+       }
+
+       /*
+        * Use the existing BRx/ORx values if it's already GPCM. Otherwise,
+        * force the values to simple 32KB GPCM windows with the most
+        * conservative timing.
+        */
+       if ((br0 & BR_MSEL) != BR_MS_GPCM) {
+               br0 = (br0 & BR_BA) | BR_V;
+               or0 = 0xFFFF8000 | 0xFF7;
+               out_be32(&lbc->bank[0].br, br0);
+               out_be32(&lbc->bank[0].or, or0);
+       }
+       if ((br1 & BR_MSEL) != BR_MS_GPCM) {
+               br1 = (br1 & BR_BA) | BR_V;
+               or1 = 0xFFFF8000 | 0xFF7;
+               out_be32(&lbc->bank[1].br, br1);
+               out_be32(&lbc->bank[1].or, or1);
+       }
+
+       cs0_addr = lbc_br_to_phys(ecm, num_laws, br0);
+       if (!cs0_addr) {
+               pr_err("p1022ds: could not determine physical address for CS0"
+                      " (BR0=%08x)\n", br0);
+               goto exit;
+       }
+       cs1_addr = lbc_br_to_phys(ecm, num_laws, br1);
+       if (!cs0_addr) {
+               pr_err("p1022ds: could not determine physical address for CS1"
+                      " (BR1=%08x)\n", br1);
+               goto exit;
+       }
 
        lbc_lcs0_ba = ioremap(cs0_addr, 1);
+       if (!lbc_lcs0_ba) {
+               pr_err("p1022ds: could not ioremap CS0 address %llx\n",
+                      (unsigned long long)cs0_addr);
+               goto exit;
+       }
        lbc_lcs1_ba = ioremap(cs1_addr, 1);
+       if (!lbc_lcs1_ba) {
+               pr_err("p1022ds: could not ioremap CS1 address %llx\n",
+                      (unsigned long long)cs1_addr);
+               goto exit;
+       }
 
        /* Make sure we're in indirect mode first. */
        if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
@@ -419,18 +479,6 @@ void __init p1022_ds_pic_init(void)
 
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
 
-/*
- * Disables a node in the device tree.
- *
- * This function is called before kmalloc() is available, so the 'new' object
- * should be allocated in the global area.  The easiest way is to do that is
- * to allocate one static local variable for each call to this function.
- */
-static void __init disable_one_node(struct device_node *np, struct property *new)
-{
-       prom_update_property(np, new);
-}
-
 /* TRUE if there is a "video=fslfb" command-line parameter. */
 static bool fslfb;
 
@@ -493,28 +541,58 @@ static void __init p1022_ds_setup_arch(void)
        diu_ops.valid_monitor_port      = p1022ds_valid_monitor_port;
 
        /*
-        * Disable the NOR flash node if there is video=fslfb... command-line
-        * parameter.  When the DIU is active, NOR flash is unavailable, so we
-        * have to disable the node before the MTD driver loads.
+        * Disable the NOR and NAND flash nodes if there is video=fslfb...
+        * command-line parameter.  When the DIU is active, the localbus is
+        * unavailable, so we have to disable these nodes before the MTD
+        * driver loads.
         */
        if (fslfb) {
                struct device_node *np =
                        of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc");
 
                if (np) {
-                       np = of_find_compatible_node(np, NULL, "cfi-flash");
-                       if (np) {
+                       struct device_node *np2;
+
+                       of_node_get(np);
+                       np2 = of_find_compatible_node(np, NULL, "cfi-flash");
+                       if (np2) {
                                static struct property nor_status = {
                                        .name = "status",
                                        .value = "disabled",
                                        .length = sizeof("disabled"),
                                };
 
+                               /*
+                                * prom_update_property() is called before
+                                * kmalloc() is available, so the 'new' object
+                                * should be allocated in the global area.
+                                * The easiest way is to do that is to
+                                * allocate one static local variable for each
+                                * call to this function.
+                                */
                                pr_info("p1022ds: disabling %s node",
-                                       np->full_name);
-                               disable_one_node(np, &nor_status);
-                               of_node_put(np);
+                                       np2->full_name);
+                               prom_update_property(np2, &nor_status);
+                               of_node_put(np2);
                        }
+
+                       of_node_get(np);
+                       np2 = of_find_compatible_node(np, NULL,
+                                                     "fsl,elbc-fcm-nand");
+                       if (np2) {
+                               static struct property nand_status = {
+                                       .name = "status",
+                                       .value = "disabled",
+                                       .length = sizeof("disabled"),
+                               };
+
+                               pr_info("p1022ds: disabling %s node",
+                                       np2->full_name);
+                               prom_update_property(np2, &nand_status);
+                               of_node_put(np2);
+                       }
+
+                       of_node_put(np);
                }
 
        }
index 60c9c0bd5ba229807badcda45a936b02fc94de53..2aa97ddb7b78841d5ef26bfac393fd9f4c3d01b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009-2010 Freescale Semiconductor, Inc
+ * Copyright 2009-2010, 2012 Freescale Semiconductor, Inc
  *
  * QorIQ based Cache Controller Memory Mapped Registers
  *
@@ -91,7 +91,7 @@ struct mpc85xx_l2ctlr {
 
 struct sram_parameters {
        unsigned int sram_size;
-       uint64_t sram_offset;
+       phys_addr_t sram_offset;
 };
 
 extern int instantiate_cache_sram(struct platform_device *dev,
index cedabd0f4bfe81e362b8bd0bbc7d5238545dc3d7..68ac3aacb1919477ed4686f859979d9bc17c7b15 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ * Copyright 2009-2010, 2012 Freescale Semiconductor, Inc.
  *
  * QorIQ (P1/P2) L2 controller init for Cache-SRAM instantiation
  *
@@ -31,24 +31,21 @@ static char *sram_size;
 static char *sram_offset;
 struct mpc85xx_l2ctlr __iomem *l2ctlr;
 
-static long get_cache_sram_size(void)
+static int get_cache_sram_params(struct sram_parameters *sram_params)
 {
-       unsigned long val;
+       unsigned long long addr;
+       unsigned int size;
 
-       if (!sram_size || (strict_strtoul(sram_size, 0, &val) < 0))
+       if (!sram_size || (kstrtouint(sram_size, 0, &size) < 0))
                return -EINVAL;
 
-       return val;
-}
-
-static long get_cache_sram_offset(void)
-{
-       unsigned long val;
-
-       if (!sram_offset || (strict_strtoul(sram_offset, 0, &val) < 0))
+       if (!sram_offset || (kstrtoull(sram_offset, 0, &addr) < 0))
                return -EINVAL;
 
-       return val;
+       sram_params->sram_offset = addr;
+       sram_params->sram_size = size;
+
+       return 0;
 }
 
 static int __init get_size_from_cmdline(char *str)
@@ -93,17 +90,9 @@ static int __devinit mpc85xx_l2ctlr_of_probe(struct platform_device *dev)
        }
        l2cache_size = *prop;
 
-       sram_params.sram_size  = get_cache_sram_size();
-       if ((int)sram_params.sram_size <= 0) {
-               dev_err(&dev->dev,
-                       "Entire L2 as cache, Aborting Cache-SRAM stuff\n");
-               return -EINVAL;
-       }
-
-       sram_params.sram_offset  = get_cache_sram_offset();
-       if ((int64_t)sram_params.sram_offset <= 0) {
+       if (get_cache_sram_params(&sram_params)) {
                dev_err(&dev->dev,
-                       "Entire L2 as cache, provide a valid sram offset\n");
+                       "Entire L2 as cache, provide valid sram offset and size\n");
                return -EINVAL;
        }
 
@@ -125,14 +114,14 @@ static int __devinit mpc85xx_l2ctlr_of_probe(struct platform_device *dev)
         * Write bits[0-17] to srbar0
         */
        out_be32(&l2ctlr->srbar0,
-               sram_params.sram_offset & L2SRAM_BAR_MSK_LO18);
+               lower_32_bits(sram_params.sram_offset) & L2SRAM_BAR_MSK_LO18);
 
        /*
         * Write bits[18-21] to srbare0
         */
 #ifdef CONFIG_PHYS_64BIT
        out_be32(&l2ctlr->srbarea0,
-               (sram_params.sram_offset >> 32) & L2SRAM_BARE_MSK_HI4);
+               upper_32_bits(sram_params.sram_offset) & L2SRAM_BARE_MSK_HI4);
 #endif
 
        clrsetbits_be32(&l2ctlr->ctl, L2CR_L2E, L2CR_L2FI);
index a39b4690c171621e78e2183c6b1b97bd25f4afaf..76de6b68487c8a44aa4eabecc1dddc7d916546e2 100644 (file)
@@ -85,10 +85,12 @@ config S390
        select HAVE_ARCH_MUTEX_CPU_RELAX
        select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
        select ARCH_SAVE_PAGE_KEYS if HIBERNATION
+       select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select HAVE_MEMBLOCK
        select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_CMPXCHG_LOCAL
        select ARCH_DISCARD_MEMBLOCK
+       select BUILDTIME_EXTABLE_SORT
        select ARCH_INLINE_SPIN_TRYLOCK
        select ARCH_INLINE_SPIN_TRYLOCK_BH
        select ARCH_INLINE_SPIN_LOCK
@@ -117,6 +119,7 @@ config S390
        select ARCH_INLINE_WRITE_UNLOCK_BH
        select ARCH_INLINE_WRITE_UNLOCK_IRQ
        select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
+       select ARCH_WANT_IPC_PARSE_VERSION
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_TIME_VSYSCALL
        select GENERIC_CLOCKEVENTS
index 37d2bf267964a5103f1b1ae189db2e9f6fd1de91..967923dea98de1574458312619c8883b89b09ae7 100644 (file)
@@ -7,6 +7,9 @@ CONFIG_TASK_DELAY_ACCT=y
 CONFIG_TASK_XACCT=y
 CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_CGROUPS=y
@@ -35,8 +38,6 @@ CONFIG_MODVERSIONS=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_IBM_PARTITION=y
 CONFIG_DEFAULT_DEADLINE=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT=y
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
index 5c63615f1349f862762ced5e20147acae7f2c5ec..b749c573365767af8487c4c24c07b8cbc8ace903 100644 (file)
@@ -11,7 +11,6 @@
 #include <asm/uaccess.h>
 #include <asm/tlbflush.h>
 #include <asm/ctl_reg.h>
-#include <asm-generic/mm_hooks.h>
 
 static inline int init_new_context(struct task_struct *tsk,
                                   struct mm_struct *mm)
@@ -58,7 +57,7 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
        pgd_t *pgd = mm->pgd;
 
        S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd);
-       if (user_mode != HOME_SPACE_MODE) {
+       if (addressing_mode != HOME_SPACE_MODE) {
                /* Load primary space page table origin. */
                asm volatile(LCTL_OPCODE" 1,1,%0\n"
                             : : "m" (S390_lowcore.user_asce) );
@@ -91,4 +90,17 @@ static inline void activate_mm(struct mm_struct *prev,
         switch_mm(prev, next, current);
 }
 
+static inline void arch_dup_mmap(struct mm_struct *oldmm,
+                                struct mm_struct *mm)
+{
+#ifdef CONFIG_64BIT
+       if (oldmm->context.asce_limit < mm->context.asce_limit)
+               crst_table_downgrade(mm, oldmm->context.asce_limit);
+#endif
+}
+
+static inline void arch_exit_mmap(struct mm_struct *mm)
+{
+}
+
 #endif /* __S390_MMU_CONTEXT_H */
index c40fa91e38a8da85fcad46d66435701f98076758..11e4e3236937e106aba159b83e7cc6ae6167c7b0 100644 (file)
@@ -120,7 +120,9 @@ struct stack_frame {
        regs->psw.mask  = psw_user_bits | PSW_MASK_BA;                  \
        regs->psw.addr  = new_psw | PSW_ADDR_AMODE;                     \
        regs->gprs[15]  = new_stackp;                                   \
+       __tlb_flush_mm(current->mm);                                    \
        crst_table_downgrade(current->mm, 1UL << 31);                   \
+       update_mm(current->mm, current);                                \
 } while (0)
 
 /* Forward declaration, a strange C thing */
index 57e80534375a603f2f839893bfa6ebc2b79e5845..e6859d16ee2dbb49f87ca15cf5b8a720153df2b6 100644 (file)
@@ -60,7 +60,7 @@ void create_mem_hole(struct mem_chunk memory_chunk[], unsigned long addr,
 #define SECONDARY_SPACE_MODE   2
 #define HOME_SPACE_MODE                3
 
-extern unsigned int user_mode;
+extern unsigned int addressing_mode;
 
 /*
  * Machine features detected in head.S
index 2e37157ba6a92cf48dd6360b994db0803f791624..6756e78f48082f1644f7a0d73cdeecaa5d193da5 100644 (file)
 #define __IGNORE_recvmmsg
 #define __IGNORE_sendmmsg
 
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
index 21be961e8a43e643daa31a26680c91edf2a5ee66..ba500d8dc392056ddd66e4978389d072452f6859 100644 (file)
@@ -110,6 +110,7 @@ struct debug_view debug_raw_view = {
        NULL,
        NULL
 };
+EXPORT_SYMBOL(debug_raw_view);
 
 struct debug_view debug_hex_ascii_view = {
        "hex_ascii",
@@ -119,6 +120,7 @@ struct debug_view debug_hex_ascii_view = {
        NULL,
        NULL
 };
+EXPORT_SYMBOL(debug_hex_ascii_view);
 
 static struct debug_view debug_level_view = {
        "level",
@@ -155,6 +157,7 @@ struct debug_view debug_sprintf_view = {
        NULL,
        NULL
 };
+EXPORT_SYMBOL(debug_sprintf_view);
 
 /* used by dump analysis tools to determine version of debug feature */
 static unsigned int __used debug_feature_version = __DEBUG_FEATURE_VERSION;
@@ -730,6 +733,7 @@ debug_info_t *debug_register(const char *name, int pages_per_area,
        return debug_register_mode(name, pages_per_area, nr_areas, buf_size,
                                   S_IRUSR | S_IWUSR, 0, 0);
 }
+EXPORT_SYMBOL(debug_register);
 
 /*
  * debug_unregister:
@@ -748,6 +752,7 @@ debug_unregister(debug_info_t * id)
 out:
        return;
 }
+EXPORT_SYMBOL(debug_unregister);
 
 /*
  * debug_set_size:
@@ -810,7 +815,7 @@ debug_set_level(debug_info_t* id, int new_level)
         }
        spin_unlock_irqrestore(&id->lock,flags);
 }
-
+EXPORT_SYMBOL(debug_set_level);
 
 /*
  * proceed_active_entry:
@@ -930,7 +935,7 @@ debug_stop_all(void)
        if (debug_stoppable)
                debug_active = 0;
 }
-
+EXPORT_SYMBOL(debug_stop_all);
 
 void debug_set_critical(void)
 {
@@ -963,6 +968,7 @@ debug_event_common(debug_info_t * id, int level, const void *buf, int len)
 
        return active;
 }
+EXPORT_SYMBOL(debug_event_common);
 
 /*
  * debug_exception_common:
@@ -990,6 +996,7 @@ debug_entry_t
 
        return active;
 }
+EXPORT_SYMBOL(debug_exception_common);
 
 /*
  * counts arguments in format string for sprintf view
@@ -1043,6 +1050,7 @@ debug_sprintf_event(debug_info_t* id, int level,char *string,...)
 
        return active;
 }
+EXPORT_SYMBOL(debug_sprintf_event);
 
 /*
  * debug_sprintf_exception:
@@ -1081,25 +1089,7 @@ debug_sprintf_exception(debug_info_t* id, int level,char *string,...)
 
        return active;
 }
-
-/*
- * debug_init:
- * - is called exactly once to initialize the debug feature
- */
-
-static int
-__init debug_init(void)
-{
-       int rc = 0;
-
-       s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table);
-       mutex_lock(&debug_mutex);
-       debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT,NULL);
-       initialized = 1;
-       mutex_unlock(&debug_mutex);
-
-       return rc;
-}
+EXPORT_SYMBOL(debug_sprintf_exception);
 
 /*
  * debug_register_view:
@@ -1147,6 +1137,7 @@ debug_register_view(debug_info_t * id, struct debug_view *view)
 out:
        return rc;
 }
+EXPORT_SYMBOL(debug_register_view);
 
 /*
  * debug_unregister_view:
@@ -1176,6 +1167,7 @@ debug_unregister_view(debug_info_t * id, struct debug_view *view)
 out:
        return rc;
 }
+EXPORT_SYMBOL(debug_unregister_view);
 
 static inline char *
 debug_get_user_string(const char __user *user_buf, size_t user_len)
@@ -1485,6 +1477,7 @@ debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
                      except_str, entry->id.fields.cpuid, (void *) caller);
        return rc;
 }
+EXPORT_SYMBOL(debug_dflt_header_fn);
 
 /*
  * prints debug data sprintf-formated:
@@ -1533,33 +1526,16 @@ out:
 }
 
 /*
- * clean up module
+ * debug_init:
+ * - is called exactly once to initialize the debug feature
  */
-static void __exit debug_exit(void)
+static int __init debug_init(void)
 {
-       debugfs_remove(debug_debugfs_root_entry);
-       unregister_sysctl_table(s390dbf_sysctl_header);
-       return;
+       s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table);
+       mutex_lock(&debug_mutex);
+       debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT, NULL);
+       initialized = 1;
+       mutex_unlock(&debug_mutex);
+       return 0;
 }
-
-/*
- * module definitions
- */
 postcore_initcall(debug_init);
-module_exit(debug_exit);
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(debug_register);
-EXPORT_SYMBOL(debug_unregister); 
-EXPORT_SYMBOL(debug_set_level);
-EXPORT_SYMBOL(debug_stop_all);
-EXPORT_SYMBOL(debug_register_view);
-EXPORT_SYMBOL(debug_unregister_view);
-EXPORT_SYMBOL(debug_event_common);
-EXPORT_SYMBOL(debug_exception_common);
-EXPORT_SYMBOL(debug_hex_ascii_view);
-EXPORT_SYMBOL(debug_raw_view);
-EXPORT_SYMBOL(debug_dflt_header_fn);
-EXPORT_SYMBOL(debug_sprintf_view);
-EXPORT_SYMBOL(debug_sprintf_exception);
-EXPORT_SYMBOL(debug_sprintf_event);
index 1f6b428e276239d94927086f6d5b2ccc668fbe2b..619c5d3507264ca1f7417563a9152b55270374a2 100644 (file)
@@ -1531,7 +1531,7 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
 
 void show_code(struct pt_regs *regs)
 {
-       char *mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
+       char *mode = user_mode(regs) ? "User" : "Krnl";
        unsigned char code[64];
        char buffer[64], *ptr;
        mm_segment_t old_fs;
@@ -1540,7 +1540,7 @@ void show_code(struct pt_regs *regs)
 
        /* Get a snapshot of the 64 bytes surrounding the fault address. */
        old_fs = get_fs();
-       set_fs((regs->psw.mask & PSW_MASK_PSTATE) ? USER_DS : KERNEL_DS);
+       set_fs(user_mode(regs) ? USER_DS : KERNEL_DS);
        for (start = 32; start && regs->psw.addr >= 34 - start; start -= 2) {
                addr = regs->psw.addr - 34 + start;
                if (__copy_from_user(code + start - 2,
index bc95a8ebd9cc3810a0bfb83d34f10cca512d1d92..83c3271c442b75d5d005e1e6130f538deea968a7 100644 (file)
@@ -455,7 +455,6 @@ void __init startup_init(void)
        init_kernel_storage_key();
        lockdep_init();
        lockdep_off();
-       sort_main_extable();
        setup_lowcore_early();
        setup_facility_list();
        detect_machine_type();
index e64d141555ce99843f4995827f4644e1dc127c79..6ffcd3203215a2bcacb50bc35ae12229113b0ff4 100644 (file)
@@ -1583,7 +1583,7 @@ static struct kset *vmcmd_kset;
 
 static void vmcmd_run(struct shutdown_trigger *trigger)
 {
-       char *cmd, *next_cmd;
+       char *cmd;
 
        if (strcmp(trigger->name, ON_REIPL_STR) == 0)
                cmd = vmcmd_on_reboot;
@@ -1600,15 +1600,7 @@ static void vmcmd_run(struct shutdown_trigger *trigger)
 
        if (strlen(cmd) == 0)
                return;
-       do {
-               next_cmd = strchr(cmd, '\n');
-               if (next_cmd) {
-                       next_cmd[0] = 0;
-                       next_cmd += 1;
-               }
-               __cpcmd(cmd, NULL, 0, NULL);
-               cmd = next_cmd;
-       } while (cmd != NULL);
+       __cpcmd(cmd, NULL, 0, NULL);
 }
 
 static int vmcmd_init(void)
index 743c0f32fe3beb0c508a02e81bf775f075242d08..f86c81e13c374be484f591faead417a7fb3ee572 100644 (file)
@@ -302,8 +302,8 @@ static int __init parse_vmalloc(char *arg)
 }
 early_param("vmalloc", parse_vmalloc);
 
-unsigned int user_mode = HOME_SPACE_MODE;
-EXPORT_SYMBOL_GPL(user_mode);
+unsigned int addressing_mode = HOME_SPACE_MODE;
+EXPORT_SYMBOL_GPL(addressing_mode);
 
 static int set_amode_primary(void)
 {
@@ -328,7 +328,7 @@ static int set_amode_primary(void)
  */
 static int __init early_parse_switch_amode(char *p)
 {
-       user_mode = PRIMARY_SPACE_MODE;
+       addressing_mode = PRIMARY_SPACE_MODE;
        return 0;
 }
 early_param("switch_amode", early_parse_switch_amode);
@@ -336,9 +336,9 @@ early_param("switch_amode", early_parse_switch_amode);
 static int __init early_parse_user_mode(char *p)
 {
        if (p && strcmp(p, "primary") == 0)
-               user_mode = PRIMARY_SPACE_MODE;
+               addressing_mode = PRIMARY_SPACE_MODE;
        else if (!p || strcmp(p, "home") == 0)
-               user_mode = HOME_SPACE_MODE;
+               addressing_mode = HOME_SPACE_MODE;
        else
                return 1;
        return 0;
@@ -347,7 +347,7 @@ early_param("user_mode", early_parse_user_mode);
 
 static void setup_addressing_mode(void)
 {
-       if (user_mode == PRIMARY_SPACE_MODE) {
+       if (addressing_mode == PRIMARY_SPACE_MODE) {
                if (set_amode_primary())
                        pr_info("Address spaces switched, "
                                "mvcos available\n");
index af2421a0f3156e9c8a965ee34d95322de55602be..01775c04a90e63a2bbebc2eb5d3ebf0363abafe2 100644 (file)
@@ -185,7 +185,7 @@ void show_registers(struct pt_regs *regs)
 {
        char *mode;
 
-       mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
+       mode = user_mode(regs) ? "User" : "Krnl";
        printk("%s PSW : %p %p",
               mode, (void *) regs->psw.mask,
               (void *) regs->psw.addr);
@@ -225,7 +225,7 @@ void show_regs(struct pt_regs *regs)
               (void *) current->thread.ksp);
        show_registers(regs);
        /* Show stack backtrace if pt_regs is from kernel mode */
-       if (!(regs->psw.mask & PSW_MASK_PSTATE))
+       if (!user_mode(regs))
                show_trace(NULL, (unsigned long *) regs->gprs[15]);
        show_last_breaking_event(regs);
 }
@@ -300,7 +300,7 @@ static void __kprobes do_trap(struct pt_regs *regs,
                       regs->int_code, si_signo) == NOTIFY_STOP)
                return;
 
-        if (regs->psw.mask & PSW_MASK_PSTATE) {
+       if (user_mode(regs)) {
                info.si_signo = si_signo;
                info.si_errno = 0;
                info.si_code = si_code;
@@ -341,7 +341,7 @@ void __kprobes do_per_trap(struct pt_regs *regs)
 
 static void default_trap_handler(struct pt_regs *regs)
 {
-        if (regs->psw.mask & PSW_MASK_PSTATE) {
+       if (user_mode(regs)) {
                report_user_fault(regs, SIGSEGV);
                do_exit(SIGSEGV);
        } else
@@ -410,7 +410,7 @@ static void __kprobes illegal_op(struct pt_regs *regs)
 
        location = get_psw_address(regs);
 
-       if (regs->psw.mask & PSW_MASK_PSTATE) {
+       if (user_mode(regs)) {
                if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
                        return;
                if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
@@ -478,7 +478,7 @@ void specification_exception(struct pt_regs *regs)
 
        location = (__u16 __user *) get_psw_address(regs);
 
-        if (regs->psw.mask & PSW_MASK_PSTATE) {
+       if (user_mode(regs)) {
                get_user(*((__u16 *) opcode), location);
                switch (opcode[0]) {
                case 0x28: /* LDR Rx,Ry   */
@@ -531,7 +531,7 @@ static void data_exception(struct pt_regs *regs)
                asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
 
 #ifdef CONFIG_MATHEMU
-        else if (regs->psw.mask & PSW_MASK_PSTATE) {
+       else if (user_mode(regs)) {
                __u8 opcode[6];
                get_user(*((__u16 *) opcode), location);
                switch (opcode[0]) {
@@ -598,7 +598,7 @@ static void data_exception(struct pt_regs *regs)
 static void space_switch_exception(struct pt_regs *regs)
 {
        /* Set user psw back to home space mode. */
-       if (regs->psw.mask & PSW_MASK_PSTATE)
+       if (user_mode(regs))
                regs->psw.mask |= PSW_ASC_HOME;
        /* Send SIGILL. */
        do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
index ea5590fdca3bb8266caa0e25410dd744b103b4c9..9a19ca367c17bc41e1f8e781ed173a93bba5da12 100644 (file)
@@ -84,7 +84,8 @@ struct vdso_data *vdso_data = &vdso_data_store.data;
  */
 static void vdso_init_data(struct vdso_data *vd)
 {
-       vd->ectg_available = user_mode != HOME_SPACE_MODE && test_facility(31);
+       vd->ectg_available =
+               addressing_mode != HOME_SPACE_MODE && test_facility(31);
 }
 
 #ifdef CONFIG_64BIT
@@ -101,7 +102,7 @@ int vdso_alloc_per_cpu(struct _lowcore *lowcore)
 
        lowcore->vdso_per_cpu_data = __LC_PASTE;
 
-       if (user_mode == HOME_SPACE_MODE || !vdso_enabled)
+       if (addressing_mode == HOME_SPACE_MODE || !vdso_enabled)
                return 0;
 
        segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER);
@@ -146,7 +147,7 @@ void vdso_free_per_cpu(struct _lowcore *lowcore)
        unsigned long segment_table, page_table, page_frame;
        u32 *psal, *aste;
 
-       if (user_mode == HOME_SPACE_MODE || !vdso_enabled)
+       if (addressing_mode == HOME_SPACE_MODE || !vdso_enabled)
                return;
 
        psal = (u32 *)(addr_t) lowcore->paste[4];
@@ -164,7 +165,7 @@ static void vdso_init_cr5(void)
 {
        unsigned long cr5;
 
-       if (user_mode == HOME_SPACE_MODE || !vdso_enabled)
+       if (addressing_mode == HOME_SPACE_MODE || !vdso_enabled)
                return;
        cr5 = offsetof(struct _lowcore, paste);
        __ctl_load(cr5, 5, 5);
index 21109c63eb12961483134141c67bfc8c2b8f8315..de8fa9bbd35ee9787537e93c18b561b75cacf72f 100644 (file)
@@ -45,7 +45,7 @@ SECTIONS
 
        .dummy : { *(.dummy) } :data
 
-       RODATA
+       RO_DATA_SECTION(PAGE_SIZE)
 
 #ifdef CONFIG_SHARED_KERNEL
        . = ALIGN(0x100000);    /* VM shared segments are 1MB aligned */
index 6a12d1bb6e09d065e5a4b2625ce79ba7209b5c2b..6c013f544146d8bf92d6143378c8f1fbf5631b02 100644 (file)
@@ -49,6 +49,7 @@
 #define VM_FAULT_BADCONTEXT    0x010000
 #define VM_FAULT_BADMAP                0x020000
 #define VM_FAULT_BADACCESS     0x040000
+#define VM_FAULT_SIGNAL        0x080000
 
 static unsigned long store_indication;
 
@@ -110,7 +111,7 @@ static inline int user_space_fault(unsigned long trans_exc_code)
        if (trans_exc_code == 2)
                /* Access via secondary space, set_fs setting decides */
                return current->thread.mm_segment.ar4;
-       if (user_mode == HOME_SPACE_MODE)
+       if (addressing_mode == HOME_SPACE_MODE)
                /* User space if the access has been done via home space. */
                return trans_exc_code == 3;
        /*
@@ -219,7 +220,7 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault)
        case VM_FAULT_BADACCESS:
        case VM_FAULT_BADMAP:
                /* Bad memory access. Check if it is kernel or user space. */
-               if (regs->psw.mask & PSW_MASK_PSTATE) {
+               if (user_mode(regs)) {
                        /* User mode accesses just cause a SIGSEGV */
                        si_code = (fault == VM_FAULT_BADMAP) ?
                                SEGV_MAPERR : SEGV_ACCERR;
@@ -229,15 +230,19 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault)
        case VM_FAULT_BADCONTEXT:
                do_no_context(regs);
                break;
+       case VM_FAULT_SIGNAL:
+               if (!user_mode(regs))
+                       do_no_context(regs);
+               break;
        default: /* fault & VM_FAULT_ERROR */
                if (fault & VM_FAULT_OOM) {
-                       if (!(regs->psw.mask & PSW_MASK_PSTATE))
+                       if (!user_mode(regs))
                                do_no_context(regs);
                        else
                                pagefault_out_of_memory();
                } else if (fault & VM_FAULT_SIGBUS) {
                        /* Kernel mode? Handle exceptions or die */
-                       if (!(regs->psw.mask & PSW_MASK_PSTATE))
+                       if (!user_mode(regs))
                                do_no_context(regs);
                        else
                                do_sigbus(regs);
@@ -286,7 +291,7 @@ static inline int do_exception(struct pt_regs *regs, int access)
 
        address = trans_exc_code & __FAIL_ADDR_MASK;
        perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
-       flags = FAULT_FLAG_ALLOW_RETRY;
+       flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
        if (access == VM_WRITE || (trans_exc_code & store_indication) == 0x400)
                flags |= FAULT_FLAG_WRITE;
        down_read(&mm->mmap_sem);
@@ -335,6 +340,11 @@ retry:
         * the fault.
         */
        fault = handle_mm_fault(mm, vma, address, flags);
+       /* No reason to continue if interrupted by SIGKILL. */
+       if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
+               fault = VM_FAULT_SIGNAL;
+               goto out;
+       }
        if (unlikely(fault & VM_FAULT_ERROR))
                goto out_up;
 
@@ -426,7 +436,7 @@ void __kprobes do_asce_exception(struct pt_regs *regs)
        }
 
        /* User mode accesses just cause a SIGSEGV */
-       if (regs->psw.mask & PSW_MASK_PSTATE) {
+       if (user_mode(regs)) {
                do_sigsegv(regs, SEGV_MAPERR);
                return;
        }
@@ -441,6 +451,7 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
        struct pt_regs regs;
        int access, fault;
 
+       /* Emulate a uaccess fault from kernel mode. */
        regs.psw.mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK;
        if (!irqs_disabled())
                regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT;
@@ -450,12 +461,12 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
        regs.int_parm_long = (uaddr & PAGE_MASK) | 2;
        access = write ? VM_WRITE : VM_READ;
        fault = do_exception(&regs, access);
-       if (unlikely(fault)) {
-               if (fault & VM_FAULT_OOM)
-                       return -EFAULT;
-               else if (fault & VM_FAULT_SIGBUS)
-                       do_sigbus(&regs);
-       }
+       /*
+        * Since the fault happened in kernel mode while performing a uaccess
+        * all we need to do now is emulating a fixup in case "fault" is not
+        * zero.
+        * For the calling uaccess functions this results always in -EFAULT.
+        */
        return fault ? -EFAULT : 0;
 }
 
index 573384256c5c5ebd1aa65295e635e808345902d0..c59a5efa58b1ee701f93b4f980397e539265805a 100644 (file)
@@ -103,9 +103,15 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
 
 int s390_mmap_check(unsigned long addr, unsigned long len)
 {
+       int rc;
+
        if (!is_compat_task() &&
-           len >= TASK_SIZE && TASK_SIZE < (1UL << 53))
-               return crst_table_upgrade(current->mm, 1UL << 53);
+           len >= TASK_SIZE && TASK_SIZE < (1UL << 53)) {
+               rc = crst_table_upgrade(current->mm, 1UL << 53);
+               if (rc)
+                       return rc;
+               update_mm(current->mm, current);
+       }
        return 0;
 }
 
@@ -125,6 +131,7 @@ s390_get_unmapped_area(struct file *filp, unsigned long addr,
                rc = crst_table_upgrade(mm, 1UL << 53);
                if (rc)
                        return (unsigned long) rc;
+               update_mm(mm, current);
                area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
        }
        return area;
@@ -147,6 +154,7 @@ s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr,
                rc = crst_table_upgrade(mm, 1UL << 53);
                if (rc)
                        return (unsigned long) rc;
+               update_mm(mm, current);
                area = arch_get_unmapped_area_topdown(filp, addr, len,
                                                      pgoff, flags);
        }
index 1cab221077cc872b5f5e5528ff1918d8551fa9d2..18df31d1f2c9841cac3d97248a2806f9fb2d81a4 100644 (file)
@@ -85,7 +85,6 @@ repeat:
                crst_table_free(mm, table);
        if (mm->context.asce_limit < limit)
                goto repeat;
-       update_mm(mm, current);
        return 0;
 }
 
@@ -93,9 +92,6 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
 {
        pgd_t *pgd;
 
-       if (mm->context.asce_limit <= limit)
-               return;
-       __tlb_flush_mm(mm);
        while (mm->context.asce_limit > limit) {
                pgd = mm->pgd;
                switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) {
@@ -118,7 +114,6 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
                mm->task_size = mm->context.asce_limit;
                crst_table_free(mm, (unsigned long *) pgd);
        }
-       update_mm(mm, current);
 }
 #endif
 
@@ -801,7 +796,7 @@ int s390_enable_sie(void)
        struct mm_struct *mm, *old_mm;
 
        /* Do we have switched amode? If no, we cannot do sie */
-       if (user_mode == HOME_SPACE_MODE)
+       if (addressing_mode == HOME_SPACE_MODE)
                return -EINVAL;
 
        /* Do we have pgstes? if yes, we are done */
index c82f62fb9c28ef6096a486c6a3458725e91b31e3..8a6811b2cdb9523a24cd32341dee0fcef317f661 100644 (file)
@@ -58,7 +58,7 @@ void s390_backtrace(struct pt_regs * const regs, unsigned int depth)
        unsigned long head;
        struct stack_frame* head_sf;
 
-       if (user_mode (regs))
+       if (user_mode(regs))
                return;
 
        head = regs->gprs[15];
index a24595d83ad6c48c5685faed4d59ecb00d410c41..36f5141e80417ac6172ce6965602e4d15a67bdfb 100644 (file)
@@ -21,6 +21,7 @@ config SUPERH
        select HAVE_KERNEL_LZMA
        select HAVE_KERNEL_XZ
        select HAVE_KERNEL_LZO
+       select ARCH_WANT_IPC_PARSE_VERSION
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_GENERIC_HARDIRQS
@@ -50,6 +51,7 @@ config SUPERH32
        select HAVE_DYNAMIC_FTRACE
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
        select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
+       select ARCH_WANT_IPC_PARSE_VERSION
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_ARCH_KGDB
        select HAVE_HW_BREAKPOINT
index e800a38c9f8d86ec512ea3c5c557fa1c3707d6b1..7bc67076baac8771d929b0f5764954e9e2c787db 100644 (file)
@@ -6,7 +6,6 @@
 # endif
 
 # define __ARCH_WANT_SYS_RT_SIGSUSPEND
-# define __ARCH_WANT_IPC_PARSE_VERSION
 # define __ARCH_WANT_OLD_READDIR
 # define __ARCH_WANT_OLD_STAT
 # define __ARCH_WANT_STAT64
index e74ff137762661844783fe76a30986fe01308e9e..67f1f6f5f4e14fa35408cda35ad1464297dd2859 100644 (file)
@@ -27,6 +27,7 @@ config SPARC
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
+       select ARCH_WANT_IPC_PARSE_VERSION
        select USE_GENERIC_SMP_HELPERS if SMP
        select GENERIC_PCI_IOMAP
        select HAVE_NMI_WATCHDOG if SPARC64
index c7cb0af0eb59cb6dfb8a94e6c6fcdd330a7af29d..fb2693464807dd59020bd737cd115e6f5f45a410 100644 (file)
 #endif
 
 #ifdef __KERNEL__
-#define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
index c38e5aaae56f2def7f8255a3347be46247c354f9..0dc1f578608131002da0b869dcfa7c56b4b149e3 100644 (file)
@@ -470,7 +470,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
                switch (call) {
                case SHMAT: {
                        ulong raddr;
-                       err = do_shmat(first, ptr, (int)second, &raddr);
+                       err = do_shmat(first, ptr, (int)second, &raddr, SHMLBA);
                        if (!err) {
                                if (put_user(raddr,
                                             (ulong __user *) third))
index fb7c65ae8de055f03a3245db759e914697c2b3f6..5bd71994452d588d4790585f76a9cd5dfd35e185 100644 (file)
@@ -16,7 +16,6 @@ generic-y += fb.h
 generic-y += fcntl.h
 generic-y += ioctl.h
 generic-y += ioctls.h
-generic-y += ipc.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += kdebug.h
index c70684f859e13473908a1370a9a3bb160db5c4e3..ba2657c492171c5ce5c295d1e1d4ef85391608d8 100644 (file)
@@ -70,6 +70,7 @@ config X86
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_TEXT_POKE_SMP
        select HAVE_GENERIC_HARDIRQS
+       select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select SPARSE_IRQ
        select GENERIC_FIND_FIRST_BIT
        select GENERIC_IRQ_PROBE
@@ -84,6 +85,7 @@ config X86
        select GENERIC_IOMAP
        select DCACHE_WORD_ACCESS
        select GENERIC_SMP_IDLE_THREAD
+       select ARCH_WANT_IPC_PARSE_VERSION if X86_32
        select HAVE_ARCH_SECCOMP_FILTER
        select BUILDTIME_EXTABLE_SORT
        select GENERIC_CMOS_UPDATE
index c78f14a0df0029a35cbedcb22594fafa1c9110be..dab39350e51e446917d5b5e302fe1ac2214b10d0 100644 (file)
@@ -234,7 +234,7 @@ extern struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr);
 extern void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap);
 extern void perf_check_microcode(void);
 #else
-static inline perf_guest_switch_msr *perf_guest_get_msrs(int *nr)
+static inline struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr)
 {
        *nr = 0;
        return NULL;
index 4437001d8e3d124853e7e12289befb09c12b2e2f..0d9776e9e2dc3f2a539015a5f2930e00d2727a99 100644 (file)
@@ -15,7 +15,6 @@
 # ifdef CONFIG_X86_32
 
 #  include <asm/unistd_32.h>
-#  define __ARCH_WANT_IPC_PARSE_VERSION
 #  define __ARCH_WANT_STAT64
 #  define __ARCH_WANT_SYS_IPC
 #  define __ARCH_WANT_SYS_OLD_MMAP
index a15df4be151fc924e3cf8a9b25ab18c991c0b58c..821d53b696d1408fb1b71faffda28283052d9733 100644 (file)
@@ -374,7 +374,7 @@ struct x86_pmu {
        /*
         * Intel DebugStore bits
         */
-       int             bts             :1,
+       unsigned int    bts             :1,
                        bts_active      :1,
                        pebs            :1,
                        pebs_active     :1,
index 7a8b9d0abcaa33c754481cf38c3f26c366f701c9..382366977d4c7856d2cd354ebccc908da65e1a4b 100644 (file)
@@ -138,6 +138,84 @@ static u64 intel_pmu_event_map(int hw_event)
        return intel_perfmon_event_map[hw_event];
 }
 
+#define SNB_DMND_DATA_RD       (1ULL << 0)
+#define SNB_DMND_RFO           (1ULL << 1)
+#define SNB_DMND_IFETCH                (1ULL << 2)
+#define SNB_DMND_WB            (1ULL << 3)
+#define SNB_PF_DATA_RD         (1ULL << 4)
+#define SNB_PF_RFO             (1ULL << 5)
+#define SNB_PF_IFETCH          (1ULL << 6)
+#define SNB_LLC_DATA_RD                (1ULL << 7)
+#define SNB_LLC_RFO            (1ULL << 8)
+#define SNB_LLC_IFETCH         (1ULL << 9)
+#define SNB_BUS_LOCKS          (1ULL << 10)
+#define SNB_STRM_ST            (1ULL << 11)
+#define SNB_OTHER              (1ULL << 15)
+#define SNB_RESP_ANY           (1ULL << 16)
+#define SNB_NO_SUPP            (1ULL << 17)
+#define SNB_LLC_HITM           (1ULL << 18)
+#define SNB_LLC_HITE           (1ULL << 19)
+#define SNB_LLC_HITS           (1ULL << 20)
+#define SNB_LLC_HITF           (1ULL << 21)
+#define SNB_LOCAL              (1ULL << 22)
+#define SNB_REMOTE             (0xffULL << 23)
+#define SNB_SNP_NONE           (1ULL << 31)
+#define SNB_SNP_NOT_NEEDED     (1ULL << 32)
+#define SNB_SNP_MISS           (1ULL << 33)
+#define SNB_NO_FWD             (1ULL << 34)
+#define SNB_SNP_FWD            (1ULL << 35)
+#define SNB_HITM               (1ULL << 36)
+#define SNB_NON_DRAM           (1ULL << 37)
+
+#define SNB_DMND_READ          (SNB_DMND_DATA_RD|SNB_LLC_DATA_RD)
+#define SNB_DMND_WRITE         (SNB_DMND_RFO|SNB_LLC_RFO)
+#define SNB_DMND_PREFETCH      (SNB_PF_DATA_RD|SNB_PF_RFO)
+
+#define SNB_SNP_ANY            (SNB_SNP_NONE|SNB_SNP_NOT_NEEDED| \
+                                SNB_SNP_MISS|SNB_NO_FWD|SNB_SNP_FWD| \
+                                SNB_HITM)
+
+#define SNB_DRAM_ANY           (SNB_LOCAL|SNB_REMOTE|SNB_SNP_ANY)
+#define SNB_DRAM_REMOTE                (SNB_REMOTE|SNB_SNP_ANY)
+
+#define SNB_L3_ACCESS          SNB_RESP_ANY
+#define SNB_L3_MISS            (SNB_DRAM_ANY|SNB_NON_DRAM)
+
+static __initconst const u64 snb_hw_cache_extra_regs
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(LL  ) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = SNB_DMND_READ|SNB_L3_ACCESS,
+               [ C(RESULT_MISS)   ] = SNB_DMND_READ|SNB_L3_MISS,
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = SNB_DMND_WRITE|SNB_L3_ACCESS,
+               [ C(RESULT_MISS)   ] = SNB_DMND_WRITE|SNB_L3_MISS,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = SNB_DMND_PREFETCH|SNB_L3_ACCESS,
+               [ C(RESULT_MISS)   ] = SNB_DMND_PREFETCH|SNB_L3_MISS,
+       },
+ },
+ [ C(NODE) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = SNB_DMND_READ|SNB_DRAM_ANY,
+               [ C(RESULT_MISS)   ] = SNB_DMND_READ|SNB_DRAM_REMOTE,
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = SNB_DMND_WRITE|SNB_DRAM_ANY,
+               [ C(RESULT_MISS)   ] = SNB_DMND_WRITE|SNB_DRAM_REMOTE,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = SNB_DMND_PREFETCH|SNB_DRAM_ANY,
+               [ C(RESULT_MISS)   ] = SNB_DMND_PREFETCH|SNB_DRAM_REMOTE,
+       },
+ },
+};
+
 static __initconst const u64 snb_hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
@@ -235,16 +313,16 @@ static __initconst const u64 snb_hw_cache_event_ids
  },
  [ C(NODE) ] = {
        [ C(OP_READ) ] = {
-               [ C(RESULT_ACCESS) ] = -1,
-               [ C(RESULT_MISS)   ] = -1,
+               [ C(RESULT_ACCESS) ] = 0x01b7,
+               [ C(RESULT_MISS)   ] = 0x01b7,
        },
        [ C(OP_WRITE) ] = {
-               [ C(RESULT_ACCESS) ] = -1,
-               [ C(RESULT_MISS)   ] = -1,
+               [ C(RESULT_ACCESS) ] = 0x01b7,
+               [ C(RESULT_MISS)   ] = 0x01b7,
        },
        [ C(OP_PREFETCH) ] = {
-               [ C(RESULT_ACCESS) ] = -1,
-               [ C(RESULT_MISS)   ] = -1,
+               [ C(RESULT_ACCESS) ] = 0x01b7,
+               [ C(RESULT_MISS)   ] = 0x01b7,
        },
  },
 
@@ -1964,6 +2042,8 @@ __init int intel_pmu_init(void)
        case 58: /* IvyBridge */
                memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
+               memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
+                      sizeof(hw_cache_extra_regs));
 
                intel_pmu_lbr_init_snb();
 
index 19faffc608865fe8e14a29200a32cb01b8c3b268..7563fda9f0339b935c7b40a347409b966f7ffbdc 100644 (file)
@@ -18,6 +18,7 @@ static struct event_constraint constraint_empty =
        EVENT_CONSTRAINT(0, 0, 0);
 
 DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
 DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
 DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
 DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
@@ -33,10 +34,81 @@ DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
 DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17");
 DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22");
 DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31");
-DEFINE_UNCORE_FORMAT_ATTR(filter_brand0, filter_brand0, "config1:0-7");
-DEFINE_UNCORE_FORMAT_ATTR(filter_brand1, filter_brand1, "config1:8-15");
-DEFINE_UNCORE_FORMAT_ATTR(filter_brand2, filter_brand2, "config1:16-23");
-DEFINE_UNCORE_FORMAT_ATTR(filter_brand3, filter_brand3, "config1:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band0, filter_band0, "config1:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band1, filter_band1, "config1:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band2, filter_band2, "config1:16-23");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band3, filter_band3, "config1:24-31");
+
+static u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+       u64 count;
+
+       rdmsrl(event->hw.event_base, count);
+
+       return count;
+}
+
+/*
+ * generic get constraint function for shared match/mask registers.
+ */
+static struct event_constraint *
+uncore_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct intel_uncore_extra_reg *er;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+       unsigned long flags;
+       bool ok = false;
+
+       /*
+        * reg->alloc can be set due to existing state, so for fake box we
+        * need to ignore this, otherwise we might fail to allocate proper
+        * fake state for this extra reg constraint.
+        */
+       if (reg1->idx == EXTRA_REG_NONE ||
+           (!uncore_box_is_fake(box) && reg1->alloc))
+               return NULL;
+
+       er = &box->shared_regs[reg1->idx];
+       raw_spin_lock_irqsave(&er->lock, flags);
+       if (!atomic_read(&er->ref) ||
+           (er->config1 == reg1->config && er->config2 == reg2->config)) {
+               atomic_inc(&er->ref);
+               er->config1 = reg1->config;
+               er->config2 = reg2->config;
+               ok = true;
+       }
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+
+       if (ok) {
+               if (!uncore_box_is_fake(box))
+                       reg1->alloc = 1;
+               return NULL;
+       }
+
+       return &constraint_empty;
+}
+
+static void uncore_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct intel_uncore_extra_reg *er;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+
+       /*
+        * Only put constraint if extra reg was actually allocated. Also
+        * takes care of event which do not use an extra shared reg.
+        *
+        * Also, if this is a fake box we shouldn't touch any event state
+        * (reg->alloc) and we don't care about leaving inconsistent box
+        * state either since it will be thrown out.
+        */
+       if (uncore_box_is_fake(box) || !reg1->alloc)
+               return;
+
+       er = &box->shared_regs[reg1->idx];
+       atomic_dec(&er->ref);
+       reg1->alloc = 0;
+}
 
 /* Sandy Bridge-EP uncore support */
 static struct intel_uncore_type snbep_uncore_cbox;
@@ -64,18 +136,15 @@ static void snbep_uncore_pci_enable_box(struct intel_uncore_box *box)
        pci_write_config_dword(pdev, box_ctl, config);
 }
 
-static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box,
-                                       struct perf_event *event)
+static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box, struct perf_event *event)
 {
        struct pci_dev *pdev = box->pci_dev;
        struct hw_perf_event *hwc = &event->hw;
 
-       pci_write_config_dword(pdev, hwc->config_base, hwc->config |
-                               SNBEP_PMON_CTL_EN);
+       pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
 }
 
-static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box,
-                                       struct perf_event *event)
+static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box, struct perf_event *event)
 {
        struct pci_dev *pdev = box->pci_dev;
        struct hw_perf_event *hwc = &event->hw;
@@ -83,8 +152,7 @@ static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box,
        pci_write_config_dword(pdev, hwc->config_base, hwc->config);
 }
 
-static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box,
-                                       struct perf_event *event)
+static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box, struct perf_event *event)
 {
        struct pci_dev *pdev = box->pci_dev;
        struct hw_perf_event *hwc = &event->hw;
@@ -92,14 +160,15 @@ static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box,
 
        pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count);
        pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1);
+
        return count;
 }
 
 static void snbep_uncore_pci_init_box(struct intel_uncore_box *box)
 {
        struct pci_dev *pdev = box->pci_dev;
-       pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL,
-                               SNBEP_PMON_BOX_CTL_INT);
+
+       pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, SNBEP_PMON_BOX_CTL_INT);
 }
 
 static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box)
@@ -112,7 +181,6 @@ static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box)
                rdmsrl(msr, config);
                config |= SNBEP_PMON_BOX_CTL_FRZ;
                wrmsrl(msr, config);
-               return;
        }
 }
 
@@ -126,12 +194,10 @@ static void snbep_uncore_msr_enable_box(struct intel_uncore_box *box)
                rdmsrl(msr, config);
                config &= ~SNBEP_PMON_BOX_CTL_FRZ;
                wrmsrl(msr, config);
-               return;
        }
 }
 
-static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box,
-                                       struct perf_event *event)
+static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
 {
        struct hw_perf_event *hwc = &event->hw;
        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
@@ -150,68 +216,15 @@ static void snbep_uncore_msr_disable_event(struct intel_uncore_box *box,
        wrmsrl(hwc->config_base, hwc->config);
 }
 
-static u64 snbep_uncore_msr_read_counter(struct intel_uncore_box *box,
-                                       struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       u64 count;
-
-       rdmsrl(hwc->event_base, count);
-       return count;
-}
-
 static void snbep_uncore_msr_init_box(struct intel_uncore_box *box)
 {
        unsigned msr = uncore_msr_box_ctl(box);
+
        if (msr)
                wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT);
 }
 
-static struct event_constraint *
-snbep_uncore_get_constraint(struct intel_uncore_box *box,
-                           struct perf_event *event)
-{
-       struct intel_uncore_extra_reg *er;
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       unsigned long flags;
-       bool ok = false;
-
-       if (reg1->idx == EXTRA_REG_NONE || (box->phys_id >= 0 && reg1->alloc))
-               return NULL;
-
-       er = &box->shared_regs[reg1->idx];
-       raw_spin_lock_irqsave(&er->lock, flags);
-       if (!atomic_read(&er->ref) || er->config1 == reg1->config) {
-               atomic_inc(&er->ref);
-               er->config1 = reg1->config;
-               ok = true;
-       }
-       raw_spin_unlock_irqrestore(&er->lock, flags);
-
-       if (ok) {
-               if (box->phys_id >= 0)
-                       reg1->alloc = 1;
-               return NULL;
-       }
-       return &constraint_empty;
-}
-
-static void snbep_uncore_put_constraint(struct intel_uncore_box *box,
-                                       struct perf_event *event)
-{
-       struct intel_uncore_extra_reg *er;
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-
-       if (box->phys_id < 0 || !reg1->alloc)
-               return;
-
-       er = &box->shared_regs[reg1->idx];
-       atomic_dec(&er->ref);
-       reg1->alloc = 0;
-}
-
-static int snbep_uncore_hw_config(struct intel_uncore_box *box,
-                                 struct perf_event *event)
+static int snbep_uncore_hw_config(struct intel_uncore_box *box, struct perf_event *event)
 {
        struct hw_perf_event *hwc = &event->hw;
        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
@@ -221,14 +234,16 @@ static int snbep_uncore_hw_config(struct intel_uncore_box *box,
                        SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
                reg1->config = event->attr.config1 &
                        SNBEP_CB0_MSR_PMON_BOX_FILTER_MASK;
-       } else if (box->pmu->type == &snbep_uncore_pcu) {
-               reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER;
-               reg1->config = event->attr.config1 &
-                       SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK;
        } else {
-               return 0;
+               if (box->pmu->type == &snbep_uncore_pcu) {
+                       reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER;
+                       reg1->config = event->attr.config1 & SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK;
+               } else {
+                       return 0;
+               }
        }
        reg1->idx = 0;
+
        return 0;
 }
 
@@ -272,10 +287,19 @@ static struct attribute *snbep_uncore_pcu_formats_attr[] = {
        &format_attr_thresh5.attr,
        &format_attr_occ_invert.attr,
        &format_attr_occ_edge.attr,
-       &format_attr_filter_brand0.attr,
-       &format_attr_filter_brand1.attr,
-       &format_attr_filter_brand2.attr,
-       &format_attr_filter_brand3.attr,
+       &format_attr_filter_band0.attr,
+       &format_attr_filter_band1.attr,
+       &format_attr_filter_band2.attr,
+       &format_attr_filter_band3.attr,
+       NULL,
+};
+
+static struct attribute *snbep_uncore_qpi_formats_attr[] = {
+       &format_attr_event_ext.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
        NULL,
 };
 
@@ -314,15 +338,20 @@ static struct attribute_group snbep_uncore_pcu_format_group = {
        .attrs = snbep_uncore_pcu_formats_attr,
 };
 
+static struct attribute_group snbep_uncore_qpi_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_qpi_formats_attr,
+};
+
 static struct intel_uncore_ops snbep_uncore_msr_ops = {
        .init_box       = snbep_uncore_msr_init_box,
        .disable_box    = snbep_uncore_msr_disable_box,
        .enable_box     = snbep_uncore_msr_enable_box,
        .disable_event  = snbep_uncore_msr_disable_event,
        .enable_event   = snbep_uncore_msr_enable_event,
-       .read_counter   = snbep_uncore_msr_read_counter,
-       .get_constraint = snbep_uncore_get_constraint,
-       .put_constraint = snbep_uncore_put_constraint,
+       .read_counter   = uncore_msr_read_counter,
+       .get_constraint = uncore_get_constraint,
+       .put_constraint = uncore_put_constraint,
        .hw_config      = snbep_uncore_hw_config,
 };
 
@@ -485,8 +514,13 @@ static struct intel_uncore_type snbep_uncore_qpi = {
        .num_counters   = 4,
        .num_boxes      = 2,
        .perf_ctr_bits  = 48,
+       .perf_ctr       = SNBEP_PCI_PMON_CTR0,
+       .event_ctl      = SNBEP_PCI_PMON_CTL0,
+       .event_mask     = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,
+       .ops            = &snbep_uncore_pci_ops,
        .event_descs    = snbep_uncore_qpi_events,
-       SNBEP_UNCORE_PCI_COMMON_INIT(),
+       .format_group   = &snbep_uncore_qpi_format_group,
 };
 
 
@@ -589,188 +623,1208 @@ static void snbep_pci2phy_map_init(void)
                /* get the Node ID mapping */
                pci_read_config_dword(ubox_dev, 0x54, &config);
                /*
-                * every three bits in the Node ID mapping register maps
-                * to a particular node.
+                * every three bits in the Node ID mapping register maps
+                * to a particular node.
+                */
+               for (i = 0; i < 8; i++) {
+                       if (nodeid == ((config >> (3 * i)) & 0x7)) {
+                               pcibus_to_physid[bus] = i;
+                               break;
+                       }
+               }
+       };
+       return;
+}
+/* end of Sandy Bridge-EP uncore support */
+
+/* Sandy Bridge uncore support */
+static void snb_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
+               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
+       else
+               wrmsrl(hwc->config_base, SNB_UNC_CTL_EN);
+}
+
+static void snb_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       wrmsrl(event->hw.config_base, 0);
+}
+
+static void snb_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+       if (box->pmu->pmu_idx == 0) {
+               wrmsrl(SNB_UNC_PERF_GLOBAL_CTL,
+                       SNB_UNC_GLOBAL_CTL_EN | SNB_UNC_GLOBAL_CTL_CORE_ALL);
+       }
+}
+
+static struct attribute *snb_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_cmask5.attr,
+       NULL,
+};
+
+static struct attribute_group snb_uncore_format_group = {
+       .name           = "format",
+       .attrs          = snb_uncore_formats_attr,
+};
+
+static struct intel_uncore_ops snb_uncore_msr_ops = {
+       .init_box       = snb_uncore_msr_init_box,
+       .disable_event  = snb_uncore_msr_disable_event,
+       .enable_event   = snb_uncore_msr_enable_event,
+       .read_counter   = uncore_msr_read_counter,
+};
+
+static struct event_constraint snb_uncore_cbox_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x80, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x83, 0x1),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type snb_uncore_cbox = {
+       .name           = "cbox",
+       .num_counters   = 2,
+       .num_boxes      = 4,
+       .perf_ctr_bits  = 44,
+       .fixed_ctr_bits = 48,
+       .perf_ctr       = SNB_UNC_CBO_0_PER_CTR0,
+       .event_ctl      = SNB_UNC_CBO_0_PERFEVTSEL0,
+       .fixed_ctr      = SNB_UNC_FIXED_CTR,
+       .fixed_ctl      = SNB_UNC_FIXED_CTR_CTRL,
+       .single_fixed   = 1,
+       .event_mask     = SNB_UNC_RAW_EVENT_MASK,
+       .msr_offset     = SNB_UNC_CBO_MSR_OFFSET,
+       .constraints    = snb_uncore_cbox_constraints,
+       .ops            = &snb_uncore_msr_ops,
+       .format_group   = &snb_uncore_format_group,
+};
+
+static struct intel_uncore_type *snb_msr_uncores[] = {
+       &snb_uncore_cbox,
+       NULL,
+};
+/* end of Sandy Bridge uncore support */
+
+/* Nehalem uncore support */
+static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, 0);
+}
+
+static void nhm_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, NHM_UNC_GLOBAL_CTL_EN_PC_ALL | NHM_UNC_GLOBAL_CTL_EN_FC);
+}
+
+static void nhm_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
+               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
+       else
+               wrmsrl(hwc->config_base, NHM_UNC_FIXED_CTR_CTL_EN);
+}
+
+static struct attribute *nhm_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_cmask8.attr,
+       NULL,
+};
+
+static struct attribute_group nhm_uncore_format_group = {
+       .name = "format",
+       .attrs = nhm_uncore_formats_attr,
+};
+
+static struct uncore_event_desc nhm_uncore_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks,                "event=0xff,umask=0x00"),
+       INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any,       "event=0x2f,umask=0x0f"),
+       INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any,      "event=0x2c,umask=0x0f"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads,     "event=0x20,umask=0x01"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes,    "event=0x20,umask=0x02"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads,  "event=0x20,umask=0x04"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads,   "event=0x20,umask=0x10"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes,  "event=0x20,umask=0x20"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_ops nhm_uncore_msr_ops = {
+       .disable_box    = nhm_uncore_msr_disable_box,
+       .enable_box     = nhm_uncore_msr_enable_box,
+       .disable_event  = snb_uncore_msr_disable_event,
+       .enable_event   = nhm_uncore_msr_enable_event,
+       .read_counter   = uncore_msr_read_counter,
+};
+
+static struct intel_uncore_type nhm_uncore = {
+       .name           = "",
+       .num_counters   = 8,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .event_ctl      = NHM_UNC_PERFEVTSEL0,
+       .perf_ctr       = NHM_UNC_UNCORE_PMC0,
+       .fixed_ctr      = NHM_UNC_FIXED_CTR,
+       .fixed_ctl      = NHM_UNC_FIXED_CTR_CTRL,
+       .event_mask     = NHM_UNC_RAW_EVENT_MASK,
+       .event_descs    = nhm_uncore_events,
+       .ops            = &nhm_uncore_msr_ops,
+       .format_group   = &nhm_uncore_format_group,
+};
+
+static struct intel_uncore_type *nhm_msr_uncores[] = {
+       &nhm_uncore,
+       NULL,
+};
+/* end of Nehalem uncore support */
+
+/* Nehalem-EX uncore support */
+#define __BITS_VALUE(x, i, n)  ((typeof(x))(((x) >> ((i) * (n))) & \
+                               ((1ULL << (n)) - 1)))
+
+DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5");
+DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7");
+DEFINE_UNCORE_FORMAT_ATTR(mm_cfg, mm_cfg, "config:63");
+DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63");
+
+static void nhmex_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+       wrmsrl(NHMEX_U_MSR_PMON_GLOBAL_CTL, NHMEX_U_PMON_GLOBAL_EN_ALL);
+}
+
+static void nhmex_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+       unsigned msr = uncore_msr_box_ctl(box);
+       u64 config;
+
+       if (msr) {
+               rdmsrl(msr, config);
+               config &= ~((1ULL << uncore_num_counters(box)) - 1);
+               /* WBox has a fixed counter */
+               if (uncore_msr_fixed_ctl(box))
+                       config &= ~NHMEX_W_PMON_GLOBAL_FIXED_EN;
+               wrmsrl(msr, config);
+       }
+}
+
+static void nhmex_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+       unsigned msr = uncore_msr_box_ctl(box);
+       u64 config;
+
+       if (msr) {
+               rdmsrl(msr, config);
+               config |= (1ULL << uncore_num_counters(box)) - 1;
+               /* WBox has a fixed counter */
+               if (uncore_msr_fixed_ctl(box))
+                       config |= NHMEX_W_PMON_GLOBAL_FIXED_EN;
+               wrmsrl(msr, config);
+       }
+}
+
+static void nhmex_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       wrmsrl(event->hw.config_base, 0);
+}
+
+static void nhmex_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->idx >= UNCORE_PMC_IDX_FIXED)
+               wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0);
+       else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0)
+               wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
+       else
+               wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
+}
+
+#define NHMEX_UNCORE_OPS_COMMON_INIT()                         \
+       .init_box       = nhmex_uncore_msr_init_box,            \
+       .disable_box    = nhmex_uncore_msr_disable_box,         \
+       .enable_box     = nhmex_uncore_msr_enable_box,          \
+       .disable_event  = nhmex_uncore_msr_disable_event,       \
+       .read_counter   = uncore_msr_read_counter
+
+static struct intel_uncore_ops nhmex_uncore_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event   = nhmex_uncore_msr_enable_event,
+};
+
+static struct attribute *nhmex_uncore_ubox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_edge.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_ubox_format_group = {
+       .name           = "format",
+       .attrs          = nhmex_uncore_ubox_formats_attr,
+};
+
+static struct intel_uncore_type nhmex_uncore_ubox = {
+       .name           = "ubox",
+       .num_counters   = 1,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       .event_ctl      = NHMEX_U_MSR_PMON_EV_SEL,
+       .perf_ctr       = NHMEX_U_MSR_PMON_CTR,
+       .event_mask     = NHMEX_U_PMON_RAW_EVENT_MASK,
+       .box_ctl        = NHMEX_U_MSR_PMON_GLOBAL_CTL,
+       .ops            = &nhmex_uncore_ops,
+       .format_group   = &nhmex_uncore_ubox_format_group
+};
+
+static struct attribute *nhmex_uncore_cbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_cbox_format_group = {
+       .name = "format",
+       .attrs = nhmex_uncore_cbox_formats_attr,
+};
+
+static struct intel_uncore_type nhmex_uncore_cbox = {
+       .name                   = "cbox",
+       .num_counters           = 6,
+       .num_boxes              = 8,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_C0_MSR_PMON_EV_SEL0,
+       .perf_ctr               = NHMEX_C0_MSR_PMON_CTR0,
+       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_C0_MSR_PMON_GLOBAL_CTL,
+       .msr_offset             = NHMEX_C_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .ops                    = &nhmex_uncore_ops,
+       .format_group           = &nhmex_uncore_cbox_format_group
+};
+
+static struct uncore_event_desc nhmex_uncore_wbox_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_type nhmex_uncore_wbox = {
+       .name                   = "wbox",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_W_MSR_PMON_CNT0,
+       .perf_ctr               = NHMEX_W_MSR_PMON_EVT_SEL0,
+       .fixed_ctr              = NHMEX_W_MSR_PMON_FIXED_CTR,
+       .fixed_ctl              = NHMEX_W_MSR_PMON_FIXED_CTL,
+       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_W_MSR_GLOBAL_CTL,
+       .pair_ctr_ctl           = 1,
+       .event_descs            = nhmex_uncore_wbox_events,
+       .ops                    = &nhmex_uncore_ops,
+       .format_group           = &nhmex_uncore_cbox_format_group
+};
+
+static int nhmex_bbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+       int ctr, ev_sel;
+
+       ctr = (hwc->config & NHMEX_B_PMON_CTR_MASK) >>
+               NHMEX_B_PMON_CTR_SHIFT;
+       ev_sel = (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK) >>
+                 NHMEX_B_PMON_CTL_EV_SEL_SHIFT;
+
+       /* events that do not use the match/mask registers */
+       if ((ctr == 0 && ev_sel > 0x3) || (ctr == 1 && ev_sel > 0x6) ||
+           (ctr == 2 && ev_sel != 0x4) || ctr == 3)
+               return 0;
+
+       if (box->pmu->pmu_idx == 0)
+               reg1->reg = NHMEX_B0_MSR_MATCH;
+       else
+               reg1->reg = NHMEX_B1_MSR_MATCH;
+       reg1->idx = 0;
+       reg1->config = event->attr.config1;
+       reg2->config = event->attr.config2;
+       return 0;
+}
+
+static void nhmex_bbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE) {
+               wrmsrl(reg1->reg, reg1->config);
+               wrmsrl(reg1->reg + 1, reg2->config);
+       }
+       wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
+               (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK));
+}
+
+/*
+ * The Bbox has 4 counters, but each counter monitors different events.
+ * Use bits 6-7 in the event config to select counter.
+ */
+static struct event_constraint nhmex_uncore_bbox_constraints[] = {
+       EVENT_CONSTRAINT(0 , 1, 0xc0),
+       EVENT_CONSTRAINT(0x40, 2, 0xc0),
+       EVENT_CONSTRAINT(0x80, 4, 0xc0),
+       EVENT_CONSTRAINT(0xc0, 8, 0xc0),
+       EVENT_CONSTRAINT_END,
+};
+
+static struct attribute *nhmex_uncore_bbox_formats_attr[] = {
+       &format_attr_event5.attr,
+       &format_attr_counter.attr,
+       &format_attr_match.attr,
+       &format_attr_mask.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_bbox_format_group = {
+       .name = "format",
+       .attrs = nhmex_uncore_bbox_formats_attr,
+};
+
+static struct intel_uncore_ops nhmex_uncore_bbox_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event           = nhmex_bbox_msr_enable_event,
+       .hw_config              = nhmex_bbox_hw_config,
+       .get_constraint         = uncore_get_constraint,
+       .put_constraint         = uncore_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_bbox = {
+       .name                   = "bbox",
+       .num_counters           = 4,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_B0_MSR_PMON_CTL0,
+       .perf_ctr               = NHMEX_B0_MSR_PMON_CTR0,
+       .event_mask             = NHMEX_B_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_B0_MSR_PMON_GLOBAL_CTL,
+       .msr_offset             = NHMEX_B_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .num_shared_regs        = 1,
+       .constraints            = nhmex_uncore_bbox_constraints,
+       .ops                    = &nhmex_uncore_bbox_ops,
+       .format_group           = &nhmex_uncore_bbox_format_group
+};
+
+static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+
+       if (event->attr.config & NHMEX_S_PMON_MM_CFG_EN) {
+               reg1->config = event->attr.config1;
+               reg2->config = event->attr.config2;
+       } else {
+               reg1->config = ~0ULL;
+               reg2->config = ~0ULL;
+       }
+
+       if (box->pmu->pmu_idx == 0)
+               reg1->reg = NHMEX_S0_MSR_MM_CFG;
+       else
+               reg1->reg = NHMEX_S1_MSR_MM_CFG;
+
+       reg1->idx = 0;
+
+       return 0;
+}
+
+static void nhmex_sbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+       wrmsrl(reg1->reg, 0);
+       if (reg1->config != ~0ULL || reg2->config != ~0ULL) {
+               wrmsrl(reg1->reg + 1, reg1->config);
+               wrmsrl(reg1->reg + 2, reg2->config);
+               wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN);
+       }
+       wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
+}
+
+static struct attribute *nhmex_uncore_sbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_mm_cfg.attr,
+       &format_attr_match.attr,
+       &format_attr_mask.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_sbox_format_group = {
+       .name                   = "format",
+       .attrs                  = nhmex_uncore_sbox_formats_attr,
+};
+
+static struct intel_uncore_ops nhmex_uncore_sbox_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event           = nhmex_sbox_msr_enable_event,
+       .hw_config              = nhmex_sbox_hw_config,
+       .get_constraint         = uncore_get_constraint,
+       .put_constraint         = uncore_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_sbox = {
+       .name                   = "sbox",
+       .num_counters           = 4,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_S0_MSR_PMON_CTL0,
+       .perf_ctr               = NHMEX_S0_MSR_PMON_CTR0,
+       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_S0_MSR_PMON_GLOBAL_CTL,
+       .msr_offset             = NHMEX_S_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .num_shared_regs        = 1,
+       .ops                    = &nhmex_uncore_sbox_ops,
+       .format_group           = &nhmex_uncore_sbox_format_group
+};
+
+enum {
+       EXTRA_REG_NHMEX_M_FILTER,
+       EXTRA_REG_NHMEX_M_DSP,
+       EXTRA_REG_NHMEX_M_ISS,
+       EXTRA_REG_NHMEX_M_MAP,
+       EXTRA_REG_NHMEX_M_MSC_THR,
+       EXTRA_REG_NHMEX_M_PGT,
+       EXTRA_REG_NHMEX_M_PLD,
+       EXTRA_REG_NHMEX_M_ZDP_CTL_FVC,
+};
+
+static struct extra_reg nhmex_uncore_mbox_extra_regs[] = {
+       MBOX_INC_SEL_EXTAR_REG(0x0, DSP),
+       MBOX_INC_SEL_EXTAR_REG(0x4, MSC_THR),
+       MBOX_INC_SEL_EXTAR_REG(0x5, MSC_THR),
+       MBOX_INC_SEL_EXTAR_REG(0x9, ISS),
+       /* event 0xa uses two extra registers */
+       MBOX_INC_SEL_EXTAR_REG(0xa, ISS),
+       MBOX_INC_SEL_EXTAR_REG(0xa, PLD),
+       MBOX_INC_SEL_EXTAR_REG(0xb, PLD),
+       /* events 0xd ~ 0x10 use the same extra register */
+       MBOX_INC_SEL_EXTAR_REG(0xd, ZDP_CTL_FVC),
+       MBOX_INC_SEL_EXTAR_REG(0xe, ZDP_CTL_FVC),
+       MBOX_INC_SEL_EXTAR_REG(0xf, ZDP_CTL_FVC),
+       MBOX_INC_SEL_EXTAR_REG(0x10, ZDP_CTL_FVC),
+       MBOX_INC_SEL_EXTAR_REG(0x16, PGT),
+       MBOX_SET_FLAG_SEL_EXTRA_REG(0x0, DSP),
+       MBOX_SET_FLAG_SEL_EXTRA_REG(0x1, ISS),
+       MBOX_SET_FLAG_SEL_EXTRA_REG(0x5, PGT),
+       MBOX_SET_FLAG_SEL_EXTRA_REG(0x6, MAP),
+       EVENT_EXTRA_END
+};
+
+static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config)
+{
+       struct intel_uncore_extra_reg *er;
+       unsigned long flags;
+       bool ret = false;
+       u64 mask;
+
+       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
+               er = &box->shared_regs[idx];
+               raw_spin_lock_irqsave(&er->lock, flags);
+               if (!atomic_read(&er->ref) || er->config == config) {
+                       atomic_inc(&er->ref);
+                       er->config = config;
+                       ret = true;
+               }
+               raw_spin_unlock_irqrestore(&er->lock, flags);
+
+               return ret;
+       }
+       /*
+        * The ZDP_CTL_FVC MSR has 4 fields which are used to control
+        * events 0xd ~ 0x10. Besides these 4 fields, there are additional
+        * fields which are shared.
+        */
+       idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+       if (WARN_ON_ONCE(idx >= 4))
+               return false;
+
+       /* mask of the shared fields */
+       mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK;
+       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
+
+       raw_spin_lock_irqsave(&er->lock, flags);
+       /* add mask of the non-shared field if it's in use */
+       if (__BITS_VALUE(atomic_read(&er->ref), idx, 8))
+               mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+
+       if (!atomic_read(&er->ref) || !((er->config ^ config) & mask)) {
+               atomic_add(1 << (idx * 8), &er->ref);
+               mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK |
+                       NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+               er->config &= ~mask;
+               er->config |= (config & mask);
+               ret = true;
+       }
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+
+       return ret;
+}
+
+static void nhmex_mbox_put_shared_reg(struct intel_uncore_box *box, int idx)
+{
+       struct intel_uncore_extra_reg *er;
+
+       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
+               er = &box->shared_regs[idx];
+               atomic_dec(&er->ref);
+               return;
+       }
+
+       idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
+       atomic_sub(1 << (idx * 8), &er->ref);
+}
+
+u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       int idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8);
+       u64 config = reg1->config;
+
+       /* get the non-shared control bits and shift them */
+       idx = orig_idx - EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+       config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+       if (new_idx > orig_idx) {
+               idx = new_idx - orig_idx;
+               config <<= 3 * idx;
+       } else {
+               idx = orig_idx - new_idx;
+               config >>= 3 * idx;
+       }
+
+       /* add the shared control bits back */
+       config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
+       if (modify) {
+               /* adjust the main event selector */
+               if (new_idx > orig_idx)
+                       hwc->config += idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
+               else
+                       hwc->config -= idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
+               reg1->config = config;
+               reg1->idx = ~0xff | new_idx;
+       }
+       return config;
+}
+
+static struct event_constraint *
+nhmex_mbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+       int i, idx[2], alloc = 0;
+       u64 config1 = reg1->config;
+
+       idx[0] = __BITS_VALUE(reg1->idx, 0, 8);
+       idx[1] = __BITS_VALUE(reg1->idx, 1, 8);
+again:
+       for (i = 0; i < 2; i++) {
+               if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
+                       idx[i] = 0xff;
+
+               if (idx[i] == 0xff)
+                       continue;
+
+               if (!nhmex_mbox_get_shared_reg(box, idx[i],
+                               __BITS_VALUE(config1, i, 32)))
+                       goto fail;
+               alloc |= (0x1 << i);
+       }
+
+       /* for the match/mask registers */
+       if ((uncore_box_is_fake(box) || !reg2->alloc) &&
+           !nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config))
+               goto fail;
+
+       /*
+        * If it's a fake box -- as per validate_{group,event}() we
+        * shouldn't touch event state and we can avoid doing so
+        * since both will only call get_event_constraints() once
+        * on each event, this avoids the need for reg->alloc.
+        */
+       if (!uncore_box_is_fake(box)) {
+               if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8))
+                       nhmex_mbox_alter_er(event, idx[0], true);
+               reg1->alloc |= alloc;
+               reg2->alloc = 1;
+       }
+       return NULL;
+fail:
+       if (idx[0] != 0xff && !(alloc & 0x1) &&
+           idx[0] >= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
+               /*
+                * events 0xd ~ 0x10 are functional identical, but are
+                * controlled by different fields in the ZDP_CTL_FVC
+                * register. If we failed to take one field, try the
+                * rest 3 choices.
                 */
-               for (i = 0; i < 8; i++) {
-                       if (nodeid == ((config >> (3 * i)) & 0x7)) {
-                               pcibus_to_physid[bus] = i;
-                               break;
-                       }
+               BUG_ON(__BITS_VALUE(reg1->idx, 1, 8) != 0xff);
+               idx[0] -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+               idx[0] = (idx[0] + 1) % 4;
+               idx[0] += EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+               if (idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) {
+                       config1 = nhmex_mbox_alter_er(event, idx[0], false);
+                       goto again;
                }
-       };
-       return;
-}
-/* end of Sandy Bridge-EP uncore support */
+       }
 
+       if (alloc & 0x1)
+               nhmex_mbox_put_shared_reg(box, idx[0]);
+       if (alloc & 0x2)
+               nhmex_mbox_put_shared_reg(box, idx[1]);
+       return &constraint_empty;
+}
 
-/* Sandy Bridge uncore support */
-static void snb_uncore_msr_enable_event(struct intel_uncore_box *box,
-                                       struct perf_event *event)
+static void nhmex_mbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
 {
-       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
 
-       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
-               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
-       else
-               wrmsrl(hwc->config_base, SNB_UNC_CTL_EN);
+       if (uncore_box_is_fake(box))
+               return;
+
+       if (reg1->alloc & 0x1)
+               nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 0, 8));
+       if (reg1->alloc & 0x2)
+               nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 1, 8));
+       reg1->alloc = 0;
+
+       if (reg2->alloc) {
+               nhmex_mbox_put_shared_reg(box, reg2->idx);
+               reg2->alloc = 0;
+       }
 }
 
-static void snb_uncore_msr_disable_event(struct intel_uncore_box *box,
-                                       struct perf_event *event)
+static int nhmex_mbox_extra_reg_idx(struct extra_reg *er)
 {
-       wrmsrl(event->hw.config_base, 0);
+       if (er->idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
+               return er->idx;
+       return er->idx + (er->event >> NHMEX_M_PMON_CTL_INC_SEL_SHIFT) - 0xd;
 }
 
-static u64 snb_uncore_msr_read_counter(struct intel_uncore_box *box,
-                                       struct perf_event *event)
+static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
 {
-       u64 count;
-       rdmsrl(event->hw.event_base, count);
-       return count;
+       struct intel_uncore_type *type = box->pmu->type;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+       struct extra_reg *er;
+       unsigned msr;
+       int reg_idx = 0;
+
+       if (WARN_ON_ONCE(reg1->idx != -1))
+               return -EINVAL;
+       /*
+        * The mbox events may require 2 extra MSRs at the most. But only
+        * the lower 32 bits in these MSRs are significant, so we can use
+        * config1 to pass two MSRs' config.
+        */
+       for (er = nhmex_uncore_mbox_extra_regs; er->msr; er++) {
+               if (er->event != (event->hw.config & er->config_mask))
+                       continue;
+               if (event->attr.config1 & ~er->valid_mask)
+                       return -EINVAL;
+               if (er->idx == __BITS_VALUE(reg1->idx, 0, 8) ||
+                   er->idx == __BITS_VALUE(reg1->idx, 1, 8))
+                       continue;
+               if (WARN_ON_ONCE(reg_idx >= 2))
+                       return -EINVAL;
+
+               msr = er->msr + type->msr_offset * box->pmu->pmu_idx;
+               if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff))
+                       return -EINVAL;
+
+               /* always use the 32~63 bits to pass the PLD config */
+               if (er->idx == EXTRA_REG_NHMEX_M_PLD)
+                       reg_idx = 1;
+
+               reg1->idx &= ~(0xff << (reg_idx * 8));
+               reg1->reg &= ~(0xffff << (reg_idx * 16));
+               reg1->idx |= nhmex_mbox_extra_reg_idx(er) << (reg_idx * 8);
+               reg1->reg |= msr << (reg_idx * 16);
+               reg1->config = event->attr.config1;
+               reg_idx++;
+       }
+       /* use config2 to pass the filter config */
+       reg2->idx = EXTRA_REG_NHMEX_M_FILTER;
+       if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN)
+               reg2->config = event->attr.config2;
+       else
+               reg2->config = ~0ULL;
+       if (box->pmu->pmu_idx == 0)
+               reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG;
+       else
+               reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG;
+
+       return 0;
 }
 
-static void snb_uncore_msr_init_box(struct intel_uncore_box *box)
+static u64 nhmex_mbox_shared_reg_config(struct intel_uncore_box *box, int idx)
 {
-       if (box->pmu->pmu_idx == 0) {
-               wrmsrl(SNB_UNC_PERF_GLOBAL_CTL,
-                       SNB_UNC_GLOBAL_CTL_EN | SNB_UNC_GLOBAL_CTL_CORE_ALL);
-       }
+       struct intel_uncore_extra_reg *er;
+       unsigned long flags;
+       u64 config;
+
+       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
+               return box->shared_regs[idx].config;
+
+       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
+       raw_spin_lock_irqsave(&er->lock, flags);
+       config = er->config;
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+       return config;
 }
 
-static struct attribute *snb_uncore_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_cmask5.attr,
+static void nhmex_mbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+       int idx;
+
+       idx = __BITS_VALUE(reg1->idx, 0, 8);
+       if (idx != 0xff)
+               wrmsrl(__BITS_VALUE(reg1->reg, 0, 16),
+                       nhmex_mbox_shared_reg_config(box, idx));
+       idx = __BITS_VALUE(reg1->idx, 1, 8);
+       if (idx != 0xff)
+               wrmsrl(__BITS_VALUE(reg1->reg, 1, 16),
+                       nhmex_mbox_shared_reg_config(box, idx));
+
+       wrmsrl(reg2->reg, 0);
+       if (reg2->config != ~0ULL) {
+               wrmsrl(reg2->reg + 1,
+                       reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK);
+               wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK &
+                       (reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT));
+               wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN);
+       }
+
+       wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
+}
+
+DEFINE_UNCORE_FORMAT_ATTR(count_mode,  count_mode,     "config:2-3");
+DEFINE_UNCORE_FORMAT_ATTR(storage_mode, storage_mode,  "config:4-5");
+DEFINE_UNCORE_FORMAT_ATTR(wrap_mode,   wrap_mode,      "config:6");
+DEFINE_UNCORE_FORMAT_ATTR(flag_mode,   flag_mode,      "config:7");
+DEFINE_UNCORE_FORMAT_ATTR(inc_sel,     inc_sel,        "config:9-13");
+DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel,        set_flag_sel,   "config:19-21");
+DEFINE_UNCORE_FORMAT_ATTR(filter_cfg,  filter_cfg,     "config2:63");
+DEFINE_UNCORE_FORMAT_ATTR(filter_match,        filter_match,   "config2:0-33");
+DEFINE_UNCORE_FORMAT_ATTR(filter_mask, filter_mask,    "config2:34-61");
+DEFINE_UNCORE_FORMAT_ATTR(dsp,         dsp,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(thr,         thr,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(fvc,         fvc,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(pgt,         pgt,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(map,         map,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(iss,         iss,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(pld,         pld,            "config1:32-63");
+
+static struct attribute *nhmex_uncore_mbox_formats_attr[] = {
+       &format_attr_count_mode.attr,
+       &format_attr_storage_mode.attr,
+       &format_attr_wrap_mode.attr,
+       &format_attr_flag_mode.attr,
+       &format_attr_inc_sel.attr,
+       &format_attr_set_flag_sel.attr,
+       &format_attr_filter_cfg.attr,
+       &format_attr_filter_match.attr,
+       &format_attr_filter_mask.attr,
+       &format_attr_dsp.attr,
+       &format_attr_thr.attr,
+       &format_attr_fvc.attr,
+       &format_attr_pgt.attr,
+       &format_attr_map.attr,
+       &format_attr_iss.attr,
+       &format_attr_pld.attr,
        NULL,
 };
 
-static struct attribute_group snb_uncore_format_group = {
-       .name = "format",
-       .attrs = snb_uncore_formats_attr,
+static struct attribute_group nhmex_uncore_mbox_format_group = {
+       .name           = "format",
+       .attrs          = nhmex_uncore_mbox_formats_attr,
 };
 
-static struct intel_uncore_ops snb_uncore_msr_ops = {
-       .init_box       = snb_uncore_msr_init_box,
-       .disable_event  = snb_uncore_msr_disable_event,
-       .enable_event   = snb_uncore_msr_enable_event,
-       .read_counter   = snb_uncore_msr_read_counter,
+static struct uncore_event_desc nhmex_uncore_mbox_events[] = {
+       INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x2800"),
+       INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x2820"),
+       { /* end: all zeroes */ },
 };
 
-static struct event_constraint snb_uncore_cbox_constraints[] = {
-       UNCORE_EVENT_CONSTRAINT(0x80, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x83, 0x1),
-       EVENT_CONSTRAINT_END
+static struct intel_uncore_ops nhmex_uncore_mbox_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event   = nhmex_mbox_msr_enable_event,
+       .hw_config      = nhmex_mbox_hw_config,
+       .get_constraint = nhmex_mbox_get_constraint,
+       .put_constraint = nhmex_mbox_put_constraint,
 };
 
-static struct intel_uncore_type snb_uncore_cbox = {
-       .name           = "cbox",
-       .num_counters   = 2,
-       .num_boxes      = 4,
-       .perf_ctr_bits  = 44,
-       .fixed_ctr_bits = 48,
-       .perf_ctr       = SNB_UNC_CBO_0_PER_CTR0,
-       .event_ctl      = SNB_UNC_CBO_0_PERFEVTSEL0,
-       .fixed_ctr      = SNB_UNC_FIXED_CTR,
-       .fixed_ctl      = SNB_UNC_FIXED_CTR_CTRL,
-       .single_fixed   = 1,
-       .event_mask     = SNB_UNC_RAW_EVENT_MASK,
-       .msr_offset     = SNB_UNC_CBO_MSR_OFFSET,
-       .constraints    = snb_uncore_cbox_constraints,
-       .ops            = &snb_uncore_msr_ops,
-       .format_group   = &snb_uncore_format_group,
+static struct intel_uncore_type nhmex_uncore_mbox = {
+       .name                   = "mbox",
+       .num_counters           = 6,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_M0_MSR_PMU_CTL0,
+       .perf_ctr               = NHMEX_M0_MSR_PMU_CNT0,
+       .event_mask             = NHMEX_M_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_M0_MSR_GLOBAL_CTL,
+       .msr_offset             = NHMEX_M_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .num_shared_regs        = 8,
+       .event_descs            = nhmex_uncore_mbox_events,
+       .ops                    = &nhmex_uncore_mbox_ops,
+       .format_group           = &nhmex_uncore_mbox_format_group,
 };
 
-static struct intel_uncore_type *snb_msr_uncores[] = {
-       &snb_uncore_cbox,
-       NULL,
-};
-/* end of Sandy Bridge uncore support */
+void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       int port;
 
-/* Nehalem uncore support */
-static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box)
+       /* adjust the main event selector */
+       if (reg1->idx % 2) {
+               reg1->idx--;
+               hwc->config -= 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
+       } else {
+               reg1->idx++;
+               hwc->config += 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
+       }
+
+       /* adjust address or config of extra register */
+       port = reg1->idx / 6 + box->pmu->pmu_idx * 4;
+       switch (reg1->idx % 6) {
+       case 0:
+               reg1->reg = NHMEX_R_MSR_PORTN_IPERF_CFG0(port);
+               break;
+       case 1:
+               reg1->reg = NHMEX_R_MSR_PORTN_IPERF_CFG1(port);
+               break;
+       case 2:
+               /* the 8~15 bits to the 0~7 bits */
+               reg1->config >>= 8;
+               break;
+       case 3:
+               /* the 0~7 bits to the 8~15 bits */
+               reg1->config <<= 8;
+               break;
+       case 4:
+               reg1->reg = NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port);
+               break;
+       case 5:
+               reg1->reg = NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port);
+               break;
+       };
+}
+
+/*
+ * Each rbox has 4 event set which monitor PQI port 0~3 or 4~7.
+ * An event set consists of 6 events, the 3rd and 4th events in
+ * an event set use the same extra register. So an event set uses
+ * 5 extra registers.
+ */
+static struct event_constraint *
+nhmex_rbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
 {
-       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, 0);
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+       struct intel_uncore_extra_reg *er;
+       unsigned long flags;
+       int idx, er_idx;
+       u64 config1;
+       bool ok = false;
+
+       if (!uncore_box_is_fake(box) && reg1->alloc)
+               return NULL;
+
+       idx = reg1->idx % 6;
+       config1 = reg1->config;
+again:
+       er_idx = idx;
+       /* the 3rd and 4th events use the same extra register */
+       if (er_idx > 2)
+               er_idx--;
+       er_idx += (reg1->idx / 6) * 5;
+
+       er = &box->shared_regs[er_idx];
+       raw_spin_lock_irqsave(&er->lock, flags);
+       if (idx < 2) {
+               if (!atomic_read(&er->ref) || er->config == reg1->config) {
+                       atomic_inc(&er->ref);
+                       er->config = reg1->config;
+                       ok = true;
+               }
+       } else if (idx == 2 || idx == 3) {
+               /*
+                * these two events use different fields in a extra register,
+                * the 0~7 bits and the 8~15 bits respectively.
+                */
+               u64 mask = 0xff << ((idx - 2) * 8);
+               if (!__BITS_VALUE(atomic_read(&er->ref), idx - 2, 8) ||
+                               !((er->config ^ config1) & mask)) {
+                       atomic_add(1 << ((idx - 2) * 8), &er->ref);
+                       er->config &= ~mask;
+                       er->config |= config1 & mask;
+                       ok = true;
+               }
+       } else {
+               if (!atomic_read(&er->ref) ||
+                               (er->config == (hwc->config >> 32) &&
+                                er->config1 == reg1->config &&
+                                er->config2 == reg2->config)) {
+                       atomic_inc(&er->ref);
+                       er->config = (hwc->config >> 32);
+                       er->config1 = reg1->config;
+                       er->config2 = reg2->config;
+                       ok = true;
+               }
+       }
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+
+       if (!ok) {
+               /*
+                * The Rbox events are always in pairs. The paired
+                * events are functional identical, but use different
+                * extra registers. If we failed to take an extra
+                * register, try the alternative.
+                */
+               if (idx % 2)
+                       idx--;
+               else
+                       idx++;
+               if (idx != reg1->idx % 6) {
+                       if (idx == 2)
+                               config1 >>= 8;
+                       else if (idx == 3)
+                               config1 <<= 8;
+                       goto again;
+               }
+       } else {
+               if (!uncore_box_is_fake(box)) {
+                       if (idx != reg1->idx % 6)
+                               nhmex_rbox_alter_er(box, event);
+                       reg1->alloc = 1;
+               }
+               return NULL;
+       }
+       return &constraint_empty;
 }
 
-static void nhm_uncore_msr_enable_box(struct intel_uncore_box *box)
+static void nhmex_rbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
 {
-       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL,
-               NHM_UNC_GLOBAL_CTL_EN_PC_ALL | NHM_UNC_GLOBAL_CTL_EN_FC);
+       struct intel_uncore_extra_reg *er;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       int idx, er_idx;
+
+       if (uncore_box_is_fake(box) || !reg1->alloc)
+               return;
+
+       idx = reg1->idx % 6;
+       er_idx = idx;
+       if (er_idx > 2)
+               er_idx--;
+       er_idx += (reg1->idx / 6) * 5;
+
+       er = &box->shared_regs[er_idx];
+       if (idx == 2 || idx == 3)
+               atomic_sub(1 << ((idx - 2) * 8), &er->ref);
+       else
+               atomic_dec(&er->ref);
+
+       reg1->alloc = 0;
 }
 
-static void nhm_uncore_msr_enable_event(struct intel_uncore_box *box,
-                                       struct perf_event *event)
+static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
 {
        struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+       int port, idx;
 
-       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
-               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
-       else
-               wrmsrl(hwc->config_base, NHM_UNC_FIXED_CTR_CTL_EN);
+       idx = (event->hw.config & NHMEX_R_PMON_CTL_EV_SEL_MASK) >>
+               NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
+       if (idx >= 0x18)
+               return -EINVAL;
+
+       reg1->idx = idx;
+       reg1->config = event->attr.config1;
+
+       port = idx / 6 + box->pmu->pmu_idx * 4;
+       idx %= 6;
+       switch (idx) {
+       case 0:
+               reg1->reg = NHMEX_R_MSR_PORTN_IPERF_CFG0(port);
+               break;
+       case 1:
+               reg1->reg = NHMEX_R_MSR_PORTN_IPERF_CFG1(port);
+               break;
+       case 2:
+       case 3:
+               reg1->reg = NHMEX_R_MSR_PORTN_QLX_CFG(port);
+               break;
+       case 4:
+       case 5:
+               if (idx == 4)
+                       reg1->reg = NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port);
+               else
+                       reg1->reg = NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port);
+               reg2->config = event->attr.config2;
+               hwc->config |= event->attr.config & (~0ULL << 32);
+               break;
+       };
+       return 0;
 }
 
-static struct attribute *nhm_uncore_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_cmask8.attr,
+static u64 nhmex_rbox_shared_reg_config(struct intel_uncore_box *box, int idx)
+{
+       struct intel_uncore_extra_reg *er;
+       unsigned long flags;
+       u64 config;
+
+       er = &box->shared_regs[idx];
+
+       raw_spin_lock_irqsave(&er->lock, flags);
+       config = er->config;
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+
+       return config;
+}
+
+static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+       int idx, er_idx;
+
+       idx = reg1->idx % 6;
+       er_idx = idx;
+       if (er_idx > 2)
+               er_idx--;
+       er_idx += (reg1->idx / 6) * 5;
+
+       switch (idx) {
+       case 0:
+       case 1:
+               wrmsrl(reg1->reg, reg1->config);
+               break;
+       case 2:
+       case 3:
+               wrmsrl(reg1->reg, nhmex_rbox_shared_reg_config(box, er_idx));
+               break;
+       case 4:
+       case 5:
+               wrmsrl(reg1->reg, reg1->config);
+               wrmsrl(reg1->reg + 1, hwc->config >> 32);
+               wrmsrl(reg1->reg + 2, reg2->config);
+               break;
+       };
+
+       wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
+               (hwc->config & NHMEX_R_PMON_CTL_EV_SEL_MASK));
+}
+
+DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config:32-63");
+DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config1:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(xbr_mask, xbr_mask, "config2:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(qlx_cfg, qlx_cfg, "config1:0-15");
+DEFINE_UNCORE_FORMAT_ATTR(iperf_cfg, iperf_cfg, "config1:0-31");
+
+static struct attribute *nhmex_uncore_rbox_formats_attr[] = {
+       &format_attr_event5.attr,
+       &format_attr_xbr_mm_cfg.attr,
+       &format_attr_xbr_match.attr,
+       &format_attr_xbr_mask.attr,
+       &format_attr_qlx_cfg.attr,
+       &format_attr_iperf_cfg.attr,
        NULL,
 };
 
-static struct attribute_group nhm_uncore_format_group = {
+static struct attribute_group nhmex_uncore_rbox_format_group = {
        .name = "format",
-       .attrs = nhm_uncore_formats_attr,
+       .attrs = nhmex_uncore_rbox_formats_attr,
 };
 
-static struct uncore_event_desc nhm_uncore_events[] = {
-       INTEL_UNCORE_EVENT_DESC(clockticks,                "event=0xff,umask=0x00"),
-       INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any,       "event=0x2f,umask=0x0f"),
-       INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any,      "event=0x2c,umask=0x0f"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads,     "event=0x20,umask=0x01"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes,    "event=0x20,umask=0x02"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads,  "event=0x20,umask=0x04"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads,   "event=0x20,umask=0x10"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes,  "event=0x20,umask=0x20"),
+static struct uncore_event_desc nhmex_uncore_rbox_events[] = {
+       INTEL_UNCORE_EVENT_DESC(qpi0_flit_send,         "event=0x0,iperf_cfg=0x80000000"),
+       INTEL_UNCORE_EVENT_DESC(qpi1_filt_send,         "event=0x6,iperf_cfg=0x80000000"),
+       INTEL_UNCORE_EVENT_DESC(qpi0_idle_filt,         "event=0x0,iperf_cfg=0x40000000"),
+       INTEL_UNCORE_EVENT_DESC(qpi1_idle_filt,         "event=0x6,iperf_cfg=0x40000000"),
+       INTEL_UNCORE_EVENT_DESC(qpi0_date_response,     "event=0x0,iperf_cfg=0xc4"),
+       INTEL_UNCORE_EVENT_DESC(qpi1_date_response,     "event=0x6,iperf_cfg=0xc4"),
        { /* end: all zeroes */ },
 };
 
-static struct intel_uncore_ops nhm_uncore_msr_ops = {
-       .disable_box    = nhm_uncore_msr_disable_box,
-       .enable_box     = nhm_uncore_msr_enable_box,
-       .disable_event  = snb_uncore_msr_disable_event,
-       .enable_event   = nhm_uncore_msr_enable_event,
-       .read_counter   = snb_uncore_msr_read_counter,
+static struct intel_uncore_ops nhmex_uncore_rbox_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event           = nhmex_rbox_msr_enable_event,
+       .hw_config              = nhmex_rbox_hw_config,
+       .get_constraint         = nhmex_rbox_get_constraint,
+       .put_constraint         = nhmex_rbox_put_constraint,
 };
 
-static struct intel_uncore_type nhm_uncore = {
-       .name           = "",
-       .num_counters   = 8,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 48,
-       .fixed_ctr_bits = 48,
-       .event_ctl      = NHM_UNC_PERFEVTSEL0,
-       .perf_ctr       = NHM_UNC_UNCORE_PMC0,
-       .fixed_ctr      = NHM_UNC_FIXED_CTR,
-       .fixed_ctl      = NHM_UNC_FIXED_CTR_CTRL,
-       .event_mask     = NHM_UNC_RAW_EVENT_MASK,
-       .event_descs    = nhm_uncore_events,
-       .ops            = &nhm_uncore_msr_ops,
-       .format_group   = &nhm_uncore_format_group,
+static struct intel_uncore_type nhmex_uncore_rbox = {
+       .name                   = "rbox",
+       .num_counters           = 8,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_R_MSR_PMON_CTL0,
+       .perf_ctr               = NHMEX_R_MSR_PMON_CNT0,
+       .event_mask             = NHMEX_R_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_R_MSR_GLOBAL_CTL,
+       .msr_offset             = NHMEX_R_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .num_shared_regs        = 20,
+       .event_descs            = nhmex_uncore_rbox_events,
+       .ops                    = &nhmex_uncore_rbox_ops,
+       .format_group           = &nhmex_uncore_rbox_format_group
 };
 
-static struct intel_uncore_type *nhm_msr_uncores[] = {
-       &nhm_uncore,
+static struct intel_uncore_type *nhmex_msr_uncores[] = {
+       &nhmex_uncore_ubox,
+       &nhmex_uncore_cbox,
+       &nhmex_uncore_bbox,
+       &nhmex_uncore_sbox,
+       &nhmex_uncore_mbox,
+       &nhmex_uncore_rbox,
+       &nhmex_uncore_wbox,
        NULL,
 };
-/* end of Nehalem uncore support */
+/* end of Nehalem-EX uncore support */
 
-static void uncore_assign_hw_event(struct intel_uncore_box *box,
-                               struct perf_event *event, int idx)
+static void uncore_assign_hw_event(struct intel_uncore_box *box, struct perf_event *event, int idx)
 {
        struct hw_perf_event *hwc = &event->hw;
 
@@ -787,8 +1841,7 @@ static void uncore_assign_hw_event(struct intel_uncore_box *box,
        hwc->event_base  = uncore_perf_ctr(box, hwc->idx);
 }
 
-static void uncore_perf_event_update(struct intel_uncore_box *box,
-                                       struct perf_event *event)
+static void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event)
 {
        u64 prev_count, new_count, delta;
        int shift;
@@ -858,14 +1911,12 @@ static void uncore_pmu_init_hrtimer(struct intel_uncore_box *box)
        box->hrtimer.function = uncore_pmu_hrtimer;
 }
 
-struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type,
-                                         int cpu)
+struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type, int cpu)
 {
        struct intel_uncore_box *box;
        int i, size;
 
-       size = sizeof(*box) + type->num_shared_regs *
-               sizeof(struct intel_uncore_extra_reg);
+       size = sizeof(*box) + type->num_shared_regs * sizeof(struct intel_uncore_extra_reg);
 
        box = kmalloc_node(size, GFP_KERNEL | __GFP_ZERO, cpu_to_node(cpu));
        if (!box)
@@ -915,12 +1966,11 @@ static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
         * perf core schedules event on the basis of cpu, uncore events are
         * collected by one of the cpus inside a physical package.
         */
-       return uncore_pmu_to_box(uncore_event_to_pmu(event),
-                                smp_processor_id());
+       return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
 }
 
-static int uncore_collect_events(struct intel_uncore_box *box,
-                               struct perf_event *leader, bool dogrp)
+static int
+uncore_collect_events(struct intel_uncore_box *box, struct perf_event *leader, bool dogrp)
 {
        struct perf_event *event;
        int n, max_count;
@@ -952,8 +2002,7 @@ static int uncore_collect_events(struct intel_uncore_box *box,
 }
 
 static struct event_constraint *
-uncore_get_event_constraint(struct intel_uncore_box *box,
-                           struct perf_event *event)
+uncore_get_event_constraint(struct intel_uncore_box *box, struct perf_event *event)
 {
        struct intel_uncore_type *type = box->pmu->type;
        struct event_constraint *c;
@@ -977,15 +2026,13 @@ uncore_get_event_constraint(struct intel_uncore_box *box,
        return &type->unconstrainted;
 }
 
-static void uncore_put_event_constraint(struct intel_uncore_box *box,
-                                       struct perf_event *event)
+static void uncore_put_event_constraint(struct intel_uncore_box *box, struct perf_event *event)
 {
        if (box->pmu->type->ops->put_constraint)
                box->pmu->type->ops->put_constraint(box, event);
 }
 
-static int uncore_assign_events(struct intel_uncore_box *box,
-                               int assign[], int n)
+static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int n)
 {
        unsigned long used_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)];
        struct event_constraint *c, *constraints[UNCORE_PMC_IDX_MAX];
@@ -1407,8 +2454,7 @@ static bool pcidrv_registered;
 /*
  * add a pci uncore device
  */
-static int __devinit uncore_pci_add(struct intel_uncore_type *type,
-                                   struct pci_dev *pdev)
+static int __devinit uncore_pci_add(struct intel_uncore_type *type, struct pci_dev *pdev)
 {
        struct intel_uncore_pmu *pmu;
        struct intel_uncore_box *box;
@@ -1485,6 +2531,7 @@ static int __devinit uncore_pci_probe(struct pci_dev *pdev,
        struct intel_uncore_type *type;
 
        type = (struct intel_uncore_type *)id->driver_data;
+
        return uncore_pci_add(type, pdev);
 }
 
@@ -1612,8 +2659,8 @@ static int __cpuinit uncore_cpu_prepare(int cpu, int phys_id)
        return 0;
 }
 
-static void __cpuinit uncore_change_context(struct intel_uncore_type **uncores,
-                                           int old_cpu, int new_cpu)
+static void __cpuinit
+uncore_change_context(struct intel_uncore_type **uncores, int old_cpu, int new_cpu)
 {
        struct intel_uncore_type *type;
        struct intel_uncore_pmu *pmu;
@@ -1694,8 +2741,8 @@ static void __cpuinit uncore_event_init_cpu(int cpu)
        uncore_change_context(pci_uncores, -1, cpu);
 }
 
-static int __cpuinit uncore_cpu_notifier(struct notifier_block *self,
                                       unsigned long action, void *hcpu)
+static int
__cpuinit uncore_cpu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
 {
        unsigned int cpu = (long)hcpu;
 
@@ -1732,12 +2779,12 @@ static int __cpuinit uncore_cpu_notifier(struct notifier_block *self,
 }
 
 static struct notifier_block uncore_cpu_nb __cpuinitdata = {
-       .notifier_call = uncore_cpu_notifier,
+       .notifier_call  = uncore_cpu_notifier,
        /*
         * to migrate uncore events, our notifier should be executed
         * before perf core's notifier.
         */
-       .priority = CPU_PRI_PERF + 1,
+       .priority       = CPU_PRI_PERF + 1,
 };
 
 static void __init uncore_cpu_setup(void *dummy)
@@ -1767,6 +2814,9 @@ static int __init uncore_cpu_init(void)
                        snbep_uncore_cbox.num_boxes = max_cores;
                msr_uncores = snbep_msr_uncores;
                break;
+       case 46:
+               msr_uncores = nhmex_msr_uncores;
+               break;
        default:
                return 0;
        }
index b13e9ea81def5684aadfa70a34e1e21f98a2af56..f3851892e0770c540c9df3a7da4925da9ecf2198 100644 (file)
@@ -5,8 +5,6 @@
 #include "perf_event.h"
 
 #define UNCORE_PMU_NAME_LEN            32
-#define UNCORE_BOX_HASH_SIZE           8
-
 #define UNCORE_PMU_HRTIMER_INTERVAL    (60 * NSEC_PER_SEC)
 
 #define UNCORE_FIXED_EVENT             0xff
                                 SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
                                 SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
 
+#define SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK      \
+                               (SNBEP_PMON_RAW_EVENT_MASK | \
+                                SNBEP_PMON_CTL_EV_SEL_EXT)
+
 /* SNB-EP pci control register */
 #define SNBEP_PCI_PMON_BOX_CTL                 0xf4
 #define SNBEP_PCI_PMON_CTL0                    0xd8
 #define SNBEP_PCU_MSR_CORE_C3_CTR              0x3fc
 #define SNBEP_PCU_MSR_CORE_C6_CTR              0x3fd
 
+/* NHM-EX event control */
+#define NHMEX_PMON_CTL_EV_SEL_MASK     0x000000ff
+#define NHMEX_PMON_CTL_UMASK_MASK      0x0000ff00
+#define NHMEX_PMON_CTL_EN_BIT0         (1 << 0)
+#define NHMEX_PMON_CTL_EDGE_DET                (1 << 18)
+#define NHMEX_PMON_CTL_PMI_EN          (1 << 20)
+#define NHMEX_PMON_CTL_EN_BIT22                (1 << 22)
+#define NHMEX_PMON_CTL_INVERT          (1 << 23)
+#define NHMEX_PMON_CTL_TRESH_MASK      0xff000000
+#define NHMEX_PMON_RAW_EVENT_MASK      (NHMEX_PMON_CTL_EV_SEL_MASK | \
+                                        NHMEX_PMON_CTL_UMASK_MASK | \
+                                        NHMEX_PMON_CTL_EDGE_DET | \
+                                        NHMEX_PMON_CTL_INVERT | \
+                                        NHMEX_PMON_CTL_TRESH_MASK)
+
+/* NHM-EX Ubox */
+#define NHMEX_U_MSR_PMON_GLOBAL_CTL            0xc00
+#define NHMEX_U_MSR_PMON_CTR                   0xc11
+#define NHMEX_U_MSR_PMON_EV_SEL                        0xc10
+
+#define NHMEX_U_PMON_GLOBAL_EN                 (1 << 0)
+#define NHMEX_U_PMON_GLOBAL_PMI_CORE_SEL       0x0000001e
+#define NHMEX_U_PMON_GLOBAL_EN_ALL             (1 << 28)
+#define NHMEX_U_PMON_GLOBAL_RST_ALL            (1 << 29)
+#define NHMEX_U_PMON_GLOBAL_FRZ_ALL            (1 << 31)
+
+#define NHMEX_U_PMON_RAW_EVENT_MASK            \
+               (NHMEX_PMON_CTL_EV_SEL_MASK |   \
+                NHMEX_PMON_CTL_EDGE_DET)
+
+/* NHM-EX Cbox */
+#define NHMEX_C0_MSR_PMON_GLOBAL_CTL           0xd00
+#define NHMEX_C0_MSR_PMON_CTR0                 0xd11
+#define NHMEX_C0_MSR_PMON_EV_SEL0              0xd10
+#define NHMEX_C_MSR_OFFSET                     0x20
+
+/* NHM-EX Bbox */
+#define NHMEX_B0_MSR_PMON_GLOBAL_CTL           0xc20
+#define NHMEX_B0_MSR_PMON_CTR0                 0xc31
+#define NHMEX_B0_MSR_PMON_CTL0                 0xc30
+#define NHMEX_B_MSR_OFFSET                     0x40
+#define NHMEX_B0_MSR_MATCH                     0xe45
+#define NHMEX_B0_MSR_MASK                      0xe46
+#define NHMEX_B1_MSR_MATCH                     0xe4d
+#define NHMEX_B1_MSR_MASK                      0xe4e
+
+#define NHMEX_B_PMON_CTL_EN                    (1 << 0)
+#define NHMEX_B_PMON_CTL_EV_SEL_SHIFT          1
+#define NHMEX_B_PMON_CTL_EV_SEL_MASK           \
+               (0x1f << NHMEX_B_PMON_CTL_EV_SEL_SHIFT)
+#define NHMEX_B_PMON_CTR_SHIFT         6
+#define NHMEX_B_PMON_CTR_MASK          \
+               (0x3 << NHMEX_B_PMON_CTR_SHIFT)
+#define NHMEX_B_PMON_RAW_EVENT_MASK            \
+               (NHMEX_B_PMON_CTL_EV_SEL_MASK | \
+                NHMEX_B_PMON_CTR_MASK)
+
+/* NHM-EX Sbox */
+#define NHMEX_S0_MSR_PMON_GLOBAL_CTL           0xc40
+#define NHMEX_S0_MSR_PMON_CTR0                 0xc51
+#define NHMEX_S0_MSR_PMON_CTL0                 0xc50
+#define NHMEX_S_MSR_OFFSET                     0x80
+#define NHMEX_S0_MSR_MM_CFG                    0xe48
+#define NHMEX_S0_MSR_MATCH                     0xe49
+#define NHMEX_S0_MSR_MASK                      0xe4a
+#define NHMEX_S1_MSR_MM_CFG                    0xe58
+#define NHMEX_S1_MSR_MATCH                     0xe59
+#define NHMEX_S1_MSR_MASK                      0xe5a
+
+#define NHMEX_S_PMON_MM_CFG_EN                 (0x1ULL << 63)
+
+/* NHM-EX Mbox */
+#define NHMEX_M0_MSR_GLOBAL_CTL                        0xca0
+#define NHMEX_M0_MSR_PMU_DSP                   0xca5
+#define NHMEX_M0_MSR_PMU_ISS                   0xca6
+#define NHMEX_M0_MSR_PMU_MAP                   0xca7
+#define NHMEX_M0_MSR_PMU_MSC_THR               0xca8
+#define NHMEX_M0_MSR_PMU_PGT                   0xca9
+#define NHMEX_M0_MSR_PMU_PLD                   0xcaa
+#define NHMEX_M0_MSR_PMU_ZDP_CTL_FVC           0xcab
+#define NHMEX_M0_MSR_PMU_CTL0                  0xcb0
+#define NHMEX_M0_MSR_PMU_CNT0                  0xcb1
+#define NHMEX_M_MSR_OFFSET                     0x40
+#define NHMEX_M0_MSR_PMU_MM_CFG                        0xe54
+#define NHMEX_M1_MSR_PMU_MM_CFG                        0xe5c
+
+#define NHMEX_M_PMON_MM_CFG_EN                 (1ULL << 63)
+#define NHMEX_M_PMON_ADDR_MATCH_MASK           0x3ffffffffULL
+#define NHMEX_M_PMON_ADDR_MASK_MASK            0x7ffffffULL
+#define NHMEX_M_PMON_ADDR_MASK_SHIFT           34
+
+#define NHMEX_M_PMON_CTL_EN                    (1 << 0)
+#define NHMEX_M_PMON_CTL_PMI_EN                        (1 << 1)
+#define NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT      2
+#define NHMEX_M_PMON_CTL_COUNT_MODE_MASK       \
+       (0x3 << NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT)
+#define NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT    4
+#define NHMEX_M_PMON_CTL_STORAGE_MODE_MASK     \
+       (0x3 << NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT)
+#define NHMEX_M_PMON_CTL_WRAP_MODE             (1 << 6)
+#define NHMEX_M_PMON_CTL_FLAG_MODE             (1 << 7)
+#define NHMEX_M_PMON_CTL_INC_SEL_SHIFT         9
+#define NHMEX_M_PMON_CTL_INC_SEL_MASK          \
+       (0x1f << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
+#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT    19
+#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK     \
+       (0x7 << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT)
+#define NHMEX_M_PMON_RAW_EVENT_MASK                    \
+               (NHMEX_M_PMON_CTL_COUNT_MODE_MASK |     \
+                NHMEX_M_PMON_CTL_STORAGE_MODE_MASK |   \
+                NHMEX_M_PMON_CTL_WRAP_MODE |           \
+                NHMEX_M_PMON_CTL_FLAG_MODE |           \
+                NHMEX_M_PMON_CTL_INC_SEL_MASK |        \
+                NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK)
+
+
+#define NHMEX_M_PMON_ZDP_CTL_FVC_FVID_MASK     0x1f
+#define NHMEX_M_PMON_ZDP_CTL_FVC_BCMD_MASK     (0x7 << 5)
+#define NHMEX_M_PMON_ZDP_CTL_FVC_RSP_MASK      (0x7 << 8)
+#define NHMEX_M_PMON_ZDP_CTL_FVC_PBOX_INIT_ERR (1 << 23)
+#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK                  \
+               (NHMEX_M_PMON_ZDP_CTL_FVC_FVID_MASK |   \
+                NHMEX_M_PMON_ZDP_CTL_FVC_BCMD_MASK |   \
+                NHMEX_M_PMON_ZDP_CTL_FVC_RSP_MASK  |   \
+                NHMEX_M_PMON_ZDP_CTL_FVC_PBOX_INIT_ERR)
+#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7 << (11 + 3 * (n)))
+
+/*
+ * use the 9~13 bits to select event If the 7th bit is not set,
+ * otherwise use the 19~21 bits to select event.
+ */
+#define MBOX_INC_SEL(x) ((x) << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
+#define MBOX_SET_FLAG_SEL(x) (((x) << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT) | \
+                               NHMEX_M_PMON_CTL_FLAG_MODE)
+#define MBOX_INC_SEL_MASK (NHMEX_M_PMON_CTL_INC_SEL_MASK | \
+                          NHMEX_M_PMON_CTL_FLAG_MODE)
+#define MBOX_SET_FLAG_SEL_MASK (NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK | \
+                               NHMEX_M_PMON_CTL_FLAG_MODE)
+#define MBOX_INC_SEL_EXTAR_REG(c, r) \
+               EVENT_EXTRA_REG(MBOX_INC_SEL(c), NHMEX_M0_MSR_PMU_##r, \
+                               MBOX_INC_SEL_MASK, (u64)-1, NHMEX_M_##r)
+#define MBOX_SET_FLAG_SEL_EXTRA_REG(c, r) \
+               EVENT_EXTRA_REG(MBOX_SET_FLAG_SEL(c), NHMEX_M0_MSR_PMU_##r, \
+                               MBOX_SET_FLAG_SEL_MASK, \
+                               (u64)-1, NHMEX_M_##r)
+
+/* NHM-EX Rbox */
+#define NHMEX_R_MSR_GLOBAL_CTL                 0xe00
+#define NHMEX_R_MSR_PMON_CTL0                  0xe10
+#define NHMEX_R_MSR_PMON_CNT0                  0xe11
+#define NHMEX_R_MSR_OFFSET                     0x20
+
+#define NHMEX_R_MSR_PORTN_QLX_CFG(n)           \
+               ((n) < 4 ? (0xe0c + (n)) : (0xe2c + (n) - 4))
+#define NHMEX_R_MSR_PORTN_IPERF_CFG0(n)                (0xe04 + (n))
+#define NHMEX_R_MSR_PORTN_IPERF_CFG1(n)                (0xe24 + (n))
+#define NHMEX_R_MSR_PORTN_XBR_OFFSET(n)                \
+               (((n) < 4 ? 0 : 0x10) + (n) * 4)
+#define NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n)   \
+               (0xe60 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
+#define NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(n)    \
+               (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 1)
+#define NHMEX_R_MSR_PORTN_XBR_SET1_MASK(n)     \
+               (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 2)
+#define NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n)   \
+               (0xe70 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
+#define NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(n)    \
+               (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 1)
+#define NHMEX_R_MSR_PORTN_XBR_SET2_MASK(n)     \
+               (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 2)
+
+#define NHMEX_R_PMON_CTL_EN                    (1 << 0)
+#define NHMEX_R_PMON_CTL_EV_SEL_SHIFT          1
+#define NHMEX_R_PMON_CTL_EV_SEL_MASK           \
+               (0x1f << NHMEX_R_PMON_CTL_EV_SEL_SHIFT)
+#define NHMEX_R_PMON_CTL_PMI_EN                        (1 << 6)
+#define NHMEX_R_PMON_RAW_EVENT_MASK            NHMEX_R_PMON_CTL_EV_SEL_MASK
+
+/* NHM-EX Wbox */
+#define NHMEX_W_MSR_GLOBAL_CTL                 0xc80
+#define NHMEX_W_MSR_PMON_CNT0                  0xc90
+#define NHMEX_W_MSR_PMON_EVT_SEL0              0xc91
+#define NHMEX_W_MSR_PMON_FIXED_CTR             0x394
+#define NHMEX_W_MSR_PMON_FIXED_CTL             0x395
+
+#define NHMEX_W_PMON_GLOBAL_FIXED_EN           (1ULL << 31)
+
 struct intel_uncore_ops;
 struct intel_uncore_pmu;
 struct intel_uncore_box;
@@ -178,6 +367,7 @@ struct intel_uncore_type {
        unsigned msr_offset;
        unsigned num_shared_regs:8;
        unsigned single_fixed:1;
+       unsigned pair_ctr_ctl:1;
        struct event_constraint unconstrainted;
        struct event_constraint *constraints;
        struct intel_uncore_pmu *pmus;
@@ -213,7 +403,7 @@ struct intel_uncore_pmu {
 
 struct intel_uncore_extra_reg {
        raw_spinlock_t lock;
-       u64 config1;
+       u64 config, config1, config2;
        atomic_t ref;
 };
 
@@ -323,14 +513,16 @@ unsigned uncore_msr_fixed_ctr(struct intel_uncore_box *box)
 static inline
 unsigned uncore_msr_event_ctl(struct intel_uncore_box *box, int idx)
 {
-       return idx + box->pmu->type->event_ctl +
+       return box->pmu->type->event_ctl +
+               (box->pmu->type->pair_ctr_ctl ? 2 * idx : idx) +
                box->pmu->type->msr_offset * box->pmu->pmu_idx;
 }
 
 static inline
 unsigned uncore_msr_perf_ctr(struct intel_uncore_box *box, int idx)
 {
-       return idx + box->pmu->type->perf_ctr +
+       return box->pmu->type->perf_ctr +
+               (box->pmu->type->pair_ctr_ctl ? 2 * idx : idx) +
                box->pmu->type->msr_offset * box->pmu->pmu_idx;
 }
 
@@ -422,3 +614,8 @@ static inline void uncore_box_init(struct intel_uncore_box *box)
                        box->pmu->type->ops->init_box(box);
        }
 }
+
+static inline bool uncore_box_is_fake(struct intel_uncore_box *box)
+{
+       return (box->phys_id < 0);
+}
index 41857970517f795739018c01e1fc070f0a831fff..ed858e9e9a7461aa9b4f8aa42a52c79d57d84507 100644 (file)
@@ -944,7 +944,7 @@ void __init e820_reserve_resources(void)
        for (i = 0; i < e820_saved.nr_map; i++) {
                struct e820entry *entry = &e820_saved.map[i];
                firmware_map_add_early(entry->addr,
-                       entry->addr + entry->size - 1,
+                       entry->addr + entry->size,
                        e820_type_to_string(entry->type));
        }
 }
diff --git a/arch/xtensa/include/asm/cpumask.h b/arch/xtensa/include/asm/cpumask.h
deleted file mode 100644 (file)
index ebeede3..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * include/asm-xtensa/cpumask.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_CPUMASK_H
-#define _XTENSA_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _XTENSA_CPUMASK_H */
diff --git a/arch/xtensa/include/asm/rmap.h b/arch/xtensa/include/asm/rmap.h
deleted file mode 100644 (file)
index 649588b..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * include/asm-xtensa/rmap.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_RMAP_H
-#define _XTENSA_RMAP_H
-
-#include <asm-generic/rmap.h>
-
-#endif
index 816e6d0d686c6f934bae7de3786ee4fc463ac567..05b3f093d5d7cd09435c0395cf5a20e0a07e26ec 100644 (file)
@@ -44,7 +44,7 @@ asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
        unsigned long ret;
        long err;
 
-       err = do_shmat(shmid, shmaddr, shmflg, &ret);
+       err = do_shmat(shmid, shmaddr, shmflg, &ret, SHMLBA);
        if (err)
                return err;
        return (long)ret;
index b17885a0b508fe82e84b012b89539caf3862dfed..5a74c53bc69c132cfad6231d9294e49f5cedef93 100644 (file)
@@ -44,6 +44,7 @@ void do_page_fault(struct pt_regs *regs)
 
        int is_write, is_exec;
        int fault;
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        info.si_code = SEGV_MAPERR;
 
@@ -71,6 +72,7 @@ void do_page_fault(struct pt_regs *regs)
               address, exccause, regs->pc, is_write? "w":"", is_exec? "x":"");
 #endif
 
+retry:
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
 
@@ -93,6 +95,7 @@ good_area:
        if (is_write) {
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
+               flags |= FAULT_FLAG_WRITE;
        } else if (is_exec) {
                if (!(vma->vm_flags & VM_EXEC))
                        goto bad_area;
@@ -104,7 +107,11 @@ good_area:
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0);
+       fault = handle_mm_fault(mm, vma, address, flags);
+
+       if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+               return;
+
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
@@ -112,10 +119,22 @@ good_area:
                        goto do_sigbus;
                BUG();
        }
-       if (fault & VM_FAULT_MAJOR)
-               current->maj_flt++;
-       else
-               current->min_flt++;
+       if (flags & FAULT_FLAG_ALLOW_RETRY) {
+               if (fault & VM_FAULT_MAJOR)
+                       current->maj_flt++;
+               else
+                       current->min_flt++;
+               if (fault & VM_FAULT_RETRY) {
+                       flags &= ~FAULT_FLAG_ALLOW_RETRY;
+
+                        /* No need to up_read(&mm->mmap_sem) as we would
+                        * have already released it in __lock_page_or_retry
+                        * in mm/filemap.c.
+                        */
+
+                       goto retry;
+               }
+       }
 
        up_read(&mm->mmap_sem);
        return;
index bfc918633fd9275f856d53e280fae9be2f8ba698..805c432c94393753557de06d61a007c15c2b7844 100644 (file)
@@ -148,4 +148,6 @@ source "drivers/iio/Kconfig"
 
 source "drivers/vme/Kconfig"
 
+source "drivers/pwm/Kconfig"
+
 endmenu
index 2ba29ffef2cbd84ff0a55d66a861ab3eee2159fa..bd36f09f22467cabbc615a6e9bb6ede08c4a0528 100644 (file)
@@ -8,6 +8,7 @@
 # GPIO must come after pinctrl as gpios may need to mux pins etc
 obj-y                          += pinctrl/
 obj-y                          += gpio/
+obj-y                          += pwm/
 obj-$(CONFIG_PCI)              += pci/
 obj-$(CONFIG_PARISC)           += parisc/
 obj-$(CONFIG_RAPIDIO)          += rapidio/
index 45d8097ef4cf0d0aae43e8e0a3576613ca90fdd8..b728880ef10e92d4baac018babd1b515c9c06f5f 100644 (file)
@@ -132,6 +132,33 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
        return AE_OK;
 }
 
+/* Force to use vendor driver when the ACPI device is known to be
+ * buggy */
+static int video_detect_force_vendor(const struct dmi_system_id *d)
+{
+       acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
+       return 0;
+}
+
+static struct dmi_system_id video_detect_dmi_table[] = {
+       /* On Samsung X360, the BIOS will set a flag (VDRV) if generic
+        * ACPI backlight device is used. This flag will definitively break
+        * the backlight interface (even the vendor interface) untill next
+        * reboot. It's why we should prevent video.ko from being used here
+        * and we can't rely on a later call to acpi_video_unregister().
+        */
+       {
+        .callback = video_detect_force_vendor,
+        .ident = "X360",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
+               DMI_MATCH(DMI_BOARD_NAME, "X360"),
+               },
+       },
+       { },
+};
+
 /*
  * Returns the video capabilities of a specific ACPI graphics device
  *
@@ -164,6 +191,8 @@ long acpi_video_get_capabilities(acpi_handle graphics_handle)
                 *              ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
                 *}
                 */
+
+               dmi_check_system(video_detect_dmi_table);
        } else {
                status = acpi_bus_get_device(graphics_handle, &tmp_dev);
                if (ACPI_FAILURE(status)) {
@@ -182,8 +211,7 @@ long acpi_video_get_capabilities(acpi_handle graphics_handle)
 }
 EXPORT_SYMBOL(acpi_video_get_capabilities);
 
-/* Returns true if video.ko can do backlight switching */
-int acpi_video_backlight_support(void)
+static void acpi_video_caps_check(void)
 {
        /*
         * We must check whether the ACPI graphics device is physically plugged
@@ -191,6 +219,34 @@ int acpi_video_backlight_support(void)
         */
        if (!acpi_video_caps_checked)
                acpi_video_get_capabilities(NULL);
+}
+
+/* Promote the vendor interface instead of the generic video module.
+ * This function allow DMI blacklists to be implemented by externals
+ * platform drivers instead of putting a big blacklist in video_detect.c
+ * After calling this function you will probably want to call
+ * acpi_video_unregister() to make sure the video module is not loaded
+ */
+void acpi_video_dmi_promote_vendor(void)
+{
+       acpi_video_caps_check();
+       acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
+}
+EXPORT_SYMBOL(acpi_video_dmi_promote_vendor);
+
+/* To be called when a driver who previously promoted the vendor
+ * interface */
+void acpi_video_dmi_demote_vendor(void)
+{
+       acpi_video_caps_check();
+       acpi_video_support &= ~ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
+}
+EXPORT_SYMBOL(acpi_video_dmi_demote_vendor);
+
+/* Returns true if video.ko can do backlight switching */
+int acpi_video_backlight_support(void)
+{
+       acpi_video_caps_check();
 
        /* First check for boot param -> highest prio */
        if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR)
index ac6a5beb28f3b99e090f358257ef161476113c32..bfaa5cb1629ae8651f111c46d0e78b694072aac1 100644 (file)
 struct arasan_cf_dev {
        /* pointer to ata_host structure */
        struct ata_host *host;
-       /* clk structure, only if HAVE_CLK is defined */
-#ifdef CONFIG_HAVE_CLK
+       /* clk structure */
        struct clk *clk;
-#endif
 
        /* physical base address of controller */
        dma_addr_t pbase;
@@ -312,13 +310,11 @@ static int cf_init(struct arasan_cf_dev *acdev)
        unsigned long flags;
        int ret = 0;
 
-#ifdef CONFIG_HAVE_CLK
        ret = clk_enable(acdev->clk);
        if (ret) {
                dev_dbg(acdev->host->dev, "clock enable failed");
                return ret;
        }
-#endif
 
        spin_lock_irqsave(&acdev->host->lock, flags);
        /* configure CF interface clock */
@@ -344,9 +340,7 @@ static void cf_exit(struct arasan_cf_dev *acdev)
        writel(readl(acdev->vbase + OP_MODE) & ~CFHOST_ENB,
                        acdev->vbase + OP_MODE);
        spin_unlock_irqrestore(&acdev->host->lock, flags);
-#ifdef CONFIG_HAVE_CLK
        clk_disable(acdev->clk);
-#endif
 }
 
 static void dma_callback(void *dev)
@@ -828,13 +822,11 @@ static int __devinit arasan_cf_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-#ifdef CONFIG_HAVE_CLK
        acdev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(acdev->clk)) {
                dev_warn(&pdev->dev, "Clock not found\n");
                return PTR_ERR(acdev->clk);
        }
-#endif
 
        /* allocate host */
        host = ata_host_alloc(&pdev->dev, 1);
@@ -899,9 +891,7 @@ static int __devinit arasan_cf_probe(struct platform_device *pdev)
                        &arasan_cf_sht);
 
 free_clk:
-#ifdef CONFIG_HAVE_CLK
        clk_put(acdev->clk);
-#endif
        return ret;
 }
 
@@ -912,9 +902,7 @@ static int __devexit arasan_cf_remove(struct platform_device *pdev)
 
        ata_host_detach(host);
        cf_exit(acdev);
-#ifdef CONFIG_HAVE_CLK
        clk_put(acdev->clk);
-#endif
 
        return 0;
 }
index 6f3676f1559f173b7767a2bdda577df2292ef461..3fbedc75e7c56219d1f0eafeabdebe9e058edc27 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
 #include <linux/gfp.h>
+#include <asm-generic/dma-coherent.h>
 
 /*
  * Managed DMA API
@@ -217,4 +218,52 @@ void dmam_release_declared_memory(struct device *dev)
 }
 EXPORT_SYMBOL(dmam_release_declared_memory);
 
+/*
+ * Create scatter-list for the already allocated DMA buffer.
+ */
+int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
+                void *cpu_addr, dma_addr_t handle, size_t size)
+{
+       struct page *page = virt_to_page(cpu_addr);
+       int ret;
+
+       ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
+       if (unlikely(ret))
+               return ret;
+
+       sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
+       return 0;
+}
+EXPORT_SYMBOL(dma_common_get_sgtable);
+
 #endif
+
+/*
+ * Create userspace mapping for the DMA-coherent memory.
+ */
+int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+                   void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+       int ret = -ENXIO;
+#ifdef CONFIG_MMU
+       unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+       unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
+       unsigned long off = vma->vm_pgoff;
+
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+               return ret;
+
+       if (off < count && user_count <= (count - off)) {
+               ret = remap_pfn_range(vma, vma->vm_start,
+                                     pfn + off,
+                                     user_count << PAGE_SHIFT,
+                                     vma->vm_page_prot);
+       }
+#endif /* CONFIG_MMU */
+
+       return ret;
+}
+EXPORT_SYMBOL(dma_common_mmap);
index 8f428a8ab003d8c7a029036eea6a1666a96d7dd3..9917943a3572ef577ac7a511ef375d11dae08350 100644 (file)
@@ -55,8 +55,6 @@
 
 #define RBD_MINORS_PER_MAJOR   256             /* max minors per blkdev */
 
-#define RBD_MAX_MD_NAME_LEN    (RBD_MAX_OBJ_NAME_LEN + sizeof(RBD_SUFFIX))
-#define RBD_MAX_POOL_NAME_LEN  64
 #define RBD_MAX_SNAP_NAME_LEN  32
 #define RBD_MAX_OPT_LEN                1024
 
  */
 struct rbd_image_header {
        u64 image_size;
-       char block_name[32];
+       char *object_prefix;
        __u8 obj_order;
        __u8 crypt_type;
        __u8 comp_type;
        struct ceph_snap_context *snapc;
        size_t snap_names_len;
-       u64 snap_seq;
        u32 total_snaps;
 
        char *snap_names;
@@ -150,7 +147,7 @@ struct rbd_snap {
  * a single device
  */
 struct rbd_device {
-       int                     id;             /* blkdev unique id */
+       int                     dev_id;         /* blkdev unique id */
 
        int                     major;          /* blkdev assigned major */
        struct gendisk          *disk;          /* blkdev's gendisk and rq */
@@ -163,20 +160,24 @@ struct rbd_device {
        spinlock_t              lock;           /* queue lock */
 
        struct rbd_image_header header;
-       char                    obj[RBD_MAX_OBJ_NAME_LEN]; /* rbd image name */
-       int                     obj_len;
-       char                    obj_md_name[RBD_MAX_MD_NAME_LEN]; /* hdr nm. */
-       char                    pool_name[RBD_MAX_POOL_NAME_LEN];
-       int                     poolid;
+       char                    *image_name;
+       size_t                  image_name_len;
+       char                    *header_name;
+       char                    *pool_name;
+       int                     pool_id;
 
        struct ceph_osd_event   *watch_event;
        struct ceph_osd_request *watch_request;
 
        /* protects updating the header */
        struct rw_semaphore     header_rwsem;
-       char                    snap_name[RBD_MAX_SNAP_NAME_LEN];
+       /* name of the snapshot this device reads from */
+       char                    *snap_name;
+       /* id of the snapshot this device reads from */
        u64                     snap_id;        /* current snapshot id */
-       int read_only;
+       /* whether the snap_id this device reads from still exists */
+       bool                    snap_exists;
+       int                     read_only;
 
        struct list_head        node;
 
@@ -201,8 +202,7 @@ static ssize_t rbd_snap_add(struct device *dev,
                            struct device_attribute *attr,
                            const char *buf,
                            size_t count);
-static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev,
-                                 struct rbd_snap *snap);
+static void __rbd_remove_snap_dev(struct rbd_snap *snap);
 
 static ssize_t rbd_add(struct bus_type *bus, const char *buf,
                       size_t count);
@@ -240,7 +240,7 @@ static void rbd_put_dev(struct rbd_device *rbd_dev)
        put_device(&rbd_dev->dev);
 }
 
-static int __rbd_refresh_header(struct rbd_device *rbd_dev);
+static int rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver);
 
 static int rbd_open(struct block_device *bdev, fmode_t mode)
 {
@@ -273,9 +273,9 @@ static const struct block_device_operations rbd_bd_ops = {
 
 /*
  * Initialize an rbd client instance.
- * We own *opt.
+ * We own *ceph_opts.
  */
-static struct rbd_client *rbd_client_create(struct ceph_options *opt,
+static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts,
                                            struct rbd_options *rbd_opts)
 {
        struct rbd_client *rbdc;
@@ -291,10 +291,10 @@ static struct rbd_client *rbd_client_create(struct ceph_options *opt,
 
        mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
 
-       rbdc->client = ceph_create_client(opt, rbdc, 0, 0);
+       rbdc->client = ceph_create_client(ceph_opts, rbdc, 0, 0);
        if (IS_ERR(rbdc->client))
                goto out_mutex;
-       opt = NULL; /* Now rbdc->client is responsible for opt */
+       ceph_opts = NULL; /* Now rbdc->client is responsible for ceph_opts */
 
        ret = ceph_open_session(rbdc->client);
        if (ret < 0)
@@ -317,23 +317,23 @@ out_mutex:
        mutex_unlock(&ctl_mutex);
        kfree(rbdc);
 out_opt:
-       if (opt)
-               ceph_destroy_options(opt);
+       if (ceph_opts)
+               ceph_destroy_options(ceph_opts);
        return ERR_PTR(ret);
 }
 
 /*
  * Find a ceph client with specific addr and configuration.
  */
-static struct rbd_client *__rbd_client_find(struct ceph_options *opt)
+static struct rbd_client *__rbd_client_find(struct ceph_options *ceph_opts)
 {
        struct rbd_client *client_node;
 
-       if (opt->flags & CEPH_OPT_NOSHARE)
+       if (ceph_opts->flags & CEPH_OPT_NOSHARE)
                return NULL;
 
        list_for_each_entry(client_node, &rbd_client_list, node)
-               if (ceph_compare_options(opt, client_node->client) == 0)
+               if (!ceph_compare_options(ceph_opts, client_node->client))
                        return client_node;
        return NULL;
 }
@@ -349,7 +349,7 @@ enum {
        /* string args above */
 };
 
-static match_table_t rbdopt_tokens = {
+static match_table_t rbd_opts_tokens = {
        {Opt_notify_timeout, "notify_timeout=%d"},
        /* int args above */
        /* string args above */
@@ -358,11 +358,11 @@ static match_table_t rbdopt_tokens = {
 
 static int parse_rbd_opts_token(char *c, void *private)
 {
-       struct rbd_options *rbdopt = private;
+       struct rbd_options *rbd_opts = private;
        substring_t argstr[MAX_OPT_ARGS];
        int token, intval, ret;
 
-       token = match_token(c, rbdopt_tokens, argstr);
+       token = match_token(c, rbd_opts_tokens, argstr);
        if (token < 0)
                return -EINVAL;
 
@@ -383,7 +383,7 @@ static int parse_rbd_opts_token(char *c, void *private)
 
        switch (token) {
        case Opt_notify_timeout:
-               rbdopt->notify_timeout = intval;
+               rbd_opts->notify_timeout = intval;
                break;
        default:
                BUG_ON(token);
@@ -400,7 +400,7 @@ static struct rbd_client *rbd_get_client(const char *mon_addr,
                                         char *options)
 {
        struct rbd_client *rbdc;
-       struct ceph_options *opt;
+       struct ceph_options *ceph_opts;
        struct rbd_options *rbd_opts;
 
        rbd_opts = kzalloc(sizeof(*rbd_opts), GFP_KERNEL);
@@ -409,29 +409,29 @@ static struct rbd_client *rbd_get_client(const char *mon_addr,
 
        rbd_opts->notify_timeout = RBD_NOTIFY_TIMEOUT_DEFAULT;
 
-       opt = ceph_parse_options(options, mon_addr,
-                               mon_addr + mon_addr_len,
-                               parse_rbd_opts_token, rbd_opts);
-       if (IS_ERR(opt)) {
+       ceph_opts = ceph_parse_options(options, mon_addr,
+                                       mon_addr + mon_addr_len,
+                                       parse_rbd_opts_token, rbd_opts);
+       if (IS_ERR(ceph_opts)) {
                kfree(rbd_opts);
-               return ERR_CAST(opt);
+               return ERR_CAST(ceph_opts);
        }
 
        spin_lock(&rbd_client_list_lock);
-       rbdc = __rbd_client_find(opt);
+       rbdc = __rbd_client_find(ceph_opts);
        if (rbdc) {
                /* using an existing client */
                kref_get(&rbdc->kref);
                spin_unlock(&rbd_client_list_lock);
 
-               ceph_destroy_options(opt);
+               ceph_destroy_options(ceph_opts);
                kfree(rbd_opts);
 
                return rbdc;
        }
        spin_unlock(&rbd_client_list_lock);
 
-       rbdc = rbd_client_create(opt, rbd_opts);
+       rbdc = rbd_client_create(ceph_opts, rbd_opts);
 
        if (IS_ERR(rbdc))
                kfree(rbd_opts);
@@ -480,46 +480,60 @@ static void rbd_coll_release(struct kref *kref)
        kfree(coll);
 }
 
+static bool rbd_dev_ondisk_valid(struct rbd_image_header_ondisk *ondisk)
+{
+       return !memcmp(&ondisk->text,
+                       RBD_HEADER_TEXT, sizeof (RBD_HEADER_TEXT));
+}
+
 /*
  * Create a new header structure, translate header format from the on-disk
  * header.
  */
 static int rbd_header_from_disk(struct rbd_image_header *header,
                                 struct rbd_image_header_ondisk *ondisk,
-                                u32 allocated_snaps,
-                                gfp_t gfp_flags)
+                                u32 allocated_snaps)
 {
-       u32 i, snap_count;
+       u32 snap_count;
 
-       if (memcmp(ondisk, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT)))
+       if (!rbd_dev_ondisk_valid(ondisk))
                return -ENXIO;
 
        snap_count = le32_to_cpu(ondisk->snap_count);
-       if (snap_count > (UINT_MAX - sizeof(struct ceph_snap_context))
-                        / sizeof (*ondisk))
+       if (snap_count > (SIZE_MAX - sizeof(struct ceph_snap_context))
+                                / sizeof (u64))
                return -EINVAL;
        header->snapc = kmalloc(sizeof(struct ceph_snap_context) +
                                snap_count * sizeof(u64),
-                               gfp_flags);
+                               GFP_KERNEL);
        if (!header->snapc)
                return -ENOMEM;
 
-       header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
        if (snap_count) {
+               header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
                header->snap_names = kmalloc(header->snap_names_len,
-                                            gfp_flags);
+                                            GFP_KERNEL);
                if (!header->snap_names)
                        goto err_snapc;
                header->snap_sizes = kmalloc(snap_count * sizeof(u64),
-                                            gfp_flags);
+                                            GFP_KERNEL);
                if (!header->snap_sizes)
                        goto err_names;
        } else {
+               WARN_ON(ondisk->snap_names_len);
+               header->snap_names_len = 0;
                header->snap_names = NULL;
                header->snap_sizes = NULL;
        }
-       memcpy(header->block_name, ondisk->block_name,
+
+       header->object_prefix = kmalloc(sizeof (ondisk->block_name) + 1,
+                                       GFP_KERNEL);
+       if (!header->object_prefix)
+               goto err_sizes;
+
+       memcpy(header->object_prefix, ondisk->block_name,
               sizeof(ondisk->block_name));
+       header->object_prefix[sizeof (ondisk->block_name)] = '\0';
 
        header->image_size = le64_to_cpu(ondisk->image_size);
        header->obj_order = ondisk->options.order;
@@ -527,11 +541,13 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
        header->comp_type = ondisk->options.comp_type;
 
        atomic_set(&header->snapc->nref, 1);
-       header->snap_seq = le64_to_cpu(ondisk->snap_seq);
+       header->snapc->seq = le64_to_cpu(ondisk->snap_seq);
        header->snapc->num_snaps = snap_count;
        header->total_snaps = snap_count;
 
        if (snap_count && allocated_snaps == snap_count) {
+               int i;
+
                for (i = 0; i < snap_count; i++) {
                        header->snapc->snaps[i] =
                                le64_to_cpu(ondisk->snaps[i].id);
@@ -540,16 +556,22 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
                }
 
                /* copy snapshot names */
-               memcpy(header->snap_names, &ondisk->snaps[i],
+               memcpy(header->snap_names, &ondisk->snaps[snap_count],
                        header->snap_names_len);
        }
 
        return 0;
 
+err_sizes:
+       kfree(header->snap_sizes);
+       header->snap_sizes = NULL;
 err_names:
        kfree(header->snap_names);
+       header->snap_names = NULL;
 err_snapc:
        kfree(header->snapc);
+       header->snapc = NULL;
+
        return -ENOMEM;
 }
 
@@ -575,52 +597,50 @@ static int snap_by_name(struct rbd_image_header *header, const char *snap_name,
        return -ENOENT;
 }
 
-static int rbd_header_set_snap(struct rbd_device *dev, u64 *size)
+static int rbd_header_set_snap(struct rbd_device *rbd_dev, u64 *size)
 {
-       struct rbd_image_header *header = &dev->header;
-       struct ceph_snap_context *snapc = header->snapc;
-       int ret = -ENOENT;
-
-       BUILD_BUG_ON(sizeof (dev->snap_name) < sizeof (RBD_SNAP_HEAD_NAME));
+       int ret;
 
-       down_write(&dev->header_rwsem);
+       down_write(&rbd_dev->header_rwsem);
 
-       if (!memcmp(dev->snap_name, RBD_SNAP_HEAD_NAME,
+       if (!memcmp(rbd_dev->snap_name, RBD_SNAP_HEAD_NAME,
                    sizeof (RBD_SNAP_HEAD_NAME))) {
-               if (header->total_snaps)
-                       snapc->seq = header->snap_seq;
-               else
-                       snapc->seq = 0;
-               dev->snap_id = CEPH_NOSNAP;
-               dev->read_only = 0;
+               rbd_dev->snap_id = CEPH_NOSNAP;
+               rbd_dev->snap_exists = false;
+               rbd_dev->read_only = 0;
                if (size)
-                       *size = header->image_size;
+                       *size = rbd_dev->header.image_size;
        } else {
-               ret = snap_by_name(header, dev->snap_name, &snapc->seq, size);
+               u64 snap_id = 0;
+
+               ret = snap_by_name(&rbd_dev->header, rbd_dev->snap_name,
+                                       &snap_id, size);
                if (ret < 0)
                        goto done;
-               dev->snap_id = snapc->seq;
-               dev->read_only = 1;
+               rbd_dev->snap_id = snap_id;
+               rbd_dev->snap_exists = true;
+               rbd_dev->read_only = 1;
        }
 
        ret = 0;
 done:
-       up_write(&dev->header_rwsem);
+       up_write(&rbd_dev->header_rwsem);
        return ret;
 }
 
 static void rbd_header_free(struct rbd_image_header *header)
 {
-       kfree(header->snapc);
-       kfree(header->snap_names);
+       kfree(header->object_prefix);
        kfree(header->snap_sizes);
+       kfree(header->snap_names);
+       ceph_put_snap_context(header->snapc);
 }
 
 /*
  * get the actual striped segment name, offset and length
  */
 static u64 rbd_get_segment(struct rbd_image_header *header,
-                          const char *block_name,
+                          const char *object_prefix,
                           u64 ofs, u64 len,
                           char *seg_name, u64 *segofs)
 {
@@ -628,7 +648,7 @@ static u64 rbd_get_segment(struct rbd_image_header *header,
 
        if (seg_name)
                snprintf(seg_name, RBD_MAX_SEG_NAME_LEN,
-                        "%s.%012llx", block_name, seg);
+                        "%s.%012llx", object_prefix, seg);
 
        ofs = ofs & ((1 << header->obj_order) - 1);
        len = min_t(u64, len, (1 << header->obj_order) - ofs);
@@ -726,9 +746,8 @@ static struct bio *bio_chain_clone(struct bio **old, struct bio **next,
                         * split_bio will BUG_ON if this is not the case
                         */
                        dout("bio_chain_clone split! total=%d remaining=%d"
-                            "bi_size=%d\n",
-                            (int)total, (int)len-total,
-                            (int)old_chain->bi_size);
+                            "bi_size=%u\n",
+                            total, len - total, old_chain->bi_size);
 
                        /* split the bio. We'll release it either in the next
                           call, or it will have to be released outside */
@@ -777,22 +796,24 @@ err_out:
 /*
  * helpers for osd request op vectors.
  */
-static int rbd_create_rw_ops(struct ceph_osd_req_op **ops,
-                           int num_ops,
-                           int opcode,
-                           u32 payload_len)
-{
-       *ops = kzalloc(sizeof(struct ceph_osd_req_op) * (num_ops + 1),
-                      GFP_NOIO);
-       if (!*ops)
-               return -ENOMEM;
-       (*ops)[0].op = opcode;
+static struct ceph_osd_req_op *rbd_create_rw_ops(int num_ops,
+                                       int opcode, u32 payload_len)
+{
+       struct ceph_osd_req_op *ops;
+
+       ops = kzalloc(sizeof (*ops) * (num_ops + 1), GFP_NOIO);
+       if (!ops)
+               return NULL;
+
+       ops[0].op = opcode;
+
        /*
         * op extent offset and length will be set later on
         * in calc_raw_layout()
         */
-       (*ops)[0].payload_len = payload_len;
-       return 0;
+       ops[0].payload_len = payload_len;
+
+       return ops;
 }
 
 static void rbd_destroy_ops(struct ceph_osd_req_op *ops)
@@ -808,8 +829,8 @@ static void rbd_coll_end_req_index(struct request *rq,
        struct request_queue *q;
        int min, max, i;
 
-       dout("rbd_coll_end_req_index %p index %d ret %d len %lld\n",
-            coll, index, ret, len);
+       dout("rbd_coll_end_req_index %p index %d ret %d len %llu\n",
+            coll, index, ret, (unsigned long long) len);
 
        if (!rq)
                return;
@@ -848,16 +869,15 @@ static void rbd_coll_end_req(struct rbd_request *req,
  * Send ceph osd request
  */
 static int rbd_do_request(struct request *rq,
-                         struct rbd_device *dev,
+                         struct rbd_device *rbd_dev,
                          struct ceph_snap_context *snapc,
                          u64 snapid,
-                         const char *obj, u64 ofs, u64 len,
+                         const char *object_name, u64 ofs, u64 len,
                          struct bio *bio,
                          struct page **pages,
                          int num_pages,
                          int flags,
                          struct ceph_osd_req_op *ops,
-                         int num_reply,
                          struct rbd_req_coll *coll,
                          int coll_index,
                          void (*rbd_cb)(struct ceph_osd_request *req,
@@ -887,15 +907,13 @@ static int rbd_do_request(struct request *rq,
                req_data->coll_index = coll_index;
        }
 
-       dout("rbd_do_request obj=%s ofs=%lld len=%lld\n", obj, len, ofs);
-
-       down_read(&dev->header_rwsem);
+       dout("rbd_do_request object_name=%s ofs=%llu len=%llu\n", object_name,
+               (unsigned long long) ofs, (unsigned long long) len);
 
-       osdc = &dev->rbd_client->client->osdc;
+       osdc = &rbd_dev->rbd_client->client->osdc;
        req = ceph_osdc_alloc_request(osdc, flags, snapc, ops,
                                        false, GFP_NOIO, pages, bio);
        if (!req) {
-               up_read(&dev->header_rwsem);
                ret = -ENOMEM;
                goto done_pages;
        }
@@ -912,7 +930,7 @@ static int rbd_do_request(struct request *rq,
        reqhead = req->r_request->front.iov_base;
        reqhead->snapid = cpu_to_le64(CEPH_NOSNAP);
 
-       strncpy(req->r_oid, obj, sizeof(req->r_oid));
+       strncpy(req->r_oid, object_name, sizeof(req->r_oid));
        req->r_oid_len = strlen(req->r_oid);
 
        layout = &req->r_file_layout;
@@ -920,7 +938,7 @@ static int rbd_do_request(struct request *rq,
        layout->fl_stripe_unit = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
        layout->fl_stripe_count = cpu_to_le32(1);
        layout->fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
-       layout->fl_pg_pool = cpu_to_le32(dev->poolid);
+       layout->fl_pg_pool = cpu_to_le32(rbd_dev->pool_id);
        ceph_calc_raw_layout(osdc, layout, snapid, ofs, &len, &bno,
                                req, ops);
 
@@ -929,7 +947,6 @@ static int rbd_do_request(struct request *rq,
                                snapc,
                                &mtime,
                                req->r_oid, req->r_oid_len);
-       up_read(&dev->header_rwsem);
 
        if (linger_req) {
                ceph_osdc_set_request_linger(osdc, req);
@@ -944,8 +961,9 @@ static int rbd_do_request(struct request *rq,
                ret = ceph_osdc_wait_request(osdc, req);
                if (ver)
                        *ver = le64_to_cpu(req->r_reassert_version.version);
-               dout("reassert_ver=%lld\n",
-                    le64_to_cpu(req->r_reassert_version.version));
+               dout("reassert_ver=%llu\n",
+                       (unsigned long long)
+                               le64_to_cpu(req->r_reassert_version.version));
                ceph_osdc_put_request(req);
        }
        return ret;
@@ -979,7 +997,8 @@ static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg)
        bytes = le64_to_cpu(op->extent.length);
        read_op = (le16_to_cpu(op->op) == CEPH_OSD_OP_READ);
 
-       dout("rbd_req_cb bytes=%lld readop=%d rc=%d\n", bytes, read_op, rc);
+       dout("rbd_req_cb bytes=%llu readop=%d rc=%d\n",
+               (unsigned long long) bytes, read_op, (int) rc);
 
        if (rc == -ENOENT && read_op) {
                zero_bio_chain(req_data->bio, 0);
@@ -1006,14 +1025,12 @@ static void rbd_simple_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg
 /*
  * Do a synchronous ceph osd operation
  */
-static int rbd_req_sync_op(struct rbd_device *dev,
+static int rbd_req_sync_op(struct rbd_device *rbd_dev,
                           struct ceph_snap_context *snapc,
                           u64 snapid,
-                          int opcode,
                           int flags,
-                          struct ceph_osd_req_op *orig_ops,
-                          int num_reply,
-                          const char *obj,
+                          struct ceph_osd_req_op *ops,
+                          const char *object_name,
                           u64 ofs, u64 len,
                           char *buf,
                           struct ceph_osd_request **linger_req,
@@ -1022,45 +1039,28 @@ static int rbd_req_sync_op(struct rbd_device *dev,
        int ret;
        struct page **pages;
        int num_pages;
-       struct ceph_osd_req_op *ops = orig_ops;
-       u32 payload_len;
+
+       BUG_ON(ops == NULL);
 
        num_pages = calc_pages_for(ofs , len);
        pages = ceph_alloc_page_vector(num_pages, GFP_KERNEL);
        if (IS_ERR(pages))
                return PTR_ERR(pages);
 
-       if (!orig_ops) {
-               payload_len = (flags & CEPH_OSD_FLAG_WRITE ? len : 0);
-               ret = rbd_create_rw_ops(&ops, 1, opcode, payload_len);
-               if (ret < 0)
-                       goto done;
-
-               if ((flags & CEPH_OSD_FLAG_WRITE) && buf) {
-                       ret = ceph_copy_to_page_vector(pages, buf, ofs, len);
-                       if (ret < 0)
-                               goto done_ops;
-               }
-       }
-
-       ret = rbd_do_request(NULL, dev, snapc, snapid,
-                         obj, ofs, len, NULL,
+       ret = rbd_do_request(NULL, rbd_dev, snapc, snapid,
+                         object_name, ofs, len, NULL,
                          pages, num_pages,
                          flags,
                          ops,
-                         2,
                          NULL, 0,
                          NULL,
                          linger_req, ver);
        if (ret < 0)
-               goto done_ops;
+               goto done;
 
        if ((flags & CEPH_OSD_FLAG_READ) && buf)
                ret = ceph_copy_from_page_vector(pages, buf, ofs, ret);
 
-done_ops:
-       if (!orig_ops)
-               rbd_destroy_ops(ops);
 done:
        ceph_release_page_vector(pages, num_pages);
        return ret;
@@ -1070,10 +1070,10 @@ done:
  * Do an asynchronous ceph osd operation
  */
 static int rbd_do_op(struct request *rq,
-                    struct rbd_device *rbd_dev ,
+                    struct rbd_device *rbd_dev,
                     struct ceph_snap_context *snapc,
                     u64 snapid,
-                    int opcode, int flags, int num_reply,
+                    int opcode, int flags,
                     u64 ofs, u64 len,
                     struct bio *bio,
                     struct rbd_req_coll *coll,
@@ -1091,14 +1091,15 @@ static int rbd_do_op(struct request *rq,
                return -ENOMEM;
 
        seg_len = rbd_get_segment(&rbd_dev->header,
-                                 rbd_dev->header.block_name,
+                                 rbd_dev->header.object_prefix,
                                  ofs, len,
                                  seg_name, &seg_ofs);
 
        payload_len = (flags & CEPH_OSD_FLAG_WRITE ? seg_len : 0);
 
-       ret = rbd_create_rw_ops(&ops, 1, opcode, payload_len);
-       if (ret < 0)
+       ret = -ENOMEM;
+       ops = rbd_create_rw_ops(1, opcode, payload_len);
+       if (!ops)
                goto done;
 
        /* we've taken care of segment sizes earlier when we
@@ -1112,7 +1113,6 @@ static int rbd_do_op(struct request *rq,
                             NULL, 0,
                             flags,
                             ops,
-                            num_reply,
                             coll, coll_index,
                             rbd_req_cb, 0, NULL);
 
@@ -1136,7 +1136,6 @@ static int rbd_req_write(struct request *rq,
        return rbd_do_op(rq, rbd_dev, snapc, CEPH_NOSNAP,
                         CEPH_OSD_OP_WRITE,
                         CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
-                        2,
                         ofs, len, bio, coll, coll_index);
 }
 
@@ -1155,55 +1154,58 @@ static int rbd_req_read(struct request *rq,
                         snapid,
                         CEPH_OSD_OP_READ,
                         CEPH_OSD_FLAG_READ,
-                        2,
                         ofs, len, bio, coll, coll_index);
 }
 
 /*
  * Request sync osd read
  */
-static int rbd_req_sync_read(struct rbd_device *dev,
-                         struct ceph_snap_context *snapc,
+static int rbd_req_sync_read(struct rbd_device *rbd_dev,
                          u64 snapid,
-                         const char *obj,
+                         const char *object_name,
                          u64 ofs, u64 len,
                          char *buf,
                          u64 *ver)
 {
-       return rbd_req_sync_op(dev, NULL,
+       struct ceph_osd_req_op *ops;
+       int ret;
+
+       ops = rbd_create_rw_ops(1, CEPH_OSD_OP_READ, 0);
+       if (!ops)
+               return -ENOMEM;
+
+       ret = rbd_req_sync_op(rbd_dev, NULL,
                               snapid,
-                              CEPH_OSD_OP_READ,
                               CEPH_OSD_FLAG_READ,
-                              NULL,
-                              1, obj, ofs, len, buf, NULL, ver);
+                              ops, object_name, ofs, len, buf, NULL, ver);
+       rbd_destroy_ops(ops);
+
+       return ret;
 }
 
 /*
  * Request sync osd watch
  */
-static int rbd_req_sync_notify_ack(struct rbd_device *dev,
+static int rbd_req_sync_notify_ack(struct rbd_device *rbd_dev,
                                   u64 ver,
-                                  u64 notify_id,
-                                  const char *obj)
+                                  u64 notify_id)
 {
        struct ceph_osd_req_op *ops;
-       struct page **pages = NULL;
        int ret;
 
-       ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY_ACK, 0);
-       if (ret < 0)
-               return ret;
+       ops = rbd_create_rw_ops(1, CEPH_OSD_OP_NOTIFY_ACK, 0);
+       if (!ops)
+               return -ENOMEM;
 
-       ops[0].watch.ver = cpu_to_le64(dev->header.obj_version);
+       ops[0].watch.ver = cpu_to_le64(ver);
        ops[0].watch.cookie = notify_id;
        ops[0].watch.flag = 0;
 
-       ret = rbd_do_request(NULL, dev, NULL, CEPH_NOSNAP,
-                         obj, 0, 0, NULL,
-                         pages, 0,
+       ret = rbd_do_request(NULL, rbd_dev, NULL, CEPH_NOSNAP,
+                         rbd_dev->header_name, 0, 0, NULL,
+                         NULL, 0,
                          CEPH_OSD_FLAG_READ,
                          ops,
-                         1,
                          NULL, 0,
                          rbd_simple_req_cb, 0, NULL);
 
@@ -1213,54 +1215,53 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev,
 
 static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
 {
-       struct rbd_device *dev = (struct rbd_device *)data;
+       struct rbd_device *rbd_dev = (struct rbd_device *)data;
+       u64 hver;
        int rc;
 
-       if (!dev)
+       if (!rbd_dev)
                return;
 
-       dout("rbd_watch_cb %s notify_id=%lld opcode=%d\n", dev->obj_md_name,
-               notify_id, (int)opcode);
-       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-       rc = __rbd_refresh_header(dev);
-       mutex_unlock(&ctl_mutex);
+       dout("rbd_watch_cb %s notify_id=%llu opcode=%u\n",
+               rbd_dev->header_name, (unsigned long long) notify_id,
+               (unsigned int) opcode);
+       rc = rbd_refresh_header(rbd_dev, &hver);
        if (rc)
                pr_warning(RBD_DRV_NAME "%d got notification but failed to "
-                          " update snaps: %d\n", dev->major, rc);
+                          " update snaps: %d\n", rbd_dev->major, rc);
 
-       rbd_req_sync_notify_ack(dev, ver, notify_id, dev->obj_md_name);
+       rbd_req_sync_notify_ack(rbd_dev, hver, notify_id);
 }
 
 /*
  * Request sync osd watch
  */
-static int rbd_req_sync_watch(struct rbd_device *dev,
-                             const char *obj,
-                             u64 ver)
+static int rbd_req_sync_watch(struct rbd_device *rbd_dev)
 {
        struct ceph_osd_req_op *ops;
-       struct ceph_osd_client *osdc = &dev->rbd_client->client->osdc;
+       struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+       int ret;
 
-       int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_WATCH, 0);
-       if (ret < 0)
-               return ret;
+       ops = rbd_create_rw_ops(1, CEPH_OSD_OP_WATCH, 0);
+       if (!ops)
+               return -ENOMEM;
 
        ret = ceph_osdc_create_event(osdc, rbd_watch_cb, 0,
-                                    (void *)dev, &dev->watch_event);
+                                    (void *)rbd_dev, &rbd_dev->watch_event);
        if (ret < 0)
                goto fail;
 
-       ops[0].watch.ver = cpu_to_le64(ver);
-       ops[0].watch.cookie = cpu_to_le64(dev->watch_event->cookie);
+       ops[0].watch.ver = cpu_to_le64(rbd_dev->header.obj_version);
+       ops[0].watch.cookie = cpu_to_le64(rbd_dev->watch_event->cookie);
        ops[0].watch.flag = 1;
 
-       ret = rbd_req_sync_op(dev, NULL,
+       ret = rbd_req_sync_op(rbd_dev, NULL,
                              CEPH_NOSNAP,
-                             0,
                              CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
                              ops,
-                             1, obj, 0, 0, NULL,
-                             &dev->watch_request, NULL);
+                             rbd_dev->header_name,
+                             0, 0, NULL,
+                             &rbd_dev->watch_request, NULL);
 
        if (ret < 0)
                goto fail_event;
@@ -1269,8 +1270,8 @@ static int rbd_req_sync_watch(struct rbd_device *dev,
        return 0;
 
 fail_event:
-       ceph_osdc_cancel_event(dev->watch_event);
-       dev->watch_event = NULL;
+       ceph_osdc_cancel_event(rbd_dev->watch_event);
+       rbd_dev->watch_event = NULL;
 fail:
        rbd_destroy_ops(ops);
        return ret;
@@ -1279,64 +1280,65 @@ fail:
 /*
  * Request sync osd unwatch
  */
-static int rbd_req_sync_unwatch(struct rbd_device *dev,
-                               const char *obj)
+static int rbd_req_sync_unwatch(struct rbd_device *rbd_dev)
 {
        struct ceph_osd_req_op *ops;
+       int ret;
 
-       int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_WATCH, 0);
-       if (ret < 0)
-               return ret;
+       ops = rbd_create_rw_ops(1, CEPH_OSD_OP_WATCH, 0);
+       if (!ops)
+               return -ENOMEM;
 
        ops[0].watch.ver = 0;
-       ops[0].watch.cookie = cpu_to_le64(dev->watch_event->cookie);
+       ops[0].watch.cookie = cpu_to_le64(rbd_dev->watch_event->cookie);
        ops[0].watch.flag = 0;
 
-       ret = rbd_req_sync_op(dev, NULL,
+       ret = rbd_req_sync_op(rbd_dev, NULL,
                              CEPH_NOSNAP,
-                             0,
                              CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
                              ops,
-                             1, obj, 0, 0, NULL, NULL, NULL);
+                             rbd_dev->header_name,
+                             0, 0, NULL, NULL, NULL);
+
 
        rbd_destroy_ops(ops);
-       ceph_osdc_cancel_event(dev->watch_event);
-       dev->watch_event = NULL;
+       ceph_osdc_cancel_event(rbd_dev->watch_event);
+       rbd_dev->watch_event = NULL;
        return ret;
 }
 
 struct rbd_notify_info {
-       struct rbd_device *dev;
+       struct rbd_device *rbd_dev;
 };
 
 static void rbd_notify_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
 {
-       struct rbd_device *dev = (struct rbd_device *)data;
-       if (!dev)
+       struct rbd_device *rbd_dev = (struct rbd_device *)data;
+       if (!rbd_dev)
                return;
 
-       dout("rbd_notify_cb %s notify_id=%lld opcode=%d\n", dev->obj_md_name,
-               notify_id, (int)opcode);
+       dout("rbd_notify_cb %s notify_id=%llu opcode=%u\n",
+                       rbd_dev->header_name, (unsigned long long) notify_id,
+                       (unsigned int) opcode);
 }
 
 /*
  * Request sync osd notify
  */
-static int rbd_req_sync_notify(struct rbd_device *dev,
-                         const char *obj)
+static int rbd_req_sync_notify(struct rbd_device *rbd_dev)
 {
        struct ceph_osd_req_op *ops;
-       struct ceph_osd_client *osdc = &dev->rbd_client->client->osdc;
+       struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
        struct ceph_osd_event *event;
        struct rbd_notify_info info;
        int payload_len = sizeof(u32) + sizeof(u32);
        int ret;
 
-       ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY, payload_len);
-       if (ret < 0)
-               return ret;
+       ops = rbd_create_rw_ops(1, CEPH_OSD_OP_NOTIFY, payload_len);
+       if (!ops)
+               return -ENOMEM;
 
-       info.dev = dev;
+       info.rbd_dev = rbd_dev;
 
        ret = ceph_osdc_create_event(osdc, rbd_notify_cb, 1,
                                     (void *)&info, &event);
@@ -1349,12 +1351,12 @@ static int rbd_req_sync_notify(struct rbd_device *dev,
        ops[0].watch.prot_ver = RADOS_NOTIFY_VER;
        ops[0].watch.timeout = 12;
 
-       ret = rbd_req_sync_op(dev, NULL,
+       ret = rbd_req_sync_op(rbd_dev, NULL,
                               CEPH_NOSNAP,
-                              0,
                               CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
                               ops,
-                              1, obj, 0, 0, NULL, NULL, NULL);
+                              rbd_dev->header_name,
+                              0, 0, NULL, NULL, NULL);
        if (ret < 0)
                goto fail_event;
 
@@ -1373,36 +1375,37 @@ fail:
 /*
  * Request sync osd read
  */
-static int rbd_req_sync_exec(struct rbd_device *dev,
-                            const char *obj,
-                            const char *cls,
-                            const char *method,
+static int rbd_req_sync_exec(struct rbd_device *rbd_dev,
+                            const char *object_name,
+                            const char *class_name,
+                            const char *method_name,
                             const char *data,
                             int len,
                             u64 *ver)
 {
        struct ceph_osd_req_op *ops;
-       int cls_len = strlen(cls);
-       int method_len = strlen(method);
-       int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_CALL,
-                                   cls_len + method_len + len);
-       if (ret < 0)
-               return ret;
+       int class_name_len = strlen(class_name);
+       int method_name_len = strlen(method_name);
+       int ret;
 
-       ops[0].cls.class_name = cls;
-       ops[0].cls.class_len = (__u8)cls_len;
-       ops[0].cls.method_name = method;
-       ops[0].cls.method_len = (__u8)method_len;
+       ops = rbd_create_rw_ops(1, CEPH_OSD_OP_CALL,
+                                   class_name_len + method_name_len + len);
+       if (!ops)
+               return -ENOMEM;
+
+       ops[0].cls.class_name = class_name;
+       ops[0].cls.class_len = (__u8) class_name_len;
+       ops[0].cls.method_name = method_name;
+       ops[0].cls.method_len = (__u8) method_name_len;
        ops[0].cls.argc = 0;
        ops[0].cls.indata = data;
        ops[0].cls.indata_len = len;
 
-       ret = rbd_req_sync_op(dev, NULL,
+       ret = rbd_req_sync_op(rbd_dev, NULL,
                               CEPH_NOSNAP,
-                              0,
                               CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
                               ops,
-                              1, obj, 0, 0, NULL, NULL, ver);
+                              object_name, 0, 0, NULL, NULL, ver);
 
        rbd_destroy_ops(ops);
 
@@ -1437,10 +1440,12 @@ static void rbd_rq_fn(struct request_queue *q)
                struct bio *bio;
                struct bio *rq_bio, *next_bio = NULL;
                bool do_write;
-               int size, op_size = 0;
+               unsigned int size;
+               u64 op_size = 0;
                u64 ofs;
                int num_segs, cur_seg = 0;
                struct rbd_req_coll *coll;
+               struct ceph_snap_context *snapc;
 
                /* peek at request from block layer */
                if (!rq)
@@ -1467,23 +1472,38 @@ static void rbd_rq_fn(struct request_queue *q)
 
                spin_unlock_irq(q->queue_lock);
 
+               down_read(&rbd_dev->header_rwsem);
+
+               if (rbd_dev->snap_id != CEPH_NOSNAP && !rbd_dev->snap_exists) {
+                       up_read(&rbd_dev->header_rwsem);
+                       dout("request for non-existent snapshot");
+                       spin_lock_irq(q->queue_lock);
+                       __blk_end_request_all(rq, -ENXIO);
+                       continue;
+               }
+
+               snapc = ceph_get_snap_context(rbd_dev->header.snapc);
+
+               up_read(&rbd_dev->header_rwsem);
+
                dout("%s 0x%x bytes at 0x%llx\n",
                     do_write ? "write" : "read",
-                    size, blk_rq_pos(rq) * SECTOR_SIZE);
+                    size, (unsigned long long) blk_rq_pos(rq) * SECTOR_SIZE);
 
                num_segs = rbd_get_num_segments(&rbd_dev->header, ofs, size);
                coll = rbd_alloc_coll(num_segs);
                if (!coll) {
                        spin_lock_irq(q->queue_lock);
                        __blk_end_request_all(rq, -ENOMEM);
+                       ceph_put_snap_context(snapc);
                        continue;
                }
 
                do {
                        /* a bio clone to be passed down to OSD req */
-                       dout("rq->bio->bi_vcnt=%d\n", rq->bio->bi_vcnt);
+                       dout("rq->bio->bi_vcnt=%hu\n", rq->bio->bi_vcnt);
                        op_size = rbd_get_segment(&rbd_dev->header,
-                                                 rbd_dev->header.block_name,
+                                                 rbd_dev->header.object_prefix,
                                                  ofs, size,
                                                  NULL, NULL);
                        kref_get(&coll->kref);
@@ -1499,7 +1519,7 @@ static void rbd_rq_fn(struct request_queue *q)
                        /* init OSD command: write or read */
                        if (do_write)
                                rbd_req_write(rq, rbd_dev,
-                                             rbd_dev->header.snapc,
+                                             snapc,
                                              ofs,
                                              op_size, bio,
                                              coll, cur_seg);
@@ -1522,6 +1542,8 @@ next_seg:
                if (bp)
                        bio_pair_release(bp);
                spin_lock_irq(q->queue_lock);
+
+               ceph_put_snap_context(snapc);
        }
 }
 
@@ -1592,18 +1614,19 @@ static int rbd_read_header(struct rbd_device *rbd_dev,
                        return -ENOMEM;
 
                rc = rbd_req_sync_read(rbd_dev,
-                                      NULL, CEPH_NOSNAP,
-                                      rbd_dev->obj_md_name,
+                                      CEPH_NOSNAP,
+                                      rbd_dev->header_name,
                                       0, len,
                                       (char *)dh, &ver);
                if (rc < 0)
                        goto out_dh;
 
-               rc = rbd_header_from_disk(header, dh, snap_count, GFP_KERNEL);
+               rc = rbd_header_from_disk(header, dh, snap_count);
                if (rc < 0) {
                        if (rc == -ENXIO)
                                pr_warning("unrecognized header format"
-                                          " for image %s", rbd_dev->obj);
+                                          " for image %s\n",
+                                          rbd_dev->image_name);
                        goto out_dh;
                }
 
@@ -1628,7 +1651,7 @@ out_dh:
 /*
  * create a snapshot
  */
-static int rbd_header_add_snap(struct rbd_device *dev,
+static int rbd_header_add_snap(struct rbd_device *rbd_dev,
                               const char *snap_name,
                               gfp_t gfp_flags)
 {
@@ -1636,16 +1659,15 @@ static int rbd_header_add_snap(struct rbd_device *dev,
        u64 new_snapid;
        int ret;
        void *data, *p, *e;
-       u64 ver;
        struct ceph_mon_client *monc;
 
        /* we should create a snapshot only if we're pointing at the head */
-       if (dev->snap_id != CEPH_NOSNAP)
+       if (rbd_dev->snap_id != CEPH_NOSNAP)
                return -EINVAL;
 
-       monc = &dev->rbd_client->client->monc;
-       ret = ceph_monc_create_snapid(monc, dev->poolid, &new_snapid);
-       dout("created snapid=%lld\n", new_snapid);
+       monc = &rbd_dev->rbd_client->client->monc;
+       ret = ceph_monc_create_snapid(monc, rbd_dev->pool_id, &new_snapid);
+       dout("created snapid=%llu\n", (unsigned long long) new_snapid);
        if (ret < 0)
                return ret;
 
@@ -1659,19 +1681,13 @@ static int rbd_header_add_snap(struct rbd_device *dev,
        ceph_encode_string_safe(&p, e, snap_name, name_len, bad);
        ceph_encode_64_safe(&p, e, new_snapid, bad);
 
-       ret = rbd_req_sync_exec(dev, dev->obj_md_name, "rbd", "snap_add",
-                               data, p - data, &ver);
+       ret = rbd_req_sync_exec(rbd_dev, rbd_dev->header_name,
+                               "rbd", "snap_add",
+                               data, p - data, NULL);
 
        kfree(data);
 
-       if (ret < 0)
-               return ret;
-
-       down_write(&dev->header_rwsem);
-       dev->header.snapc->seq = new_snapid;
-       up_write(&dev->header_rwsem);
-
-       return 0;
+       return ret < 0 ? ret : 0;
 bad:
        return -ERANGE;
 }
@@ -1679,52 +1695,52 @@ bad:
 static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev)
 {
        struct rbd_snap *snap;
+       struct rbd_snap *next;
 
-       while (!list_empty(&rbd_dev->snaps)) {
-               snap = list_first_entry(&rbd_dev->snaps, struct rbd_snap, node);
-               __rbd_remove_snap_dev(rbd_dev, snap);
-       }
+       list_for_each_entry_safe(snap, next, &rbd_dev->snaps, node)
+               __rbd_remove_snap_dev(snap);
 }
 
 /*
  * only read the first part of the ondisk header, without the snaps info
  */
-static int __rbd_refresh_header(struct rbd_device *rbd_dev)
+static int __rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver)
 {
        int ret;
        struct rbd_image_header h;
-       u64 snap_seq;
-       int follow_seq = 0;
 
        ret = rbd_read_header(rbd_dev, &h);
        if (ret < 0)
                return ret;
 
-       /* resized? */
-       set_capacity(rbd_dev->disk, h.image_size / SECTOR_SIZE);
-
        down_write(&rbd_dev->header_rwsem);
 
-       snap_seq = rbd_dev->header.snapc->seq;
-       if (rbd_dev->header.total_snaps &&
-           rbd_dev->header.snapc->snaps[0] == snap_seq)
-               /* pointing at the head, will need to follow that
-                  if head moves */
-               follow_seq = 1;
+       /* resized? */
+       if (rbd_dev->snap_id == CEPH_NOSNAP) {
+               sector_t size = (sector_t) h.image_size / SECTOR_SIZE;
 
-       kfree(rbd_dev->header.snapc);
-       kfree(rbd_dev->header.snap_names);
+               dout("setting size to %llu sectors", (unsigned long long) size);
+               set_capacity(rbd_dev->disk, size);
+       }
+
+       /* rbd_dev->header.object_prefix shouldn't change */
        kfree(rbd_dev->header.snap_sizes);
+       kfree(rbd_dev->header.snap_names);
+       /* osd requests may still refer to snapc */
+       ceph_put_snap_context(rbd_dev->header.snapc);
 
+       if (hver)
+               *hver = h.obj_version;
+       rbd_dev->header.obj_version = h.obj_version;
+       rbd_dev->header.image_size = h.image_size;
        rbd_dev->header.total_snaps = h.total_snaps;
        rbd_dev->header.snapc = h.snapc;
        rbd_dev->header.snap_names = h.snap_names;
        rbd_dev->header.snap_names_len = h.snap_names_len;
        rbd_dev->header.snap_sizes = h.snap_sizes;
-       if (follow_seq)
-               rbd_dev->header.snapc->seq = rbd_dev->header.snapc->snaps[0];
-       else
-               rbd_dev->header.snapc->seq = snap_seq;
+       /* Free the extra copy of the object prefix */
+       WARN_ON(strcmp(rbd_dev->header.object_prefix, h.object_prefix));
+       kfree(h.object_prefix);
 
        ret = __rbd_init_snaps_header(rbd_dev);
 
@@ -1733,6 +1749,17 @@ static int __rbd_refresh_header(struct rbd_device *rbd_dev)
        return ret;
 }
 
+static int rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver)
+{
+       int ret;
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+       ret = __rbd_refresh_header(rbd_dev, hver);
+       mutex_unlock(&ctl_mutex);
+
+       return ret;
+}
+
 static int rbd_init_disk(struct rbd_device *rbd_dev)
 {
        struct gendisk *disk;
@@ -1762,7 +1789,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
                goto out;
 
        snprintf(disk->disk_name, sizeof(disk->disk_name), RBD_DRV_NAME "%d",
-                rbd_dev->id);
+                rbd_dev->dev_id);
        disk->major = rbd_dev->major;
        disk->first_minor = 0;
        disk->fops = &rbd_bd_ops;
@@ -1819,8 +1846,13 @@ static ssize_t rbd_size_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
+       sector_t size;
+
+       down_read(&rbd_dev->header_rwsem);
+       size = get_capacity(rbd_dev->disk);
+       up_read(&rbd_dev->header_rwsem);
 
-       return sprintf(buf, "%llu\n", (unsigned long long)rbd_dev->header.image_size);
+       return sprintf(buf, "%llu\n", (unsigned long long) size * SECTOR_SIZE);
 }
 
 static ssize_t rbd_major_show(struct device *dev,
@@ -1848,12 +1880,20 @@ static ssize_t rbd_pool_show(struct device *dev,
        return sprintf(buf, "%s\n", rbd_dev->pool_name);
 }
 
+static ssize_t rbd_pool_id_show(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
+
+       return sprintf(buf, "%d\n", rbd_dev->pool_id);
+}
+
 static ssize_t rbd_name_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
-       return sprintf(buf, "%s\n", rbd_dev->obj);
+       return sprintf(buf, "%s\n", rbd_dev->image_name);
 }
 
 static ssize_t rbd_snap_show(struct device *dev,
@@ -1871,23 +1911,18 @@ static ssize_t rbd_image_refresh(struct device *dev,
                                 size_t size)
 {
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
-       int rc;
-       int ret = size;
-
-       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+       int ret;
 
-       rc = __rbd_refresh_header(rbd_dev);
-       if (rc < 0)
-               ret = rc;
+       ret = rbd_refresh_header(rbd_dev, NULL);
 
-       mutex_unlock(&ctl_mutex);
-       return ret;
+       return ret < 0 ? ret : size;
 }
 
 static DEVICE_ATTR(size, S_IRUGO, rbd_size_show, NULL);
 static DEVICE_ATTR(major, S_IRUGO, rbd_major_show, NULL);
 static DEVICE_ATTR(client_id, S_IRUGO, rbd_client_id_show, NULL);
 static DEVICE_ATTR(pool, S_IRUGO, rbd_pool_show, NULL);
+static DEVICE_ATTR(pool_id, S_IRUGO, rbd_pool_id_show, NULL);
 static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL);
 static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh);
 static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL);
@@ -1898,6 +1933,7 @@ static struct attribute *rbd_attrs[] = {
        &dev_attr_major.attr,
        &dev_attr_client_id.attr,
        &dev_attr_pool.attr,
+       &dev_attr_pool_id.attr,
        &dev_attr_name.attr,
        &dev_attr_current_snap.attr,
        &dev_attr_refresh.attr,
@@ -1977,15 +2013,13 @@ static struct device_type rbd_snap_device_type = {
        .release        = rbd_snap_dev_release,
 };
 
-static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev,
-                                 struct rbd_snap *snap)
+static void __rbd_remove_snap_dev(struct rbd_snap *snap)
 {
        list_del(&snap->node);
        device_unregister(&snap->dev);
 }
 
-static int rbd_register_snap_dev(struct rbd_device *rbd_dev,
-                                 struct rbd_snap *snap,
+static int rbd_register_snap_dev(struct rbd_snap *snap,
                                  struct device *parent)
 {
        struct device *dev = &snap->dev;
@@ -2000,29 +2034,36 @@ static int rbd_register_snap_dev(struct rbd_device *rbd_dev,
        return ret;
 }
 
-static int __rbd_add_snap_dev(struct rbd_device *rbd_dev,
-                             int i, const char *name,
-                             struct rbd_snap **snapp)
+static struct rbd_snap *__rbd_add_snap_dev(struct rbd_device *rbd_dev,
+                                             int i, const char *name)
 {
+       struct rbd_snap *snap;
        int ret;
-       struct rbd_snap *snap = kzalloc(sizeof(*snap), GFP_KERNEL);
+
+       snap = kzalloc(sizeof (*snap), GFP_KERNEL);
        if (!snap)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
+
+       ret = -ENOMEM;
        snap->name = kstrdup(name, GFP_KERNEL);
+       if (!snap->name)
+               goto err;
+
        snap->size = rbd_dev->header.snap_sizes[i];
        snap->id = rbd_dev->header.snapc->snaps[i];
        if (device_is_registered(&rbd_dev->dev)) {
-               ret = rbd_register_snap_dev(rbd_dev, snap,
-                                            &rbd_dev->dev);
+               ret = rbd_register_snap_dev(snap, &rbd_dev->dev);
                if (ret < 0)
                        goto err;
        }
-       *snapp = snap;
-       return 0;
+
+       return snap;
+
 err:
        kfree(snap->name);
        kfree(snap);
-       return ret;
+
+       return ERR_PTR(ret);
 }
 
 /*
@@ -2055,7 +2096,6 @@ static int __rbd_init_snaps_header(struct rbd_device *rbd_dev)
        const char *name, *first_name;
        int i = rbd_dev->header.total_snaps;
        struct rbd_snap *snap, *old_snap = NULL;
-       int ret;
        struct list_head *p, *n;
 
        first_name = rbd_dev->header.snap_names;
@@ -2070,8 +2110,15 @@ static int __rbd_init_snaps_header(struct rbd_device *rbd_dev)
                        cur_id = rbd_dev->header.snapc->snaps[i - 1];
 
                if (!i || old_snap->id < cur_id) {
-                       /* old_snap->id was skipped, thus was removed */
-                       __rbd_remove_snap_dev(rbd_dev, old_snap);
+                       /*
+                        * old_snap->id was skipped, thus was
+                        * removed.  If this rbd_dev is mapped to
+                        * the removed snapshot, record that it no
+                        * longer exists, to prevent further I/O.
+                        */
+                       if (rbd_dev->snap_id == old_snap->id)
+                               rbd_dev->snap_exists = false;
+                       __rbd_remove_snap_dev(old_snap);
                        continue;
                }
                if (old_snap->id == cur_id) {
@@ -2091,9 +2138,9 @@ static int __rbd_init_snaps_header(struct rbd_device *rbd_dev)
                        if (cur_id >= old_snap->id)
                                break;
                        /* a new snapshot */
-                       ret = __rbd_add_snap_dev(rbd_dev, i - 1, name, &snap);
-                       if (ret < 0)
-                               return ret;
+                       snap = __rbd_add_snap_dev(rbd_dev, i - 1, name);
+                       if (IS_ERR(snap))
+                               return PTR_ERR(snap);
 
                        /* note that we add it backward so using n and not p */
                        list_add(&snap->node, n);
@@ -2107,9 +2154,9 @@ static int __rbd_init_snaps_header(struct rbd_device *rbd_dev)
                        WARN_ON(1);
                        return -EINVAL;
                }
-               ret = __rbd_add_snap_dev(rbd_dev, i - 1, name, &snap);
-               if (ret < 0)
-                       return ret;
+               snap = __rbd_add_snap_dev(rbd_dev, i - 1, name);
+               if (IS_ERR(snap))
+                       return PTR_ERR(snap);
                list_add(&snap->node, &rbd_dev->snaps);
        }
 
@@ -2129,14 +2176,13 @@ static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
        dev->type = &rbd_device_type;
        dev->parent = &rbd_root_dev;
        dev->release = rbd_dev_release;
-       dev_set_name(dev, "%d", rbd_dev->id);
+       dev_set_name(dev, "%d", rbd_dev->dev_id);
        ret = device_register(dev);
        if (ret < 0)
                goto out;
 
        list_for_each_entry(snap, &rbd_dev->snaps, node) {
-               ret = rbd_register_snap_dev(rbd_dev, snap,
-                                            &rbd_dev->dev);
+               ret = rbd_register_snap_dev(snap, &rbd_dev->dev);
                if (ret < 0)
                        break;
        }
@@ -2155,12 +2201,9 @@ static int rbd_init_watch_dev(struct rbd_device *rbd_dev)
        int ret, rc;
 
        do {
-               ret = rbd_req_sync_watch(rbd_dev, rbd_dev->obj_md_name,
-                                        rbd_dev->header.obj_version);
+               ret = rbd_req_sync_watch(rbd_dev);
                if (ret == -ERANGE) {
-                       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-                       rc = __rbd_refresh_header(rbd_dev);
-                       mutex_unlock(&ctl_mutex);
+                       rc = rbd_refresh_header(rbd_dev, NULL);
                        if (rc < 0)
                                return rc;
                }
@@ -2177,7 +2220,7 @@ static atomic64_t rbd_id_max = ATOMIC64_INIT(0);
  */
 static void rbd_id_get(struct rbd_device *rbd_dev)
 {
-       rbd_dev->id = atomic64_inc_return(&rbd_id_max);
+       rbd_dev->dev_id = atomic64_inc_return(&rbd_id_max);
 
        spin_lock(&rbd_dev_list_lock);
        list_add_tail(&rbd_dev->node, &rbd_dev_list);
@@ -2191,7 +2234,7 @@ static void rbd_id_get(struct rbd_device *rbd_dev)
 static void rbd_id_put(struct rbd_device *rbd_dev)
 {
        struct list_head *tmp;
-       int rbd_id = rbd_dev->id;
+       int rbd_id = rbd_dev->dev_id;
        int max_id;
 
        BUG_ON(rbd_id < 1);
@@ -2282,19 +2325,58 @@ static inline size_t copy_token(const char **buf,
 }
 
 /*
- * This fills in the pool_name, obj, obj_len, snap_name, obj_len,
+ * Finds the next token in *buf, dynamically allocates a buffer big
+ * enough to hold a copy of it, and copies the token into the new
+ * buffer.  The copy is guaranteed to be terminated with '\0'.  Note
+ * that a duplicate buffer is created even for a zero-length token.
+ *
+ * Returns a pointer to the newly-allocated duplicate, or a null
+ * pointer if memory for the duplicate was not available.  If
+ * the lenp argument is a non-null pointer, the length of the token
+ * (not including the '\0') is returned in *lenp.
+ *
+ * If successful, the *buf pointer will be updated to point beyond
+ * the end of the found token.
+ *
+ * Note: uses GFP_KERNEL for allocation.
+ */
+static inline char *dup_token(const char **buf, size_t *lenp)
+{
+       char *dup;
+       size_t len;
+
+       len = next_token(buf);
+       dup = kmalloc(len + 1, GFP_KERNEL);
+       if (!dup)
+               return NULL;
+
+       memcpy(dup, *buf, len);
+       *(dup + len) = '\0';
+       *buf += len;
+
+       if (lenp)
+               *lenp = len;
+
+       return dup;
+}
+
+/*
+ * This fills in the pool_name, image_name, image_name_len, snap_name,
  * rbd_dev, rbd_md_name, and name fields of the given rbd_dev, based
  * on the list of monitor addresses and other options provided via
  * /sys/bus/rbd/add.
+ *
+ * Note: rbd_dev is assumed to have been initially zero-filled.
  */
 static int rbd_add_parse_args(struct rbd_device *rbd_dev,
                              const char *buf,
                              const char **mon_addrs,
                              size_t *mon_addrs_size,
                              char *options,
-                             size_t options_size)
+                            size_t options_size)
 {
-       size_t  len;
+       size_t len;
+       int ret;
 
        /* The first four tokens are required */
 
@@ -2310,56 +2392,74 @@ static int rbd_add_parse_args(struct rbd_device *rbd_dev,
        if (!len || len >= options_size)
                return -EINVAL;
 
-       len = copy_token(&buf, rbd_dev->pool_name, sizeof (rbd_dev->pool_name));
-       if (!len || len >= sizeof (rbd_dev->pool_name))
-               return -EINVAL;
-
-       len = copy_token(&buf, rbd_dev->obj, sizeof (rbd_dev->obj));
-       if (!len || len >= sizeof (rbd_dev->obj))
-               return -EINVAL;
+       ret = -ENOMEM;
+       rbd_dev->pool_name = dup_token(&buf, NULL);
+       if (!rbd_dev->pool_name)
+               goto out_err;
 
-       /* We have the object length in hand, save it. */
+       rbd_dev->image_name = dup_token(&buf, &rbd_dev->image_name_len);
+       if (!rbd_dev->image_name)
+               goto out_err;
 
-       rbd_dev->obj_len = len;
+       /* Create the name of the header object */
 
-       BUILD_BUG_ON(RBD_MAX_MD_NAME_LEN
-                               < RBD_MAX_OBJ_NAME_LEN + sizeof (RBD_SUFFIX));
-       sprintf(rbd_dev->obj_md_name, "%s%s", rbd_dev->obj, RBD_SUFFIX);
+       rbd_dev->header_name = kmalloc(rbd_dev->image_name_len
+                                               + sizeof (RBD_SUFFIX),
+                                       GFP_KERNEL);
+       if (!rbd_dev->header_name)
+               goto out_err;
+       sprintf(rbd_dev->header_name, "%s%s", rbd_dev->image_name, RBD_SUFFIX);
 
        /*
-        * The snapshot name is optional, but it's an error if it's
-        * too long.  If no snapshot is supplied, fill in the default.
+        * The snapshot name is optional.  If none is is supplied,
+        * we use the default value.
         */
-       len = copy_token(&buf, rbd_dev->snap_name, sizeof (rbd_dev->snap_name));
-       if (!len)
+       rbd_dev->snap_name = dup_token(&buf, &len);
+       if (!rbd_dev->snap_name)
+               goto out_err;
+       if (!len) {
+               /* Replace the empty name with the default */
+               kfree(rbd_dev->snap_name);
+               rbd_dev->snap_name
+                       = kmalloc(sizeof (RBD_SNAP_HEAD_NAME), GFP_KERNEL);
+               if (!rbd_dev->snap_name)
+                       goto out_err;
+
                memcpy(rbd_dev->snap_name, RBD_SNAP_HEAD_NAME,
                        sizeof (RBD_SNAP_HEAD_NAME));
-       else if (len >= sizeof (rbd_dev->snap_name))
-               return -EINVAL;
+       }
 
        return 0;
+
+out_err:
+       kfree(rbd_dev->header_name);
+       kfree(rbd_dev->image_name);
+       kfree(rbd_dev->pool_name);
+       rbd_dev->pool_name = NULL;
+
+       return ret;
 }
 
 static ssize_t rbd_add(struct bus_type *bus,
                       const char *buf,
                       size_t count)
 {
-       struct rbd_device *rbd_dev;
+       char *options;
+       struct rbd_device *rbd_dev = NULL;
        const char *mon_addrs = NULL;
        size_t mon_addrs_size = 0;
-       char *options = NULL;
        struct ceph_osd_client *osdc;
        int rc = -ENOMEM;
 
        if (!try_module_get(THIS_MODULE))
                return -ENODEV;
 
-       rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL);
-       if (!rbd_dev)
-               goto err_nomem;
        options = kmalloc(count, GFP_KERNEL);
        if (!options)
                goto err_nomem;
+       rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL);
+       if (!rbd_dev)
+               goto err_nomem;
 
        /* static rbd_device initialization */
        spin_lock_init(&rbd_dev->lock);
@@ -2367,15 +2467,13 @@ static ssize_t rbd_add(struct bus_type *bus,
        INIT_LIST_HEAD(&rbd_dev->snaps);
        init_rwsem(&rbd_dev->header_rwsem);
 
-       init_rwsem(&rbd_dev->header_rwsem);
-
        /* generate unique id: find highest unique id, add one */
        rbd_id_get(rbd_dev);
 
        /* Fill in the device name, now that we have its id. */
        BUILD_BUG_ON(DEV_NAME_LEN
                        < sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH);
-       sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->id);
+       sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->dev_id);
 
        /* parse add command */
        rc = rbd_add_parse_args(rbd_dev, buf, &mon_addrs, &mon_addrs_size,
@@ -2395,7 +2493,7 @@ static ssize_t rbd_add(struct bus_type *bus,
        rc = ceph_pg_poolid_by_name(osdc->osdmap, rbd_dev->pool_name);
        if (rc < 0)
                goto err_out_client;
-       rbd_dev->poolid = rc;
+       rbd_dev->pool_id = rc;
 
        /* register our block device */
        rc = register_blkdev(0, rbd_dev->name);
@@ -2435,10 +2533,16 @@ err_out_blkdev:
 err_out_client:
        rbd_put_client(rbd_dev);
 err_put_id:
+       if (rbd_dev->pool_name) {
+               kfree(rbd_dev->snap_name);
+               kfree(rbd_dev->header_name);
+               kfree(rbd_dev->image_name);
+               kfree(rbd_dev->pool_name);
+       }
        rbd_id_put(rbd_dev);
 err_nomem:
-       kfree(options);
        kfree(rbd_dev);
+       kfree(options);
 
        dout("Error adding device %s\n", buf);
        module_put(THIS_MODULE);
@@ -2446,7 +2550,7 @@ err_nomem:
        return (ssize_t) rc;
 }
 
-static struct rbd_device *__rbd_get_dev(unsigned long id)
+static struct rbd_device *__rbd_get_dev(unsigned long dev_id)
 {
        struct list_head *tmp;
        struct rbd_device *rbd_dev;
@@ -2454,7 +2558,7 @@ static struct rbd_device *__rbd_get_dev(unsigned long id)
        spin_lock(&rbd_dev_list_lock);
        list_for_each(tmp, &rbd_dev_list) {
                rbd_dev = list_entry(tmp, struct rbd_device, node);
-               if (rbd_dev->id == id) {
+               if (rbd_dev->dev_id == dev_id) {
                        spin_unlock(&rbd_dev_list_lock);
                        return rbd_dev;
                }
@@ -2474,7 +2578,7 @@ static void rbd_dev_release(struct device *dev)
                                                    rbd_dev->watch_request);
        }
        if (rbd_dev->watch_event)
-               rbd_req_sync_unwatch(rbd_dev, rbd_dev->obj_md_name);
+               rbd_req_sync_unwatch(rbd_dev);
 
        rbd_put_client(rbd_dev);
 
@@ -2483,6 +2587,10 @@ static void rbd_dev_release(struct device *dev)
        unregister_blkdev(rbd_dev->major, rbd_dev->name);
 
        /* done with the id, and with the rbd_dev */
+       kfree(rbd_dev->snap_name);
+       kfree(rbd_dev->header_name);
+       kfree(rbd_dev->pool_name);
+       kfree(rbd_dev->image_name);
        rbd_id_put(rbd_dev);
        kfree(rbd_dev);
 
@@ -2544,7 +2652,7 @@ static ssize_t rbd_snap_add(struct device *dev,
        if (ret < 0)
                goto err_unlock;
 
-       ret = __rbd_refresh_header(rbd_dev);
+       ret = __rbd_refresh_header(rbd_dev, NULL);
        if (ret < 0)
                goto err_unlock;
 
@@ -2553,7 +2661,7 @@ static ssize_t rbd_snap_add(struct device *dev,
        mutex_unlock(&ctl_mutex);
 
        /* make a best effort, don't error if failed */
-       rbd_req_sync_notify(rbd_dev, rbd_dev->obj_md_name);
+       rbd_req_sync_notify(rbd_dev);
 
        ret = count;
        kfree(name);
index 950708688f1719109962e86b450186c845f89cf7..0924e9e41a60ce4b297f8fb62a17ca6d81c90cf1 100644 (file)
@@ -31,7 +31,6 @@
 #define RBD_MIN_OBJ_ORDER       16
 #define RBD_MAX_OBJ_ORDER       30
 
-#define RBD_MAX_OBJ_NAME_LEN   96
 #define RBD_MAX_SEG_NAME_LEN   128
 
 #define RBD_COMP_NONE          0
index 693187df76012e1ace1f3c9b58fd4e78d6ec3aab..c0bbeb4707542ac2370b0337de5f3e4a3037d619 100644 (file)
@@ -21,8 +21,6 @@ struct workqueue_struct *virtblk_wq;
 
 struct virtio_blk
 {
-       spinlock_t lock;
-
        struct virtio_device *vdev;
        struct virtqueue *vq;
 
@@ -65,7 +63,7 @@ static void blk_done(struct virtqueue *vq)
        unsigned int len;
        unsigned long flags;
 
-       spin_lock_irqsave(&vblk->lock, flags);
+       spin_lock_irqsave(vblk->disk->queue->queue_lock, flags);
        while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) {
                int error;
 
@@ -99,7 +97,7 @@ static void blk_done(struct virtqueue *vq)
        }
        /* In case queue is stopped waiting for more buffers. */
        blk_start_queue(vblk->disk->queue);
-       spin_unlock_irqrestore(&vblk->lock, flags);
+       spin_unlock_irqrestore(vblk->disk->queue->queue_lock, flags);
 }
 
 static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
@@ -397,6 +395,83 @@ static int virtblk_name_format(char *prefix, int index, char *buf, int buflen)
        return 0;
 }
 
+static int virtblk_get_cache_mode(struct virtio_device *vdev)
+{
+       u8 writeback;
+       int err;
+
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_CONFIG_WCE,
+                               offsetof(struct virtio_blk_config, wce),
+                               &writeback);
+       if (err)
+               writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE);
+
+       return writeback;
+}
+
+static void virtblk_update_cache_mode(struct virtio_device *vdev)
+{
+       u8 writeback = virtblk_get_cache_mode(vdev);
+       struct virtio_blk *vblk = vdev->priv;
+
+       if (writeback)
+               blk_queue_flush(vblk->disk->queue, REQ_FLUSH);
+       else
+               blk_queue_flush(vblk->disk->queue, 0);
+
+       revalidate_disk(vblk->disk);
+}
+
+static const char *const virtblk_cache_types[] = {
+       "write through", "write back"
+};
+
+static ssize_t
+virtblk_cache_type_store(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t count)
+{
+       struct gendisk *disk = dev_to_disk(dev);
+       struct virtio_blk *vblk = disk->private_data;
+       struct virtio_device *vdev = vblk->vdev;
+       int i;
+       u8 writeback;
+
+       BUG_ON(!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_CONFIG_WCE));
+       for (i = ARRAY_SIZE(virtblk_cache_types); --i >= 0; )
+               if (sysfs_streq(buf, virtblk_cache_types[i]))
+                       break;
+
+       if (i < 0)
+               return -EINVAL;
+
+       writeback = i;
+       vdev->config->set(vdev,
+                         offsetof(struct virtio_blk_config, wce),
+                         &writeback, sizeof(writeback));
+
+       virtblk_update_cache_mode(vdev);
+       return count;
+}
+
+static ssize_t
+virtblk_cache_type_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct gendisk *disk = dev_to_disk(dev);
+       struct virtio_blk *vblk = disk->private_data;
+       u8 writeback = virtblk_get_cache_mode(vblk->vdev);
+
+       BUG_ON(writeback >= ARRAY_SIZE(virtblk_cache_types));
+       return snprintf(buf, 40, "%s\n", virtblk_cache_types[writeback]);
+}
+
+static const struct device_attribute dev_attr_cache_type_ro =
+       __ATTR(cache_type, S_IRUGO,
+              virtblk_cache_type_show, NULL);
+static const struct device_attribute dev_attr_cache_type_rw =
+       __ATTR(cache_type, S_IRUGO|S_IWUSR,
+              virtblk_cache_type_show, virtblk_cache_type_store);
+
 static int __devinit virtblk_probe(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk;
@@ -431,7 +506,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
                goto out_free_index;
        }
 
-       spin_lock_init(&vblk->lock);
        vblk->vdev = vdev;
        vblk->sg_elems = sg_elems;
        sg_init_table(vblk->sg, vblk->sg_elems);
@@ -456,7 +530,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
                goto out_mempool;
        }
 
-       q = vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
+       q = vblk->disk->queue = blk_init_queue(do_virtblk_request, NULL);
        if (!q) {
                err = -ENOMEM;
                goto out_put_disk;
@@ -474,8 +548,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
        vblk->index = index;
 
        /* configure queue flush support */
-       if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
-               blk_queue_flush(q, REQ_FLUSH);
+       virtblk_update_cache_mode(vdev);
 
        /* If disk is read-only in the host, the guest should obey */
        if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
@@ -553,6 +626,14 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
        if (err)
                goto out_del_disk;
 
+       if (virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE))
+               err = device_create_file(disk_to_dev(vblk->disk),
+                                        &dev_attr_cache_type_rw);
+       else
+               err = device_create_file(disk_to_dev(vblk->disk),
+                                        &dev_attr_cache_type_ro);
+       if (err)
+               goto out_del_disk;
        return 0;
 
 out_del_disk:
@@ -576,30 +657,20 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk = vdev->priv;
        int index = vblk->index;
-       struct virtblk_req *vbr;
-       unsigned long flags;
 
        /* Prevent config work handler from accessing the device. */
        mutex_lock(&vblk->config_lock);
        vblk->config_enable = false;
        mutex_unlock(&vblk->config_lock);
 
+       del_gendisk(vblk->disk);
+       blk_cleanup_queue(vblk->disk->queue);
+
        /* Stop all the virtqueues. */
        vdev->config->reset(vdev);
 
        flush_work(&vblk->config_work);
 
-       del_gendisk(vblk->disk);
-
-       /* Abort requests dispatched to driver. */
-       spin_lock_irqsave(&vblk->lock, flags);
-       while ((vbr = virtqueue_detach_unused_buf(vblk->vq))) {
-               __blk_end_request_all(vbr->req, -EIO);
-               mempool_free(vbr, vblk->pool);
-       }
-       spin_unlock_irqrestore(&vblk->lock, flags);
-
-       blk_cleanup_queue(vblk->disk->queue);
        put_disk(vblk->disk);
        mempool_destroy(vblk->pool);
        vdev->config->del_vqs(vdev);
@@ -655,7 +726,7 @@ static const struct virtio_device_id id_table[] = {
 static unsigned int features[] = {
        VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
        VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_SCSI,
-       VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY
+       VIRTIO_BLK_F_WCE, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE
 };
 
 /*
index b01d67328243c28dff8291932f16c7bc29b7e888..7c0d391996b5b4e82432b9b3418d427f7a42894a 100644 (file)
@@ -73,6 +73,20 @@ config HW_RANDOM_ATMEL
 
          If unsure, say Y.
 
+config HW_RANDOM_BCM63XX
+       tristate "Broadcom BCM63xx Random Number Generator support"
+       depends on HW_RANDOM && BCM63XX
+       default HW_RANDOM
+       ---help---
+         This driver provides kernel-side support for the Random Number
+         Generator hardware found on the Broadcom BCM63xx SoCs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called bcm63xx-rng
+
+         If unusure, say Y.
+
+
 config HW_RANDOM_GEODE
        tristate "AMD Geode HW Random Number Generator support"
        depends on HW_RANDOM && X86_32 && PCI
index 8d6d173b65e6ea51cb806b60400e0d157629da96..39a757ca15b65c59b188d0489b12488e4b4c6ac3 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o
 obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o
 obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o
 obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o
+obj-$(CONFIG_HW_RANDOM_BCM63XX)        += bcm63xx-rng.o
 obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
 obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o
 n2-rng-y := n2-drv.o n2-asm.o
diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c
new file mode 100644 (file)
index 0000000..aec6a42
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Broadcom BCM63xx Random Number Generator support
+ *
+ * Copyright (C) 2011, Florian Fainelli <florian@openwrt.org>
+ * Copyright (C) 2009, Broadcom Corporation
+ *
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+
+#include <bcm63xx_io.h>
+#include <bcm63xx_regs.h>
+
+struct bcm63xx_rng_priv {
+       struct clk *clk;
+       void __iomem *regs;
+};
+
+#define to_rng_priv(rng)       ((struct bcm63xx_rng_priv *)rng->priv)
+
+static int bcm63xx_rng_init(struct hwrng *rng)
+{
+       struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
+       u32 val;
+
+       val = bcm_readl(priv->regs + RNG_CTRL);
+       val |= RNG_EN;
+       bcm_writel(val, priv->regs + RNG_CTRL);
+
+       return 0;
+}
+
+static void bcm63xx_rng_cleanup(struct hwrng *rng)
+{
+       struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
+       u32 val;
+
+       val = bcm_readl(priv->regs + RNG_CTRL);
+       val &= ~RNG_EN;
+       bcm_writel(val, priv->regs + RNG_CTRL);
+}
+
+static int bcm63xx_rng_data_present(struct hwrng *rng, int wait)
+{
+       struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
+
+       return bcm_readl(priv->regs + RNG_STAT) & RNG_AVAIL_MASK;
+}
+
+static int bcm63xx_rng_data_read(struct hwrng *rng, u32 *data)
+{
+       struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
+
+       *data = bcm_readl(priv->regs + RNG_DATA);
+
+       return 4;
+}
+
+static int __devinit bcm63xx_rng_probe(struct platform_device *pdev)
+{
+       struct resource *r;
+       struct clk *clk;
+       int ret;
+       struct bcm63xx_rng_priv *priv;
+       struct hwrng *rng;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pdev->dev, "no iomem resource\n");
+               ret = -ENXIO;
+               goto out;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(&pdev->dev, "no memory for private structure\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       rng = kzalloc(sizeof(*rng), GFP_KERNEL);
+       if (!rng) {
+               dev_err(&pdev->dev, "no memory for rng structure\n");
+               ret = -ENOMEM;
+               goto out_free_priv;
+       }
+
+       platform_set_drvdata(pdev, rng);
+       rng->priv = (unsigned long)priv;
+       rng->name = pdev->name;
+       rng->init = bcm63xx_rng_init;
+       rng->cleanup = bcm63xx_rng_cleanup;
+       rng->data_present = bcm63xx_rng_data_present;
+       rng->data_read = bcm63xx_rng_data_read;
+
+       clk = clk_get(&pdev->dev, "ipsec");
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "no clock for device\n");
+               ret = PTR_ERR(clk);
+               goto out_free_rng;
+       }
+
+       priv->clk = clk;
+
+       if (!devm_request_mem_region(&pdev->dev, r->start,
+                                       resource_size(r), pdev->name)) {
+               dev_err(&pdev->dev, "request mem failed");
+               ret = -ENOMEM;
+               goto out_free_rng;
+       }
+
+       priv->regs = devm_ioremap_nocache(&pdev->dev, r->start,
+                                       resource_size(r));
+       if (!priv->regs) {
+               dev_err(&pdev->dev, "ioremap failed");
+               ret = -ENOMEM;
+               goto out_free_rng;
+       }
+
+       clk_enable(clk);
+
+       ret = hwrng_register(rng);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register rng device\n");
+               goto out_clk_disable;
+       }
+
+       dev_info(&pdev->dev, "registered RNG driver\n");
+
+       return 0;
+
+out_clk_disable:
+       clk_disable(clk);
+out_free_rng:
+       platform_set_drvdata(pdev, NULL);
+       kfree(rng);
+out_free_priv:
+       kfree(priv);
+out:
+       return ret;
+}
+
+static int __devexit bcm63xx_rng_remove(struct platform_device *pdev)
+{
+       struct hwrng *rng = platform_get_drvdata(pdev);
+       struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
+
+       hwrng_unregister(rng);
+       clk_disable(priv->clk);
+       kfree(priv);
+       kfree(rng);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver bcm63xx_rng_driver = {
+       .probe          = bcm63xx_rng_probe,
+       .remove         = __devexit_p(bcm63xx_rng_remove),
+       .driver         = {
+               .name   = "bcm63xx-rng",
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(bcm63xx_rng_driver);
+
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
+MODULE_DESCRIPTION("Broadcom BCM63xx RNG driver");
+MODULE_LICENSE("GPL");
index 723725bbb96b774036f9fee05562b207d1cecfc0..5708299507d0e5b59ad401d495f1b0baa80dbe65 100644 (file)
@@ -55,6 +55,7 @@ static void register_buffer(u8 *buf, size_t size)
 
 static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
 {
+       int ret;
 
        if (!busy) {
                busy = true;
@@ -65,7 +66,9 @@ static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
        if (!wait)
                return 0;
 
-       wait_for_completion(&have_data);
+       ret = wait_for_completion_killable(&have_data);
+       if (ret < 0)
+               return ret;
 
        busy = false;
 
@@ -85,7 +88,7 @@ static struct hwrng virtio_hwrng = {
        .read           = virtio_read,
 };
 
-static int virtrng_probe(struct virtio_device *vdev)
+static int probe_common(struct virtio_device *vdev)
 {
        int err;
 
@@ -103,13 +106,37 @@ static int virtrng_probe(struct virtio_device *vdev)
        return 0;
 }
 
-static void __devexit virtrng_remove(struct virtio_device *vdev)
+static void remove_common(struct virtio_device *vdev)
 {
        vdev->config->reset(vdev);
+       busy = false;
        hwrng_unregister(&virtio_hwrng);
        vdev->config->del_vqs(vdev);
 }
 
+static int virtrng_probe(struct virtio_device *vdev)
+{
+       return probe_common(vdev);
+}
+
+static void __devexit virtrng_remove(struct virtio_device *vdev)
+{
+       remove_common(vdev);
+}
+
+#ifdef CONFIG_PM
+static int virtrng_freeze(struct virtio_device *vdev)
+{
+       remove_common(vdev);
+       return 0;
+}
+
+static int virtrng_restore(struct virtio_device *vdev)
+{
+       return probe_common(vdev);
+}
+#endif
+
 static struct virtio_device_id id_table[] = {
        { VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID },
        { 0 },
@@ -121,6 +148,10 @@ static struct virtio_driver virtio_rng_driver = {
        .id_table =     id_table,
        .probe =        virtrng_probe,
        .remove =       __devexit_p(virtrng_remove),
+#ifdef CONFIG_PM
+       .freeze =       virtrng_freeze,
+       .restore =      virtrng_restore,
+#endif
 };
 
 static int __init init(void)
index 8b78750f1efe89d50a1ea075420ea032f4ad2ecd..845f97fd18326fbe2301a515da53483d966907a8 100644 (file)
@@ -283,7 +283,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma,
        vdata->flags = flags;
        vdata->type = type;
        spin_lock_init(&vdata->lock);
-       vdata->refcnt = ATOMIC_INIT(1);
+       atomic_set(&vdata->refcnt, 1);
        vma->vm_private_data = vdata;
 
        vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP | VM_DONTEXPAND);
index 3f99b9099658ebe70a76a10f14af31716e4987c9..7f0b5ca785160733839e6652cf7d67b410fe32e9 100644 (file)
@@ -25,7 +25,6 @@ menu "Common Clock Framework"
 
 config COMMON_CLK_DEBUG
        bool "DebugFS representation of clock tree"
-       depends on COMMON_CLK
        select DEBUG_FS
        ---help---
          Creates a directory hierchy in debugfs for visualizing the clk
index c87fdd7105609d7bddd836dd9fa2e640753bb22a..efdfd009c2701a40b18a7ec8025ce7500fb98c53 100644 (file)
@@ -465,6 +465,9 @@ static void __clk_disable(struct clk *clk)
        if (!clk)
                return;
 
+       if (WARN_ON(IS_ERR(clk)))
+               return;
+
        if (WARN_ON(clk->enable_count == 0))
                return;
 
index a88331644ebfc7fcf3be31478e7a47ec148cb4a3..e64c253cb1698d456ba853bb8c2ce4f03b2016cd 100644 (file)
@@ -65,20 +65,20 @@ static unsigned int clkdiv_cpu0_5250[CPUFREQ_LEVEL_END][8] = {
         * Clock divider value for following
         * { ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2 }
         */
-       { 0, 3, 7, 7, 6, 1, 3, 0 },     /* 1700 MHz - N/A */
-       { 0, 3, 7, 7, 6, 1, 3, 0 },     /* 1600 MHz - N/A */
-       { 0, 3, 7, 7, 5, 1, 3, 0 },     /* 1500 MHz - N/A */
-       { 0, 3, 7, 7, 6, 1, 3, 0 },     /* 1400 MHz */
-       { 0, 3, 7, 7, 6, 1, 3, 0 },     /* 1300 MHz */
-       { 0, 3, 7, 7, 5, 1, 3, 0 },     /* 1200 MHz */
-       { 0, 2, 7, 7, 5, 1, 2, 0 },     /* 1100 MHz */
-       { 0, 2, 7, 7, 4, 1, 2, 0 },     /* 1000 MHz */
-       { 0, 2, 7, 7, 4, 1, 2, 0 },     /* 900 MHz */
-       { 0, 2, 7, 7, 3, 1, 1, 0 },     /* 800 MHz */
+       { 0, 3, 7, 7, 7, 3, 5, 0 },     /* 1700 MHz */
+       { 0, 3, 7, 7, 7, 1, 4, 0 },     /* 1600 MHz */
+       { 0, 2, 7, 7, 7, 1, 4, 0 },     /* 1500 MHz */
+       { 0, 2, 7, 7, 6, 1, 4, 0 },     /* 1400 MHz */
+       { 0, 2, 7, 7, 6, 1, 3, 0 },     /* 1300 MHz */
+       { 0, 2, 7, 7, 5, 1, 3, 0 },     /* 1200 MHz */
+       { 0, 3, 7, 7, 5, 1, 3, 0 },     /* 1100 MHz */
+       { 0, 1, 7, 7, 4, 1, 2, 0 },     /* 1000 MHz */
+       { 0, 1, 7, 7, 4, 1, 2, 0 },     /* 900 MHz */
+       { 0, 1, 7, 7, 4, 1, 2, 0 },     /* 800 MHz */
        { 0, 1, 7, 7, 3, 1, 1, 0 },     /* 700 MHz */
-       { 0, 1, 7, 7, 2, 1, 1, 0 },     /* 600 MHz */
+       { 0, 1, 7, 7, 3, 1, 1, 0 },     /* 600 MHz */
        { 0, 1, 7, 7, 2, 1, 1, 0 },     /* 500 MHz */
-       { 0, 1, 7, 7, 1, 1, 1, 0 },     /* 400 MHz */
+       { 0, 1, 7, 7, 2, 1, 1, 0 },     /* 400 MHz */
        { 0, 1, 7, 7, 1, 1, 1, 0 },     /* 300 MHz */
        { 0, 1, 7, 7, 1, 1, 1, 0 },     /* 200 MHz */
 };
@@ -87,9 +87,9 @@ static unsigned int clkdiv_cpu1_5250[CPUFREQ_LEVEL_END][2] = {
        /* Clock divider value for following
         * { COPY, HPM }
         */
-       { 0, 2 },       /* 1700 MHz - N/A */
-       { 0, 2 },       /* 1600 MHz - N/A */
-       { 0, 2 },       /* 1500 MHz - N/A */
+       { 0, 2 },       /* 1700 MHz */
+       { 0, 2 },       /* 1600 MHz */
+       { 0, 2 },       /* 1500 MHz */
        { 0, 2 },       /* 1400 MHz */
        { 0, 2 },       /* 1300 MHz */
        { 0, 2 },       /* 1200 MHz */
@@ -106,10 +106,10 @@ static unsigned int clkdiv_cpu1_5250[CPUFREQ_LEVEL_END][2] = {
 };
 
 static unsigned int exynos5_apll_pms_table[CPUFREQ_LEVEL_END] = {
-       (0),                            /* 1700 MHz - N/A */
-       (0),                            /* 1600 MHz - N/A */
-       (0),                            /* 1500 MHz - N/A */
-       (0),                            /* 1400 MHz */
+       ((425 << 16) | (6 << 8) | 0),   /* 1700 MHz */
+       ((200 << 16) | (3 << 8) | 0),   /* 1600 MHz */
+       ((250 << 16) | (4 << 8) | 0),   /* 1500 MHz */
+       ((175 << 16) | (3 << 8) | 0),   /* 1400 MHz */
        ((325 << 16) | (6 << 8) | 0),   /* 1300 MHz */
        ((200 << 16) | (4 << 8) | 0),   /* 1200 MHz */
        ((275 << 16) | (6 << 8) | 0),   /* 1100 MHz */
@@ -126,9 +126,10 @@ static unsigned int exynos5_apll_pms_table[CPUFREQ_LEVEL_END] = {
 
 /* ASV group voltage table */
 static const unsigned int asv_voltage_5250[CPUFREQ_LEVEL_END] = {
-       0, 0, 0, 0, 0, 0, 0,    /* 1700 MHz ~ 1100 MHz Not supported */
-       1175000, 1125000, 1075000, 1050000, 1000000,
-       950000, 925000, 925000, 900000
+       1300000, 1250000, 1225000, 1200000, 1150000,
+       1125000, 1100000, 1075000, 1050000, 1025000,
+       1012500, 1000000,  975000,  950000,  937500,
+       925000
 };
 
 static void set_clkdiv(unsigned int div_index)
@@ -248,15 +249,7 @@ static void __init set_volt_table(void)
 {
        unsigned int i;
 
-       exynos5250_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
-       exynos5250_freq_table[L1].frequency = CPUFREQ_ENTRY_INVALID;
-       exynos5250_freq_table[L2].frequency = CPUFREQ_ENTRY_INVALID;
-       exynos5250_freq_table[L3].frequency = CPUFREQ_ENTRY_INVALID;
-       exynos5250_freq_table[L4].frequency = CPUFREQ_ENTRY_INVALID;
-       exynos5250_freq_table[L5].frequency = CPUFREQ_ENTRY_INVALID;
-       exynos5250_freq_table[L6].frequency = CPUFREQ_ENTRY_INVALID;
-
-       max_support_idx = L7;
+       max_support_idx = L0;
 
        for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
                exynos5250_volt_table[i] = asv_voltage_5250[i];
index fdffa1beca17288eeab2055d25382545c3dbbdcf..409b92b8d346087b4ec292bda8790d03cc764224 100644 (file)
@@ -7,7 +7,7 @@
 menuconfig EDAC
        bool "EDAC (Error Detection And Correction) reporting"
        depends on HAS_IOMEM
-       depends on X86 || PPC || TILE
+       depends on X86 || PPC || TILE || ARM
        help
          EDAC is designed to report errors in the core system.
          These are low-level errors that are reported in the CPU or
@@ -31,6 +31,14 @@ if EDAC
 
 comment "Reporting subsystems"
 
+config EDAC_LEGACY_SYSFS
+       bool "EDAC legacy sysfs"
+       default y
+       help
+         Enable the compatibility sysfs nodes.
+         Use 'Y' if your edac utilities aren't ported to work with the newer
+         structures.
+
 config EDAC_DEBUG
        bool "Debugging"
        help
@@ -294,4 +302,18 @@ config EDAC_TILE
          Support for error detection and correction on the
          Tilera memory controller.
 
+config EDAC_HIGHBANK_MC
+       tristate "Highbank Memory Controller"
+       depends on EDAC_MM_EDAC && ARCH_HIGHBANK
+       help
+         Support for error detection and correction on the
+         Calxeda Highbank memory controller.
+
+config EDAC_HIGHBANK_L2
+       tristate "Highbank L2 Cache"
+       depends on EDAC_MM_EDAC && ARCH_HIGHBANK
+       help
+         Support for error detection and correction on the
+         Calxeda Highbank memory controller.
+
 endif # EDAC
index 196a63dd37c5c41e0914502620fb3a8424c7d2a4..7e5129a733f8cc6b8afdc7dac91228167949512d 100644 (file)
@@ -55,3 +55,6 @@ obj-$(CONFIG_EDAC_AMD8111)            += amd8111_edac.o
 obj-$(CONFIG_EDAC_AMD8131)             += amd8131_edac.o
 
 obj-$(CONFIG_EDAC_TILE)                        += tile_edac.o
+
+obj-$(CONFIG_EDAC_HIGHBANK_MC) += highbank_mc_edac.o
+obj-$(CONFIG_EDAC_HIGHBANK_L2) += highbank_l2_edac.o
index 7be9b7288e90eaaf5fab79f34dcac2ceafbc3a2b..5a297a26211d622b0f0ceedb0389fcbeb4223baf 100644 (file)
@@ -321,8 +321,8 @@ found:
        return edac_mc_find((int)node_id);
 
 err_no_match:
-       debugf2("sys_addr 0x%lx doesn't match any node\n",
-               (unsigned long)sys_addr);
+       edac_dbg(2, "sys_addr 0x%lx doesn't match any node\n",
+                (unsigned long)sys_addr);
 
        return NULL;
 }
@@ -393,15 +393,15 @@ static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
                mask = ~mask;
 
                if ((input_addr & mask) == (base & mask)) {
-                       debugf2("InputAddr 0x%lx matches csrow %d (node %d)\n",
-                               (unsigned long)input_addr, csrow,
-                               pvt->mc_node_id);
+                       edac_dbg(2, "InputAddr 0x%lx matches csrow %d (node %d)\n",
+                                (unsigned long)input_addr, csrow,
+                                pvt->mc_node_id);
 
                        return csrow;
                }
        }
-       debugf2("no matching csrow for InputAddr 0x%lx (MC node %d)\n",
-               (unsigned long)input_addr, pvt->mc_node_id);
+       edac_dbg(2, "no matching csrow for InputAddr 0x%lx (MC node %d)\n",
+                (unsigned long)input_addr, pvt->mc_node_id);
 
        return -1;
 }
@@ -430,20 +430,20 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
 
        /* only revE and later have the DRAM Hole Address Register */
        if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_E) {
-               debugf1("  revision %d for node %d does not support DHAR\n",
-                       pvt->ext_model, pvt->mc_node_id);
+               edac_dbg(1, "  revision %d for node %d does not support DHAR\n",
+                        pvt->ext_model, pvt->mc_node_id);
                return 1;
        }
 
        /* valid for Fam10h and above */
        if (boot_cpu_data.x86 >= 0x10 && !dhar_mem_hoist_valid(pvt)) {
-               debugf1("  Dram Memory Hoisting is DISABLED on this system\n");
+               edac_dbg(1, "  Dram Memory Hoisting is DISABLED on this system\n");
                return 1;
        }
 
        if (!dhar_valid(pvt)) {
-               debugf1("  Dram Memory Hoisting is DISABLED on this node %d\n",
-                       pvt->mc_node_id);
+               edac_dbg(1, "  Dram Memory Hoisting is DISABLED on this node %d\n",
+                        pvt->mc_node_id);
                return 1;
        }
 
@@ -475,9 +475,9 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
        else
                *hole_offset = k8_dhar_offset(pvt);
 
-       debugf1("  DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n",
-               pvt->mc_node_id, (unsigned long)*hole_base,
-               (unsigned long)*hole_offset, (unsigned long)*hole_size);
+       edac_dbg(1, "  DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n",
+                pvt->mc_node_id, (unsigned long)*hole_base,
+                (unsigned long)*hole_offset, (unsigned long)*hole_size);
 
        return 0;
 }
@@ -528,10 +528,9 @@ static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
                        /* use DHAR to translate SysAddr to DramAddr */
                        dram_addr = sys_addr - hole_offset;
 
-                       debugf2("using DHAR to translate SysAddr 0x%lx to "
-                               "DramAddr 0x%lx\n",
-                               (unsigned long)sys_addr,
-                               (unsigned long)dram_addr);
+                       edac_dbg(2, "using DHAR to translate SysAddr 0x%lx to DramAddr 0x%lx\n",
+                                (unsigned long)sys_addr,
+                                (unsigned long)dram_addr);
 
                        return dram_addr;
                }
@@ -548,9 +547,8 @@ static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
         */
        dram_addr = (sys_addr & GENMASK(0, 39)) - dram_base;
 
-       debugf2("using DRAM Base register to translate SysAddr 0x%lx to "
-               "DramAddr 0x%lx\n", (unsigned long)sys_addr,
-               (unsigned long)dram_addr);
+       edac_dbg(2, "using DRAM Base register to translate SysAddr 0x%lx to DramAddr 0x%lx\n",
+                (unsigned long)sys_addr, (unsigned long)dram_addr);
        return dram_addr;
 }
 
@@ -586,9 +584,9 @@ static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr)
        input_addr = ((dram_addr >> intlv_shift) & GENMASK(12, 35)) +
                      (dram_addr & 0xfff);
 
-       debugf2("  Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n",
-               intlv_shift, (unsigned long)dram_addr,
-               (unsigned long)input_addr);
+       edac_dbg(2, "  Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n",
+                intlv_shift, (unsigned long)dram_addr,
+                (unsigned long)input_addr);
 
        return input_addr;
 }
@@ -604,8 +602,8 @@ static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr)
        input_addr =
            dram_addr_to_input_addr(mci, sys_addr_to_dram_addr(mci, sys_addr));
 
-       debugf2("SysAdddr 0x%lx translates to InputAddr 0x%lx\n",
-               (unsigned long)sys_addr, (unsigned long)input_addr);
+       edac_dbg(2, "SysAdddr 0x%lx translates to InputAddr 0x%lx\n",
+                (unsigned long)sys_addr, (unsigned long)input_addr);
 
        return input_addr;
 }
@@ -637,8 +635,8 @@ static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
 
        intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
        if (intlv_shift == 0) {
-               debugf1("    InputAddr 0x%lx translates to DramAddr of "
-                       "same value\n", (unsigned long)input_addr);
+               edac_dbg(1, "    InputAddr 0x%lx translates to DramAddr of same value\n",
+                        (unsigned long)input_addr);
 
                return input_addr;
        }
@@ -649,9 +647,9 @@ static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
        intlv_sel = dram_intlv_sel(pvt, node_id) & ((1 << intlv_shift) - 1);
        dram_addr = bits + (intlv_sel << 12);
 
-       debugf1("InputAddr 0x%lx translates to DramAddr 0x%lx "
-               "(%d node interleave bits)\n", (unsigned long)input_addr,
-               (unsigned long)dram_addr, intlv_shift);
+       edac_dbg(1, "InputAddr 0x%lx translates to DramAddr 0x%lx (%d node interleave bits)\n",
+                (unsigned long)input_addr,
+                (unsigned long)dram_addr, intlv_shift);
 
        return dram_addr;
 }
@@ -673,9 +671,9 @@ static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
                    (dram_addr < (hole_base + hole_size))) {
                        sys_addr = dram_addr + hole_offset;
 
-                       debugf1("using DHAR to translate DramAddr 0x%lx to "
-                               "SysAddr 0x%lx\n", (unsigned long)dram_addr,
-                               (unsigned long)sys_addr);
+                       edac_dbg(1, "using DHAR to translate DramAddr 0x%lx to SysAddr 0x%lx\n",
+                                (unsigned long)dram_addr,
+                                (unsigned long)sys_addr);
 
                        return sys_addr;
                }
@@ -697,9 +695,9 @@ static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
         */
        sys_addr |= ~((sys_addr & (1ull << 39)) - 1);
 
-       debugf1("    Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n",
-               pvt->mc_node_id, (unsigned long)dram_addr,
-               (unsigned long)sys_addr);
+       edac_dbg(1, "    Node %d, DramAddr 0x%lx to SysAddr 0x%lx\n",
+                pvt->mc_node_id, (unsigned long)dram_addr,
+                (unsigned long)sys_addr);
 
        return sys_addr;
 }
@@ -768,49 +766,48 @@ static void amd64_debug_display_dimm_sizes(struct amd64_pvt *, u8);
 
 static void amd64_dump_dramcfg_low(u32 dclr, int chan)
 {
-       debugf1("F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
+       edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
 
-       debugf1("  DIMM type: %sbuffered; all DIMMs support ECC: %s\n",
-               (dclr & BIT(16)) ?  "un" : "",
-               (dclr & BIT(19)) ? "yes" : "no");
+       edac_dbg(1, "  DIMM type: %sbuffered; all DIMMs support ECC: %s\n",
+                (dclr & BIT(16)) ?  "un" : "",
+                (dclr & BIT(19)) ? "yes" : "no");
 
-       debugf1("  PAR/ERR parity: %s\n",
-               (dclr & BIT(8)) ?  "enabled" : "disabled");
+       edac_dbg(1, "  PAR/ERR parity: %s\n",
+                (dclr & BIT(8)) ?  "enabled" : "disabled");
 
        if (boot_cpu_data.x86 == 0x10)
-               debugf1("  DCT 128bit mode width: %s\n",
-                       (dclr & BIT(11)) ?  "128b" : "64b");
+               edac_dbg(1, "  DCT 128bit mode width: %s\n",
+                        (dclr & BIT(11)) ?  "128b" : "64b");
 
-       debugf1("  x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n",
-               (dclr & BIT(12)) ?  "yes" : "no",
-               (dclr & BIT(13)) ?  "yes" : "no",
-               (dclr & BIT(14)) ?  "yes" : "no",
-               (dclr & BIT(15)) ?  "yes" : "no");
+       edac_dbg(1, "  x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n",
+                (dclr & BIT(12)) ?  "yes" : "no",
+                (dclr & BIT(13)) ?  "yes" : "no",
+                (dclr & BIT(14)) ?  "yes" : "no",
+                (dclr & BIT(15)) ?  "yes" : "no");
 }
 
 /* Display and decode various NB registers for debug purposes. */
 static void dump_misc_regs(struct amd64_pvt *pvt)
 {
-       debugf1("F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
+       edac_dbg(1, "F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
 
-       debugf1("  NB two channel DRAM capable: %s\n",
-               (pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no");
+       edac_dbg(1, "  NB two channel DRAM capable: %s\n",
+                (pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no");
 
-       debugf1("  ECC capable: %s, ChipKill ECC capable: %s\n",
-               (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
-               (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
+       edac_dbg(1, "  ECC capable: %s, ChipKill ECC capable: %s\n",
+                (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
+                (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
 
        amd64_dump_dramcfg_low(pvt->dclr0, 0);
 
-       debugf1("F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare);
+       edac_dbg(1, "F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare);
 
-       debugf1("F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, "
-                       "offset: 0x%08x\n",
-                       pvt->dhar, dhar_base(pvt),
-                       (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt)
-                                                  : f10_dhar_offset(pvt));
+       edac_dbg(1, "F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, offset: 0x%08x\n",
+                pvt->dhar, dhar_base(pvt),
+                (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt)
+                : f10_dhar_offset(pvt));
 
-       debugf1("  DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
+       edac_dbg(1, "  DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
 
        amd64_debug_display_dimm_sizes(pvt, 0);
 
@@ -857,15 +854,15 @@ static void read_dct_base_mask(struct amd64_pvt *pvt)
                u32 *base1 = &pvt->csels[1].csbases[cs];
 
                if (!amd64_read_dct_pci_cfg(pvt, reg0, base0))
-                       debugf0("  DCSB0[%d]=0x%08x reg: F2x%x\n",
-                               cs, *base0, reg0);
+                       edac_dbg(0, "  DCSB0[%d]=0x%08x reg: F2x%x\n",
+                                cs, *base0, reg0);
 
                if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
                        continue;
 
                if (!amd64_read_dct_pci_cfg(pvt, reg1, base1))
-                       debugf0("  DCSB1[%d]=0x%08x reg: F2x%x\n",
-                               cs, *base1, reg1);
+                       edac_dbg(0, "  DCSB1[%d]=0x%08x reg: F2x%x\n",
+                                cs, *base1, reg1);
        }
 
        for_each_chip_select_mask(cs, 0, pvt) {
@@ -875,15 +872,15 @@ static void read_dct_base_mask(struct amd64_pvt *pvt)
                u32 *mask1 = &pvt->csels[1].csmasks[cs];
 
                if (!amd64_read_dct_pci_cfg(pvt, reg0, mask0))
-                       debugf0("    DCSM0[%d]=0x%08x reg: F2x%x\n",
-                               cs, *mask0, reg0);
+                       edac_dbg(0, "    DCSM0[%d]=0x%08x reg: F2x%x\n",
+                                cs, *mask0, reg0);
 
                if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
                        continue;
 
                if (!amd64_read_dct_pci_cfg(pvt, reg1, mask1))
-                       debugf0("    DCSM1[%d]=0x%08x reg: F2x%x\n",
-                               cs, *mask1, reg1);
+                       edac_dbg(0, "    DCSM1[%d]=0x%08x reg: F2x%x\n",
+                                cs, *mask1, reg1);
        }
 }
 
@@ -1049,24 +1046,22 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
        if (!src_mci) {
                amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n",
                             (unsigned long)sys_addr);
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                     page, offset, syndrome,
                                     -1, -1, -1,
-                                    EDAC_MOD_STR,
                                     "failed to map error addr to a node",
-                                    NULL);
+                                    "");
                return;
        }
 
        /* Now map the sys_addr to a CSROW */
        csrow = sys_addr_to_csrow(src_mci, sys_addr);
        if (csrow < 0) {
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                     page, offset, syndrome,
                                     -1, -1, -1,
-                                    EDAC_MOD_STR,
                                     "failed to map error addr to a csrow",
-                                    NULL);
+                                    "");
                return;
        }
 
@@ -1082,12 +1077,11 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
                        amd64_mc_warn(src_mci, "unknown syndrome 0x%04x - "
                                      "possible error reporting race\n",
                                      syndrome);
-                       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+                       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                             page, offset, syndrome,
                                             csrow, -1, -1,
-                                            EDAC_MOD_STR,
                                             "unknown syndrome - possible error reporting race",
-                                            NULL);
+                                            "");
                        return;
                }
        } else {
@@ -1102,10 +1096,10 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
                channel = ((sys_addr & BIT(3)) != 0);
        }
 
-       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, src_mci,
+       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, src_mci, 1,
                             page, offset, syndrome,
                             csrow, channel, -1,
-                            EDAC_MOD_STR, "", NULL);
+                            "", "");
 }
 
 static int ddr2_cs_size(unsigned i, bool dct_width)
@@ -1193,7 +1187,7 @@ static int f1x_early_channel_count(struct amd64_pvt *pvt)
         * Need to check DCT0[0] and DCT1[0] to see if only one of them has
         * their CSEnable bit on. If so, then SINGLE DIMM case.
         */
-       debugf0("Data width is not 128 bits - need more decoding\n");
+       edac_dbg(0, "Data width is not 128 bits - need more decoding\n");
 
        /*
         * Check DRAM Bank Address Mapping values for each DIMM to see if there
@@ -1272,25 +1266,24 @@ static void read_dram_ctl_register(struct amd64_pvt *pvt)
                return;
 
        if (!amd64_read_dct_pci_cfg(pvt, DCT_SEL_LO, &pvt->dct_sel_lo)) {
-               debugf0("F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n",
-                       pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
+               edac_dbg(0, "F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n",
+                        pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
 
-               debugf0("  DCTs operate in %s mode.\n",
-                       (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
+               edac_dbg(0, "  DCTs operate in %s mode\n",
+                        (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
 
                if (!dct_ganging_enabled(pvt))
-                       debugf0("  Address range split per DCT: %s\n",
-                               (dct_high_range_enabled(pvt) ? "yes" : "no"));
+                       edac_dbg(0, "  Address range split per DCT: %s\n",
+                                (dct_high_range_enabled(pvt) ? "yes" : "no"));
 
-               debugf0("  data interleave for ECC: %s, "
-                       "DRAM cleared since last warm reset: %s\n",
-                       (dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"),
-                       (dct_memory_cleared(pvt) ? "yes" : "no"));
+               edac_dbg(0, "  data interleave for ECC: %s, DRAM cleared since last warm reset: %s\n",
+                        (dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"),
+                        (dct_memory_cleared(pvt) ? "yes" : "no"));
 
-               debugf0("  channel interleave: %s, "
-                       "interleave bits selector: 0x%x\n",
-                       (dct_interleave_enabled(pvt) ? "enabled" : "disabled"),
-                       dct_sel_interleave_addr(pvt));
+               edac_dbg(0, "  channel interleave: %s, "
+                        "interleave bits selector: 0x%x\n",
+                        (dct_interleave_enabled(pvt) ? "enabled" : "disabled"),
+                        dct_sel_interleave_addr(pvt));
        }
 
        amd64_read_dct_pci_cfg(pvt, DCT_SEL_HI, &pvt->dct_sel_hi);
@@ -1428,7 +1421,7 @@ static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
 
        pvt = mci->pvt_info;
 
-       debugf1("input addr: 0x%llx, DCT: %d\n", in_addr, dct);
+       edac_dbg(1, "input addr: 0x%llx, DCT: %d\n", in_addr, dct);
 
        for_each_chip_select(csrow, dct, pvt) {
                if (!csrow_enabled(csrow, dct, pvt))
@@ -1436,19 +1429,18 @@ static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
 
                get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask);
 
-               debugf1("    CSROW=%d CSBase=0x%llx CSMask=0x%llx\n",
-                       csrow, cs_base, cs_mask);
+               edac_dbg(1, "    CSROW=%d CSBase=0x%llx CSMask=0x%llx\n",
+                        csrow, cs_base, cs_mask);
 
                cs_mask = ~cs_mask;
 
-               debugf1("    (InputAddr & ~CSMask)=0x%llx "
-                       "(CSBase & ~CSMask)=0x%llx\n",
-                       (in_addr & cs_mask), (cs_base & cs_mask));
+               edac_dbg(1, "    (InputAddr & ~CSMask)=0x%llx (CSBase & ~CSMask)=0x%llx\n",
+                        (in_addr & cs_mask), (cs_base & cs_mask));
 
                if ((in_addr & cs_mask) == (cs_base & cs_mask)) {
                        cs_found = f10_process_possible_spare(pvt, dct, csrow);
 
-                       debugf1(" MATCH csrow=%d\n", cs_found);
+                       edac_dbg(1, " MATCH csrow=%d\n", cs_found);
                        break;
                }
        }
@@ -1505,8 +1497,8 @@ static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
        u8 intlv_en   = dram_intlv_en(pvt, range);
        u32 intlv_sel = dram_intlv_sel(pvt, range);
 
-       debugf1("(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
-               range, sys_addr, get_dram_limit(pvt, range));
+       edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
+                range, sys_addr, get_dram_limit(pvt, range));
 
        if (dhar_valid(pvt) &&
            dhar_base(pvt) <= sys_addr &&
@@ -1562,7 +1554,7 @@ static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
                                     (chan_addr & 0xfff);
        }
 
-       debugf1("   Normalized DCT addr: 0x%llx\n", chan_addr);
+       edac_dbg(1, "   Normalized DCT addr: 0x%llx\n", chan_addr);
 
        cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel);
 
@@ -1616,12 +1608,11 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
        csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
 
        if (csrow < 0) {
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                     page, offset, syndrome,
                                     -1, -1, -1,
-                                    EDAC_MOD_STR,
                                     "failed to map error addr to a csrow",
-                                    NULL);
+                                    "");
                return;
        }
 
@@ -1633,10 +1624,10 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
        if (dct_ganging_enabled(pvt))
                chan = get_channel_from_ecc_syndrome(mci, syndrome);
 
-       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                             page, offset, syndrome,
                             csrow, chan, -1,
-                            EDAC_MOD_STR, "", NULL);
+                            "", "");
 }
 
 /*
@@ -1664,7 +1655,8 @@ static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
        dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->csels[1].csbases
                                                   : pvt->csels[0].csbases;
 
-       debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", ctrl, dbam);
+       edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n",
+                ctrl, dbam);
 
        edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl);
 
@@ -1840,7 +1832,7 @@ static int decode_syndrome(u16 syndrome, u16 *vectors, unsigned num_vecs,
                }
        }
 
-       debugf0("syndrome(%x) not found\n", syndrome);
+       edac_dbg(0, "syndrome(%x) not found\n", syndrome);
        return -1;
 }
 
@@ -1917,12 +1909,11 @@ static void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m)
        /* Ensure that the Error Address is VALID */
        if (!(m->status & MCI_STATUS_ADDRV)) {
                amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                     0, 0, 0,
                                     -1, -1, -1,
-                                    EDAC_MOD_STR,
                                     "HW has no ERROR_ADDRESS available",
-                                    NULL);
+                                    "");
                return;
        }
 
@@ -1946,12 +1937,11 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
 
        if (!(m->status & MCI_STATUS_ADDRV)) {
                amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                     0, 0, 0,
                                     -1, -1, -1,
-                                    EDAC_MOD_STR,
                                     "HW has no ERROR_ADDRESS available",
-                                    NULL);
+                                    "");
                return;
        }
 
@@ -1966,11 +1956,11 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
        if (!src_mci) {
                amd64_mc_err(mci, "ERROR ADDRESS (0x%lx) NOT mapped to a MC\n",
                                  (unsigned long)sys_addr);
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                     page, offset, 0,
                                     -1, -1, -1,
-                                    EDAC_MOD_STR,
-                                    "ERROR ADDRESS NOT mapped to a MC", NULL);
+                                    "ERROR ADDRESS NOT mapped to a MC",
+                                    "");
                return;
        }
 
@@ -1980,17 +1970,16 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
        if (csrow < 0) {
                amd64_mc_err(mci, "ERROR_ADDRESS (0x%lx) NOT mapped to CS\n",
                                  (unsigned long)sys_addr);
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                     page, offset, 0,
                                     -1, -1, -1,
-                                    EDAC_MOD_STR,
                                     "ERROR ADDRESS NOT mapped to CS",
-                                    NULL);
+                                    "");
        } else {
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                     page, offset, 0,
                                     csrow, -1, -1,
-                                    EDAC_MOD_STR, "", NULL);
+                                    "", "");
        }
 }
 
@@ -2047,9 +2036,9 @@ static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 f1_id, u16 f3_id)
 
                return -ENODEV;
        }
-       debugf1("F1: %s\n", pci_name(pvt->F1));
-       debugf1("F2: %s\n", pci_name(pvt->F2));
-       debugf1("F3: %s\n", pci_name(pvt->F3));
+       edac_dbg(1, "F1: %s\n", pci_name(pvt->F1));
+       edac_dbg(1, "F2: %s\n", pci_name(pvt->F2));
+       edac_dbg(1, "F3: %s\n", pci_name(pvt->F3));
 
        return 0;
 }
@@ -2076,15 +2065,15 @@ static void read_mc_regs(struct amd64_pvt *pvt)
         * those are Read-As-Zero
         */
        rdmsrl(MSR_K8_TOP_MEM1, pvt->top_mem);
-       debugf0("  TOP_MEM:  0x%016llx\n", pvt->top_mem);
+       edac_dbg(0, "  TOP_MEM:  0x%016llx\n", pvt->top_mem);
 
        /* check first whether TOP_MEM2 is enabled */
        rdmsrl(MSR_K8_SYSCFG, msr_val);
        if (msr_val & (1U << 21)) {
                rdmsrl(MSR_K8_TOP_MEM2, pvt->top_mem2);
-               debugf0("  TOP_MEM2: 0x%016llx\n", pvt->top_mem2);
+               edac_dbg(0, "  TOP_MEM2: 0x%016llx\n", pvt->top_mem2);
        } else
-               debugf0("  TOP_MEM2 disabled.\n");
+               edac_dbg(0, "  TOP_MEM2 disabled\n");
 
        amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap);
 
@@ -2100,17 +2089,17 @@ static void read_mc_regs(struct amd64_pvt *pvt)
                if (!rw)
                        continue;
 
-               debugf1("  DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n",
-                       range,
-                       get_dram_base(pvt, range),
-                       get_dram_limit(pvt, range));
+               edac_dbg(1, "  DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n",
+                        range,
+                        get_dram_base(pvt, range),
+                        get_dram_limit(pvt, range));
 
-               debugf1("   IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n",
-                       dram_intlv_en(pvt, range) ? "Enabled" : "Disabled",
-                       (rw & 0x1) ? "R" : "-",
-                       (rw & 0x2) ? "W" : "-",
-                       dram_intlv_sel(pvt, range),
-                       dram_dst_node(pvt, range));
+               edac_dbg(1, "   IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n",
+                        dram_intlv_en(pvt, range) ? "Enabled" : "Disabled",
+                        (rw & 0x1) ? "R" : "-",
+                        (rw & 0x2) ? "W" : "-",
+                        dram_intlv_sel(pvt, range),
+                        dram_dst_node(pvt, range));
        }
 
        read_dct_base_mask(pvt);
@@ -2191,9 +2180,9 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
 
        nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
 
-       debugf0("  (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode);
-       debugf0("    nr_pages/channel= %u  channel-count = %d\n",
-               nr_pages, pvt->channel_count);
+       edac_dbg(0, "  (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode);
+       edac_dbg(0, "    nr_pages/channel= %u  channel-count = %d\n",
+                nr_pages, pvt->channel_count);
 
        return nr_pages;
 }
@@ -2205,6 +2194,7 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
 static int init_csrows(struct mem_ctl_info *mci)
 {
        struct csrow_info *csrow;
+       struct dimm_info *dimm;
        struct amd64_pvt *pvt = mci->pvt_info;
        u64 base, mask;
        u32 val;
@@ -2217,22 +2207,19 @@ static int init_csrows(struct mem_ctl_info *mci)
 
        pvt->nbcfg = val;
 
-       debugf0("node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
-               pvt->mc_node_id, val,
-               !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
+       edac_dbg(0, "node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
+                pvt->mc_node_id, val,
+                !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
 
        for_each_chip_select(i, 0, pvt) {
-               csrow = &mci->csrows[i];
+               csrow = mci->csrows[i];
 
                if (!csrow_enabled(i, 0, pvt) && !csrow_enabled(i, 1, pvt)) {
-                       debugf1("----CSROW %d EMPTY for node %d\n", i,
-                               pvt->mc_node_id);
+                       edac_dbg(1, "----CSROW %d VALID for MC node %d\n",
+                                i, pvt->mc_node_id);
                        continue;
                }
 
-               debugf1("----CSROW %d VALID for MC node %d\n",
-                       i, pvt->mc_node_id);
-
                empty = 0;
                if (csrow_enabled(i, 0, pvt))
                        nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
@@ -2244,8 +2231,9 @@ static int init_csrows(struct mem_ctl_info *mci)
 
                mtype = amd64_determine_memory_type(pvt, i);
 
-               debugf1("  for MC node %d csrow %d:\n", pvt->mc_node_id, i);
-               debugf1("    nr_pages: %u\n", nr_pages * pvt->channel_count);
+               edac_dbg(1, "  for MC node %d csrow %d:\n", pvt->mc_node_id, i);
+               edac_dbg(1, "    nr_pages: %u\n",
+                        nr_pages * pvt->channel_count);
 
                /*
                 * determine whether CHIPKILL or JUST ECC or NO ECC is operating
@@ -2257,9 +2245,10 @@ static int init_csrows(struct mem_ctl_info *mci)
                        edac_mode = EDAC_NONE;
 
                for (j = 0; j < pvt->channel_count; j++) {
-                       csrow->channels[j].dimm->mtype = mtype;
-                       csrow->channels[j].dimm->edac_mode = edac_mode;
-                       csrow->channels[j].dimm->nr_pages = nr_pages;
+                       dimm = csrow->channels[j]->dimm;
+                       dimm->mtype = mtype;
+                       dimm->edac_mode = edac_mode;
+                       dimm->nr_pages = nr_pages;
                }
        }
 
@@ -2296,9 +2285,9 @@ static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid)
                struct msr *reg = per_cpu_ptr(msrs, cpu);
                nbe = reg->l & MSR_MCGCTL_NBE;
 
-               debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
-                       cpu, reg->q,
-                       (nbe ? "enabled" : "disabled"));
+               edac_dbg(0, "core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
+                        cpu, reg->q,
+                        (nbe ? "enabled" : "disabled"));
 
                if (!nbe)
                        goto out;
@@ -2369,8 +2358,8 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
 
        amd64_read_pci_cfg(F3, NBCFG, &value);
 
-       debugf0("1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
-               nid, value, !!(value & NBCFG_ECC_ENABLE));
+       edac_dbg(0, "1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
+                nid, value, !!(value & NBCFG_ECC_ENABLE));
 
        if (!(value & NBCFG_ECC_ENABLE)) {
                amd64_warn("DRAM ECC disabled on this node, enabling...\n");
@@ -2394,8 +2383,8 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
                s->flags.nb_ecc_prev = 1;
        }
 
-       debugf0("2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
-               nid, value, !!(value & NBCFG_ECC_ENABLE));
+       edac_dbg(0, "2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
+                nid, value, !!(value & NBCFG_ECC_ENABLE));
 
        return ret;
 }
@@ -2463,26 +2452,29 @@ static bool ecc_enabled(struct pci_dev *F3, u8 nid)
        return true;
 }
 
-struct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) +
-                                         ARRAY_SIZE(amd64_inj_attrs) +
-                                         1];
-
-struct mcidev_sysfs_attribute terminator = { .attr = { .name = NULL } };
-
-static void set_mc_sysfs_attrs(struct mem_ctl_info *mci)
+static int set_mc_sysfs_attrs(struct mem_ctl_info *mci)
 {
-       unsigned int i = 0, j = 0;
+       int rc;
 
-       for (; i < ARRAY_SIZE(amd64_dbg_attrs); i++)
-               sysfs_attrs[i] = amd64_dbg_attrs[i];
+       rc = amd64_create_sysfs_dbg_files(mci);
+       if (rc < 0)
+               return rc;
 
-       if (boot_cpu_data.x86 >= 0x10)
-               for (j = 0; j < ARRAY_SIZE(amd64_inj_attrs); j++, i++)
-                       sysfs_attrs[i] = amd64_inj_attrs[j];
+       if (boot_cpu_data.x86 >= 0x10) {
+               rc = amd64_create_sysfs_inject_files(mci);
+               if (rc < 0)
+                       return rc;
+       }
+
+       return 0;
+}
 
-       sysfs_attrs[i] = terminator;
+static void del_mc_sysfs_attrs(struct mem_ctl_info *mci)
+{
+       amd64_remove_sysfs_dbg_files(mci);
 
-       mci->mc_driver_sysfs_attributes = sysfs_attrs;
+       if (boot_cpu_data.x86 >= 0x10)
+               amd64_remove_sysfs_inject_files(mci);
 }
 
 static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
@@ -2601,20 +2593,22 @@ static int amd64_init_one_instance(struct pci_dev *F2)
                goto err_siblings;
 
        mci->pvt_info = pvt;
-       mci->dev = &pvt->F2->dev;
+       mci->pdev = &pvt->F2->dev;
 
        setup_mci_misc_attrs(mci, fam_type);
 
        if (init_csrows(mci))
                mci->edac_cap = EDAC_FLAG_NONE;
 
-       set_mc_sysfs_attrs(mci);
-
        ret = -ENODEV;
        if (edac_mc_add_mc(mci)) {
-               debugf1("failed edac_mc_add_mc()\n");
+               edac_dbg(1, "failed edac_mc_add_mc()\n");
                goto err_add_mc;
        }
+       if (set_mc_sysfs_attrs(mci)) {
+               edac_dbg(1, "failed edac_mc_add_mc()\n");
+               goto err_add_sysfs;
+       }
 
        /* register stuff with EDAC MCE */
        if (report_gart_errors)
@@ -2628,6 +2622,8 @@ static int amd64_init_one_instance(struct pci_dev *F2)
 
        return 0;
 
+err_add_sysfs:
+       edac_mc_del_mc(mci->pdev);
 err_add_mc:
        edac_mc_free(mci);
 
@@ -2651,7 +2647,7 @@ static int __devinit amd64_probe_one_instance(struct pci_dev *pdev,
 
        ret = pci_enable_device(pdev);
        if (ret < 0) {
-               debugf0("ret=%d\n", ret);
+               edac_dbg(0, "ret=%d\n", ret);
                return -EIO;
        }
 
@@ -2698,6 +2694,8 @@ static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
        struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
        struct ecc_settings *s = ecc_stngs[nid];
 
+       mci = find_mci_by_dev(&pdev->dev);
+       del_mc_sysfs_attrs(mci);
        /* Remove from EDAC CORE tracking list */
        mci = edac_mc_del_mc(&pdev->dev);
        if (!mci)
index 9a666cb985b2bd446edba7c249f3740d23e49d8e..8d4804732bacb77be17f07465e48f24ea513ab0c 100644 (file)
@@ -413,20 +413,33 @@ struct ecc_settings {
 };
 
 #ifdef CONFIG_EDAC_DEBUG
-#define NUM_DBG_ATTRS 5
+int amd64_create_sysfs_dbg_files(struct mem_ctl_info *mci);
+void amd64_remove_sysfs_dbg_files(struct mem_ctl_info *mci);
+
 #else
-#define NUM_DBG_ATTRS 0
+static inline int amd64_create_sysfs_dbg_files(struct mem_ctl_info *mci)
+{
+       return 0;
+}
+static void inline amd64_remove_sysfs_dbg_files(struct mem_ctl_info *mci)
+{
+}
 #endif
 
 #ifdef CONFIG_EDAC_AMD64_ERROR_INJECTION
-#define NUM_INJ_ATTRS 5
+int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci);
+void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci);
+
 #else
-#define NUM_INJ_ATTRS 0
+static inline int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci)
+{
+       return 0;
+}
+static inline void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci)
+{
+}
 #endif
 
-extern struct mcidev_sysfs_attribute amd64_dbg_attrs[NUM_DBG_ATTRS],
-                                    amd64_inj_attrs[NUM_INJ_ATTRS];
-
 /*
  * Each of the PCI Device IDs types have their own set of hardware accessor
  * functions and per device encoding/decoding logic.
@@ -460,3 +473,5 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
 
 int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
                             u64 *hole_offset, u64 *hole_size);
+
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
index e3562288f4ce80589ab0680f4fc179335da80822..2c1bbf7406058f4f80e1edb170db160c488cdcbc 100644 (file)
@@ -1,8 +1,11 @@
 #include "amd64_edac.h"
 
 #define EDAC_DCT_ATTR_SHOW(reg)                                                \
-static ssize_t amd64_##reg##_show(struct mem_ctl_info *mci, char *data)        \
+static ssize_t amd64_##reg##_show(struct device *dev,                  \
+                              struct device_attribute *mattr,          \
+                              char *data)                              \
 {                                                                      \
+       struct mem_ctl_info *mci = to_mci(dev);                         \
        struct amd64_pvt *pvt = mci->pvt_info;                          \
                return sprintf(data, "0x%016llx\n", (u64)pvt->reg);     \
 }
@@ -12,8 +15,12 @@ EDAC_DCT_ATTR_SHOW(dbam0);
 EDAC_DCT_ATTR_SHOW(top_mem);
 EDAC_DCT_ATTR_SHOW(top_mem2);
 
-static ssize_t amd64_hole_show(struct mem_ctl_info *mci, char *data)
+static ssize_t amd64_hole_show(struct device *dev,
+                              struct device_attribute *mattr,
+                              char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
+
        u64 hole_base = 0;
        u64 hole_offset = 0;
        u64 hole_size = 0;
@@ -27,46 +34,40 @@ static ssize_t amd64_hole_show(struct mem_ctl_info *mci, char *data)
 /*
  * update NUM_DBG_ATTRS in case you add new members
  */
-struct mcidev_sysfs_attribute amd64_dbg_attrs[] = {
+static DEVICE_ATTR(dhar, S_IRUGO, amd64_dhar_show, NULL);
+static DEVICE_ATTR(dbam, S_IRUGO, amd64_dbam0_show, NULL);
+static DEVICE_ATTR(topmem, S_IRUGO, amd64_top_mem_show, NULL);
+static DEVICE_ATTR(topmem2, S_IRUGO, amd64_top_mem2_show, NULL);
+static DEVICE_ATTR(dram_hole, S_IRUGO, amd64_hole_show, NULL);
+
+int amd64_create_sysfs_dbg_files(struct mem_ctl_info *mci)
+{
+       int rc;
+
+       rc = device_create_file(&mci->dev, &dev_attr_dhar);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_dbam);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_topmem);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_topmem2);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_dram_hole);
+       if (rc < 0)
+               return rc;
 
-       {
-               .attr = {
-                       .name = "dhar",
-                       .mode = (S_IRUGO)
-               },
-               .show = amd64_dhar_show,
-               .store = NULL,
-       },
-       {
-               .attr = {
-                       .name = "dbam",
-                       .mode = (S_IRUGO)
-               },
-               .show = amd64_dbam0_show,
-               .store = NULL,
-       },
-       {
-               .attr = {
-                       .name = "topmem",
-                       .mode = (S_IRUGO)
-               },
-               .show = amd64_top_mem_show,
-               .store = NULL,
-       },
-       {
-               .attr = {
-                       .name = "topmem2",
-                       .mode = (S_IRUGO)
-               },
-               .show = amd64_top_mem2_show,
-               .store = NULL,
-       },
-       {
-               .attr = {
-                       .name = "dram_hole",
-                       .mode = (S_IRUGO)
-               },
-               .show = amd64_hole_show,
-               .store = NULL,
-       },
-};
+       return 0;
+}
+
+void amd64_remove_sysfs_dbg_files(struct mem_ctl_info *mci)
+{
+       device_remove_file(&mci->dev, &dev_attr_dhar);
+       device_remove_file(&mci->dev, &dev_attr_dbam);
+       device_remove_file(&mci->dev, &dev_attr_topmem);
+       device_remove_file(&mci->dev, &dev_attr_topmem2);
+       device_remove_file(&mci->dev, &dev_attr_dram_hole);
+}
index 303f10e03dda946b5aebce3c82c1f07b564ca53b..53d972e00dfb084d812419463b7a0984a9c1deda 100644 (file)
@@ -1,7 +1,10 @@
 #include "amd64_edac.h"
 
-static ssize_t amd64_inject_section_show(struct mem_ctl_info *mci, char *buf)
+static ssize_t amd64_inject_section_show(struct device *dev,
+                                        struct device_attribute *mattr,
+                                        char *buf)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct amd64_pvt *pvt = mci->pvt_info;
        return sprintf(buf, "0x%x\n", pvt->injection.section);
 }
@@ -12,9 +15,11 @@ static ssize_t amd64_inject_section_show(struct mem_ctl_info *mci, char *buf)
  *
  * range: 0..3
  */
-static ssize_t amd64_inject_section_store(struct mem_ctl_info *mci,
+static ssize_t amd64_inject_section_store(struct device *dev,
+                                         struct device_attribute *mattr,
                                          const char *data, size_t count)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct amd64_pvt *pvt = mci->pvt_info;
        unsigned long value;
        int ret = 0;
@@ -33,8 +38,11 @@ static ssize_t amd64_inject_section_store(struct mem_ctl_info *mci,
        return ret;
 }
 
-static ssize_t amd64_inject_word_show(struct mem_ctl_info *mci, char *buf)
+static ssize_t amd64_inject_word_show(struct device *dev,
+                                       struct device_attribute *mattr,
+                                       char *buf)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct amd64_pvt *pvt = mci->pvt_info;
        return sprintf(buf, "0x%x\n", pvt->injection.word);
 }
@@ -45,9 +53,11 @@ static ssize_t amd64_inject_word_show(struct mem_ctl_info *mci, char *buf)
  *
  * range: 0..8
  */
-static ssize_t amd64_inject_word_store(struct mem_ctl_info *mci,
-                                       const char *data, size_t count)
+static ssize_t amd64_inject_word_store(struct device *dev,
+                                      struct device_attribute *mattr,
+                                      const char *data, size_t count)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct amd64_pvt *pvt = mci->pvt_info;
        unsigned long value;
        int ret = 0;
@@ -66,8 +76,11 @@ static ssize_t amd64_inject_word_store(struct mem_ctl_info *mci,
        return ret;
 }
 
-static ssize_t amd64_inject_ecc_vector_show(struct mem_ctl_info *mci, char *buf)
+static ssize_t amd64_inject_ecc_vector_show(struct device *dev,
+                                           struct device_attribute *mattr,
+                                           char *buf)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct amd64_pvt *pvt = mci->pvt_info;
        return sprintf(buf, "0x%x\n", pvt->injection.bit_map);
 }
@@ -77,9 +90,11 @@ static ssize_t amd64_inject_ecc_vector_show(struct mem_ctl_info *mci, char *buf)
  * corresponding bit within the error injection word above. When used during a
  * DRAM ECC read, it holds the contents of the of the DRAM ECC bits.
  */
-static ssize_t amd64_inject_ecc_vector_store(struct mem_ctl_info *mci,
-                                            const char *data, size_t count)
+static ssize_t amd64_inject_ecc_vector_store(struct device *dev,
+                                      struct device_attribute *mattr,
+                                      const char *data, size_t count)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct amd64_pvt *pvt = mci->pvt_info;
        unsigned long value;
        int ret = 0;
@@ -103,9 +118,11 @@ static ssize_t amd64_inject_ecc_vector_store(struct mem_ctl_info *mci,
  * Do a DRAM ECC read. Assemble staged values in the pvt area, format into
  * fields needed by the injection registers and read the NB Array Data Port.
  */
-static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci,
-                                       const char *data, size_t count)
+static ssize_t amd64_inject_read_store(struct device *dev,
+                                      struct device_attribute *mattr,
+                                      const char *data, size_t count)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct amd64_pvt *pvt = mci->pvt_info;
        unsigned long value;
        u32 section, word_bits;
@@ -125,7 +142,8 @@ static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci,
                /* Issue 'word' and 'bit' along with the READ request */
                amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
 
-               debugf0("section=0x%x word_bits=0x%x\n", section, word_bits);
+               edac_dbg(0, "section=0x%x word_bits=0x%x\n",
+                        section, word_bits);
 
                return count;
        }
@@ -136,9 +154,11 @@ static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci,
  * Do a DRAM ECC write. Assemble staged values in the pvt area and format into
  * fields needed by the injection registers.
  */
-static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci,
+static ssize_t amd64_inject_write_store(struct device *dev,
+                                       struct device_attribute *mattr,
                                        const char *data, size_t count)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct amd64_pvt *pvt = mci->pvt_info;
        unsigned long value;
        u32 section, word_bits;
@@ -158,7 +178,8 @@ static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci,
                /* Issue 'word' and 'bit' along with the READ request */
                amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
 
-               debugf0("section=0x%x word_bits=0x%x\n", section, word_bits);
+               edac_dbg(0, "section=0x%x word_bits=0x%x\n",
+                        section, word_bits);
 
                return count;
        }
@@ -168,46 +189,47 @@ static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci,
 /*
  * update NUM_INJ_ATTRS in case you add new members
  */
-struct mcidev_sysfs_attribute amd64_inj_attrs[] = {
-
-       {
-               .attr = {
-                       .name = "inject_section",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show = amd64_inject_section_show,
-               .store = amd64_inject_section_store,
-       },
-       {
-               .attr = {
-                       .name = "inject_word",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show = amd64_inject_word_show,
-               .store = amd64_inject_word_store,
-       },
-       {
-               .attr = {
-                       .name = "inject_ecc_vector",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show = amd64_inject_ecc_vector_show,
-               .store = amd64_inject_ecc_vector_store,
-       },
-       {
-               .attr = {
-                       .name = "inject_write",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show = NULL,
-               .store = amd64_inject_write_store,
-       },
-       {
-               .attr = {
-                       .name = "inject_read",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show = NULL,
-               .store = amd64_inject_read_store,
-       },
-};
+
+static DEVICE_ATTR(inject_section, S_IRUGO | S_IWUSR,
+                  amd64_inject_section_show, amd64_inject_section_store);
+static DEVICE_ATTR(inject_word, S_IRUGO | S_IWUSR,
+                  amd64_inject_word_show, amd64_inject_word_store);
+static DEVICE_ATTR(inject_ecc_vector, S_IRUGO | S_IWUSR,
+                  amd64_inject_ecc_vector_show, amd64_inject_ecc_vector_store);
+static DEVICE_ATTR(inject_write, S_IRUGO | S_IWUSR,
+                  NULL, amd64_inject_write_store);
+static DEVICE_ATTR(inject_read, S_IRUGO | S_IWUSR,
+                  NULL, amd64_inject_read_store);
+
+
+int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci)
+{
+       int rc;
+
+       rc = device_create_file(&mci->dev, &dev_attr_inject_section);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_inject_word);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_inject_ecc_vector);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_inject_write);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_inject_read);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci)
+{
+       device_remove_file(&mci->dev, &dev_attr_inject_section);
+       device_remove_file(&mci->dev, &dev_attr_inject_word);
+       device_remove_file(&mci->dev, &dev_attr_inject_ecc_vector);
+       device_remove_file(&mci->dev, &dev_attr_inject_write);
+       device_remove_file(&mci->dev, &dev_attr_inject_read);
+}
index 9774d443fa57616a9f7e64ba06a2fae3e3bc2f92..29eeb68a200caf7cb091698d1acbecf4eca80bcb 100644 (file)
@@ -105,7 +105,7 @@ static void amd76x_get_error_info(struct mem_ctl_info *mci,
 {
        struct pci_dev *pdev;
 
-       pdev = to_pci_dev(mci->dev);
+       pdev = to_pci_dev(mci->pdev);
        pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS,
                        &info->ecc_mode_status);
 
@@ -145,10 +145,10 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
 
                if (handle_errors) {
                        row = (info->ecc_mode_status >> 4) & 0xf;
-                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
-                                            mci->csrows[row].first_page, 0, 0,
+                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
+                                            mci->csrows[row]->first_page, 0, 0,
                                             row, 0, -1,
-                                            mci->ctl_name, "", NULL);
+                                            mci->ctl_name, "");
                }
        }
 
@@ -160,10 +160,10 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
 
                if (handle_errors) {
                        row = info->ecc_mode_status & 0xf;
-                       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
-                                            mci->csrows[row].first_page, 0, 0,
+                       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
+                                            mci->csrows[row]->first_page, 0, 0,
                                             row, 0, -1,
-                                            mci->ctl_name, "", NULL);
+                                            mci->ctl_name, "");
                }
        }
 
@@ -180,7 +180,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
 static void amd76x_check(struct mem_ctl_info *mci)
 {
        struct amd76x_error_info info;
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
        amd76x_get_error_info(mci, &info);
        amd76x_process_error_info(mci, &info, 1);
 }
@@ -194,8 +194,8 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
        int index;
 
        for (index = 0; index < mci->nr_csrows; index++) {
-               csrow = &mci->csrows[index];
-               dimm = csrow->channels[0].dimm;
+               csrow = mci->csrows[index];
+               dimm = csrow->channels[0]->dimm;
 
                /* find the DRAM Chip Select Base address and mask */
                pci_read_config_dword(pdev,
@@ -241,7 +241,7 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
        u32 ems_mode;
        struct amd76x_error_info discard;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
        pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems);
        ems_mode = (ems >> 10) & 0x3;
 
@@ -256,8 +256,8 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
        if (mci == NULL)
                return -ENOMEM;
 
-       debugf0("%s(): mci = %p\n", __func__, mci);
-       mci->dev = &pdev->dev;
+       edac_dbg(0, "mci = %p\n", mci);
+       mci->pdev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_RDDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
        mci->edac_cap = ems_mode ?
@@ -276,7 +276,7 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
         * type of memory controller.  The ID is therefore hardcoded to 0.
         */
        if (edac_mc_add_mc(mci)) {
-               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "failed edac_mc_add_mc()\n");
                goto fail;
        }
 
@@ -292,7 +292,7 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
        }
 
        /* get this far and it's successful */
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
        return 0;
 
 fail:
@@ -304,7 +304,7 @@ fail:
 static int __devinit amd76x_init_one(struct pci_dev *pdev,
                                const struct pci_device_id *ent)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* don't need to call pci_enable_device() */
        return amd76x_probe1(pdev, ent->driver_data);
@@ -322,7 +322,7 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        if (amd76x_pci)
                edac_pci_release_generic_ctl(amd76x_pci);
index 69ee6aab5c716fefd0b919a5da4b46ef5c7c4a64..a1bbd8edd2575e4faf0633c972f1a6cf12a3815a 100644 (file)
@@ -33,10 +33,10 @@ struct cell_edac_priv
 static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
 {
        struct cell_edac_priv           *priv = mci->pvt_info;
-       struct csrow_info               *csrow = &mci->csrows[0];
+       struct csrow_info               *csrow = mci->csrows[0];
        unsigned long                   address, pfn, offset, syndrome;
 
-       dev_dbg(mci->dev, "ECC CE err on node %d, channel %d, ar = 0x%016llx\n",
+       dev_dbg(mci->pdev, "ECC CE err on node %d, channel %d, ar = 0x%016llx\n",
                priv->node, chan, ar);
 
        /* Address decoding is likely a bit bogus, to dbl check */
@@ -48,18 +48,18 @@ static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
        syndrome = (ar & 0x000000001fe00000ul) >> 21;
 
        /* TODO: Decoding of the error address */
-       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                             csrow->first_page + pfn, offset, syndrome,
-                            0, chan, -1, "", "", NULL);
+                            0, chan, -1, "", "");
 }
 
 static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
 {
        struct cell_edac_priv           *priv = mci->pvt_info;
-       struct csrow_info               *csrow = &mci->csrows[0];
+       struct csrow_info               *csrow = mci->csrows[0];
        unsigned long                   address, pfn, offset;
 
-       dev_dbg(mci->dev, "ECC UE err on node %d, channel %d, ar = 0x%016llx\n",
+       dev_dbg(mci->pdev, "ECC UE err on node %d, channel %d, ar = 0x%016llx\n",
                priv->node, chan, ar);
 
        /* Address decoding is likely a bit bogus, to dbl check */
@@ -70,9 +70,9 @@ static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
        offset = address & ~PAGE_MASK;
 
        /* TODO: Decoding of the error address */
-       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                             csrow->first_page + pfn, offset, 0,
-                            0, chan, -1, "", "", NULL);
+                            0, chan, -1, "", "");
 }
 
 static void cell_edac_check(struct mem_ctl_info *mci)
@@ -83,7 +83,7 @@ static void cell_edac_check(struct mem_ctl_info *mci)
        fir = in_be64(&priv->regs->mic_fir);
 #ifdef DEBUG
        if (fir != priv->prev_fir) {
-               dev_dbg(mci->dev, "fir change : 0x%016lx\n", fir);
+               dev_dbg(mci->pdev, "fir change : 0x%016lx\n", fir);
                priv->prev_fir = fir;
        }
 #endif
@@ -119,14 +119,14 @@ static void cell_edac_check(struct mem_ctl_info *mci)
                mb();   /* sync up */
 #ifdef DEBUG
                fir = in_be64(&priv->regs->mic_fir);
-               dev_dbg(mci->dev, "fir clear  : 0x%016lx\n", fir);
+               dev_dbg(mci->pdev, "fir clear  : 0x%016lx\n", fir);
 #endif
        }
 }
 
 static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
 {
-       struct csrow_info               *csrow = &mci->csrows[0];
+       struct csrow_info               *csrow = mci->csrows[0];
        struct dimm_info                *dimm;
        struct cell_edac_priv           *priv = mci->pvt_info;
        struct device_node              *np;
@@ -150,12 +150,12 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
                csrow->last_page = csrow->first_page + nr_pages - 1;
 
                for (j = 0; j < csrow->nr_channels; j++) {
-                       dimm = csrow->channels[j].dimm;
+                       dimm = csrow->channels[j]->dimm;
                        dimm->mtype = MEM_XDR;
                        dimm->edac_mode = EDAC_SECDED;
                        dimm->nr_pages = nr_pages / csrow->nr_channels;
                }
-               dev_dbg(mci->dev,
+               dev_dbg(mci->pdev,
                        "Initialized on node %d, chanmask=0x%x,"
                        " first_page=0x%lx, nr_pages=0x%x\n",
                        priv->node, priv->chanmask,
@@ -212,7 +212,7 @@ static int __devinit cell_edac_probe(struct platform_device *pdev)
        priv->regs = regs;
        priv->node = pdev->id;
        priv->chanmask = chanmask;
-       mci->dev = &pdev->dev;
+       mci->pdev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_XDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
        mci->edac_cap = EDAC_FLAG_EC | EDAC_FLAG_SECDED;
index e22030a9de66fbc0c38fd2d0b274b1464dda7a2f..c2ef1349587368d666d9465a3c6996b893d10771 100644 (file)
@@ -316,13 +316,12 @@ static void get_total_mem(struct cpc925_mc_pdata *pdata)
                reg += aw;
                size = of_read_number(reg, sw);
                reg += sw;
-               debugf1("%s: start 0x%lx, size 0x%lx\n", __func__,
-                       start, size);
+               edac_dbg(1, "start 0x%lx, size 0x%lx\n", start, size);
                pdata->total_mem += size;
        } while (reg < reg_end);
 
        of_node_put(np);
-       debugf0("%s: total_mem 0x%lx\n", __func__, pdata->total_mem);
+       edac_dbg(0, "total_mem 0x%lx\n", pdata->total_mem);
 }
 
 static void cpc925_init_csrows(struct mem_ctl_info *mci)
@@ -330,8 +329,9 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
        struct cpc925_mc_pdata *pdata = mci->pvt_info;
        struct csrow_info *csrow;
        struct dimm_info *dimm;
+       enum dev_type dtype;
        int index, j;
-       u32 mbmr, mbbar, bba;
+       u32 mbmr, mbbar, bba, grain;
        unsigned long row_size, nr_pages, last_nr_pages = 0;
 
        get_total_mem(pdata);
@@ -347,7 +347,7 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
                if (bba == 0)
                        continue; /* not populated */
 
-               csrow = &mci->csrows[index];
+               csrow = mci->csrows[index];
 
                row_size = bba * (1UL << 28);   /* 256M */
                csrow->first_page = last_nr_pages;
@@ -355,37 +355,36 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
                csrow->last_page = csrow->first_page + nr_pages - 1;
                last_nr_pages = csrow->last_page + 1;
 
+               switch (csrow->nr_channels) {
+               case 1: /* Single channel */
+                       grain = 32; /* four-beat burst of 32 bytes */
+                       break;
+               case 2: /* Dual channel */
+               default:
+                       grain = 64; /* four-beat burst of 64 bytes */
+                       break;
+               }
+               switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) {
+               case 6: /* 0110, no way to differentiate X8 VS X16 */
+               case 5: /* 0101 */
+               case 8: /* 1000 */
+                       dtype = DEV_X16;
+                       break;
+               case 7: /* 0111 */
+               case 9: /* 1001 */
+                       dtype = DEV_X8;
+                       break;
+               default:
+                       dtype = DEV_UNKNOWN;
+               break;
+               }
                for (j = 0; j < csrow->nr_channels; j++) {
-                       dimm = csrow->channels[j].dimm;
-
+                       dimm = csrow->channels[j]->dimm;
                        dimm->nr_pages = nr_pages / csrow->nr_channels;
                        dimm->mtype = MEM_RDDR;
                        dimm->edac_mode = EDAC_SECDED;
-
-                       switch (csrow->nr_channels) {
-                       case 1: /* Single channel */
-                               dimm->grain = 32; /* four-beat burst of 32 bytes */
-                               break;
-                       case 2: /* Dual channel */
-                       default:
-                               dimm->grain = 64; /* four-beat burst of 64 bytes */
-                               break;
-                       }
-
-                       switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) {
-                       case 6: /* 0110, no way to differentiate X8 VS X16 */
-                       case 5: /* 0101 */
-                       case 8: /* 1000 */
-                               dimm->dtype = DEV_X16;
-                               break;
-                       case 7: /* 0111 */
-                       case 9: /* 1001 */
-                               dimm->dtype = DEV_X8;
-                               break;
-                       default:
-                               dimm->dtype = DEV_UNKNOWN;
-                               break;
-                       }
+                       dimm->grain = grain;
+                       dimm->dtype = dtype;
                }
        }
 }
@@ -463,7 +462,7 @@ static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear,
        *csrow = rank;
 
 #ifdef CONFIG_EDAC_DEBUG
-       if (mci->csrows[rank].first_page == 0) {
+       if (mci->csrows[rank]->first_page == 0) {
                cpc925_mc_printk(mci, KERN_ERR, "ECC occurs in a "
                        "non-populated csrow, broken hardware?\n");
                return;
@@ -471,7 +470,7 @@ static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear,
 #endif
 
        /* Revert csrow number */
-       pa = mci->csrows[rank].first_page << PAGE_SHIFT;
+       pa = mci->csrows[rank]->first_page << PAGE_SHIFT;
 
        /* Revert column address */
        col += bcnt;
@@ -512,7 +511,7 @@ static void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear,
        *offset = pa & (PAGE_SIZE - 1);
        *pfn = pa >> PAGE_SHIFT;
 
-       debugf0("%s: ECC physical address 0x%lx\n", __func__, pa);
+       edac_dbg(0, "ECC physical address 0x%lx\n", pa);
 }
 
 static int cpc925_mc_find_channel(struct mem_ctl_info *mci, u16 syndrome)
@@ -555,18 +554,18 @@ static void cpc925_mc_check(struct mem_ctl_info *mci)
        if (apiexcp & CECC_EXCP_DETECTED) {
                cpc925_mc_printk(mci, KERN_INFO, "DRAM CECC Fault\n");
                channel = cpc925_mc_find_channel(mci, syndrome);
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                     pfn, offset, syndrome,
                                     csrow, channel, -1,
-                                    mci->ctl_name, "", NULL);
+                                    mci->ctl_name, "");
        }
 
        if (apiexcp & UECC_EXCP_DETECTED) {
                cpc925_mc_printk(mci, KERN_INFO, "DRAM UECC Fault\n");
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                     pfn, offset, 0,
                                     csrow, -1, -1,
-                                    mci->ctl_name, "", NULL);
+                                    mci->ctl_name, "");
        }
 
        cpc925_mc_printk(mci, KERN_INFO, "Dump registers:\n");
@@ -852,8 +851,8 @@ static void cpc925_add_edac_devices(void __iomem *vbase)
                        goto err2;
                }
 
-               debugf0("%s: Successfully added edac device for %s\n",
-                       __func__, dev_info->ctl_name);
+               edac_dbg(0, "Successfully added edac device for %s\n",
+                        dev_info->ctl_name);
 
                continue;
 
@@ -884,8 +883,8 @@ static void cpc925_del_edac_devices(void)
                if (dev_info->exit)
                        dev_info->exit(dev_info);
 
-               debugf0("%s: Successfully deleted edac device for %s\n",
-                       __func__, dev_info->ctl_name);
+               edac_dbg(0, "Successfully deleted edac device for %s\n",
+                        dev_info->ctl_name);
        }
 }
 
@@ -900,7 +899,7 @@ static int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci)
        mscr = __raw_readl(pdata->vbase + REG_MSCR_OFFSET);
        si = (mscr & MSCR_SI_MASK) >> MSCR_SI_SHIFT;
 
-       debugf0("%s, Mem Scrub Ctrl Register 0x%x\n", __func__, mscr);
+       edac_dbg(0, "Mem Scrub Ctrl Register 0x%x\n", mscr);
 
        if (((mscr & MSCR_SCRUB_MOD_MASK) != MSCR_BACKGR_SCRUB) ||
            (si == 0)) {
@@ -928,8 +927,7 @@ static int cpc925_mc_get_channels(void __iomem *vbase)
            ((mbcr & MBCR_64BITBUS_MASK) == 0))
                dual = 1;
 
-       debugf0("%s: %s channel\n", __func__,
-               (dual > 0) ? "Dual" : "Single");
+       edac_dbg(0, "%s channel\n", (dual > 0) ? "Dual" : "Single");
 
        return dual;
 }
@@ -944,7 +942,7 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
        struct resource *r;
        int res = 0, nr_channels;
 
-       debugf0("%s: %s platform device found!\n", __func__, pdev->name);
+       edac_dbg(0, "%s platform device found!\n", pdev->name);
 
        if (!devres_open_group(&pdev->dev, cpc925_probe, GFP_KERNEL)) {
                res = -ENOMEM;
@@ -995,7 +993,7 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
        pdata->edac_idx = edac_mc_idx++;
        pdata->name = pdev->name;
 
-       mci->dev = &pdev->dev;
+       mci->pdev = &pdev->dev;
        platform_set_drvdata(pdev, mci);
        mci->dev_name = dev_name(&pdev->dev);
        mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
@@ -1026,7 +1024,7 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
        cpc925_add_edac_devices(vbase);
 
        /* get this far and it's successful */
-       debugf0("%s: success\n", __func__);
+       edac_dbg(0, "success\n");
 
        res = 0;
        goto out;
index 3186512c97393f80e1da0748cf496746ba91e52e..a5ed6b795fd4331452dd112626218c102f565d40 100644 (file)
@@ -309,7 +309,7 @@ static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
        u32 remap;
        struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        if (page < pvt->tolm)
                return page;
@@ -335,7 +335,7 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
        int i;
        struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        /* convert the addr to 4k page */
        page = sec1_add >> (PAGE_SHIFT - 4);
@@ -371,10 +371,10 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
        channel = !(error_one & 1);
 
        /* e752x mc reads 34:6 of the DRAM linear address */
-       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                             page, offset_in_page(sec1_add << 4), sec1_syndrome,
                             row, channel, -1,
-                            "e752x CE", "", NULL);
+                            "e752x CE", "");
 }
 
 static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
@@ -394,7 +394,7 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
        int row;
        struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        if (error_one & 0x0202) {
                error_2b = ded_add;
@@ -408,11 +408,11 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
                        edac_mc_find_csrow_by_page(mci, block_page);
 
                /* e752x mc reads 34:6 of the DRAM linear address */
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                        block_page,
                                        offset_in_page(error_2b << 4), 0,
                                         row, -1, -1,
-                                       "e752x UE from Read", "", NULL);
+                                       "e752x UE from Read", "");
 
        }
        if (error_one & 0x0404) {
@@ -427,11 +427,11 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
                        edac_mc_find_csrow_by_page(mci, block_page);
 
                /* e752x mc reads 34:6 of the DRAM linear address */
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                        block_page,
                                        offset_in_page(error_2b << 4), 0,
                                        row, -1, -1,
-                                       "e752x UE from Scruber", "", NULL);
+                                       "e752x UE from Scruber", "");
        }
 }
 
@@ -453,10 +453,10 @@ static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
        if (!handle_error)
                return;
 
-       debugf3("%s()\n", __func__);
-       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
+       edac_dbg(3, "\n");
+       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
                             -1, -1, -1,
-                            "e752x UE log memory write", "", NULL);
+                            "e752x UE log memory write", "");
 }
 
 static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error,
@@ -982,7 +982,7 @@ static void e752x_check(struct mem_ctl_info *mci)
 {
        struct e752x_error_info info;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
        e752x_get_error_info(mci, &info);
        e752x_process_error_info(mci, &info, 1);
 }
@@ -1069,6 +1069,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
                        u16 ddrcsr)
 {
        struct csrow_info *csrow;
+       enum edac_type edac_mode;
        unsigned long last_cumul_size;
        int index, mem_dev, drc_chan;
        int drc_drbg;           /* DRB granularity 0=64mb, 1=128mb */
@@ -1095,14 +1096,13 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
        for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
                /* mem_dev 0=x8, 1=x4 */
                mem_dev = (dra >> (index * 4 + 2)) & 0x3;
-               csrow = &mci->csrows[remap_csrow_index(mci, index)];
+               csrow = mci->csrows[remap_csrow_index(mci, index)];
 
                mem_dev = (mem_dev == 2);
                pci_read_config_byte(pdev, E752X_DRB + index, &value);
                /* convert a 128 or 64 MiB DRB to a page size. */
                cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
-               debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
-                       cumul_size);
+               edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size);
                if (cumul_size == last_cumul_size)
                        continue;       /* not populated */
 
@@ -1111,29 +1111,29 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
                nr_pages = cumul_size - last_cumul_size;
                last_cumul_size = cumul_size;
 
+               /*
+               * if single channel or x8 devices then SECDED
+               * if dual channel and x4 then S4ECD4ED
+               */
+               if (drc_ddim) {
+                       if (drc_chan && mem_dev) {
+                               edac_mode = EDAC_S4ECD4ED;
+                               mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
+                       } else {
+                               edac_mode = EDAC_SECDED;
+                               mci->edac_cap |= EDAC_FLAG_SECDED;
+                       }
+               } else
+                       edac_mode = EDAC_NONE;
                for (i = 0; i < csrow->nr_channels; i++) {
-                       struct dimm_info *dimm = csrow->channels[i].dimm;
+                       struct dimm_info *dimm = csrow->channels[i]->dimm;
 
-                       debugf3("Initializing rank at (%i,%i)\n", index, i);
+                       edac_dbg(3, "Initializing rank at (%i,%i)\n", index, i);
                        dimm->nr_pages = nr_pages / csrow->nr_channels;
                        dimm->grain = 1 << 12;  /* 4KiB - resolution of CELOG */
                        dimm->mtype = MEM_RDDR; /* only one type supported */
                        dimm->dtype = mem_dev ? DEV_X4 : DEV_X8;
-
-                       /*
-                       * if single channel or x8 devices then SECDED
-                       * if dual channel and x4 then S4ECD4ED
-                       */
-                       if (drc_ddim) {
-                               if (drc_chan && mem_dev) {
-                                       dimm->edac_mode = EDAC_S4ECD4ED;
-                                       mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
-                               } else {
-                                       dimm->edac_mode = EDAC_SECDED;
-                                       mci->edac_cap |= EDAC_FLAG_SECDED;
-                               }
-                       } else
-                               dimm->edac_mode = EDAC_NONE;
+                       dimm->edac_mode = edac_mode;
                }
        }
 }
@@ -1269,8 +1269,8 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
        int drc_chan;           /* Number of channels 0=1chan,1=2chan */
        struct e752x_error_info discard;
 
-       debugf0("%s(): mci\n", __func__);
-       debugf0("Starting Probe1\n");
+       edac_dbg(0, "mci\n");
+       edac_dbg(0, "Starting Probe1\n");
 
        /* check to see if device 0 function 1 is enabled; if it isn't, we
         * assume the BIOS has reserved it for a reason and is expecting
@@ -1300,7 +1300,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
        if (mci == NULL)
                return -ENOMEM;
 
-       debugf3("%s(): init mci\n", __func__);
+       edac_dbg(3, "init mci\n");
        mci->mtype_cap = MEM_FLAG_RDDR;
        /* 3100 IMCH supports SECDEC only */
        mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED :
@@ -1308,9 +1308,9 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
        /* FIXME - what if different memory types are in different csrows? */
        mci->mod_name = EDAC_MOD_STR;
        mci->mod_ver = E752X_REVISION;
-       mci->dev = &pdev->dev;
+       mci->pdev = &pdev->dev;
 
-       debugf3("%s(): init pvt\n", __func__);
+       edac_dbg(3, "init pvt\n");
        pvt = (struct e752x_pvt *)mci->pvt_info;
        pvt->dev_info = &e752x_devs[dev_idx];
        pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
@@ -1320,7 +1320,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
                return -ENODEV;
        }
 
-       debugf3("%s(): more mci init\n", __func__);
+       edac_dbg(3, "more mci init\n");
        mci->ctl_name = pvt->dev_info->ctl_name;
        mci->dev_name = pci_name(pdev);
        mci->edac_check = e752x_check;
@@ -1342,7 +1342,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
                mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */
        else
                mci->edac_cap |= EDAC_FLAG_NONE;
-       debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
+       edac_dbg(3, "tolm, remapbase, remaplimit\n");
 
        /* load the top of low memory, remap base, and remap limit vars */
        pci_read_config_word(pdev, E752X_TOLM, &pci_data);
@@ -1359,7 +1359,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
         * type of memory controller.  The ID is therefore hardcoded to 0.
         */
        if (edac_mc_add_mc(mci)) {
-               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "failed edac_mc_add_mc()\n");
                goto fail;
        }
 
@@ -1377,7 +1377,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
        }
 
        /* get this far and it's successful */
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
        return 0;
 
 fail:
@@ -1393,7 +1393,7 @@ fail:
 static int __devinit e752x_init_one(struct pci_dev *pdev,
                                const struct pci_device_id *ent)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* wake up and enable device */
        if (pci_enable_device(pdev) < 0)
@@ -1407,7 +1407,7 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
        struct mem_ctl_info *mci;
        struct e752x_pvt *pvt;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        if (e752x_pci)
                edac_pci_release_generic_ctl(e752x_pci);
@@ -1453,7 +1453,7 @@ static int __init e752x_init(void)
 {
        int pci_rc;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -1464,7 +1464,7 @@ static int __init e752x_init(void)
 
 static void __exit e752x_exit(void)
 {
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
        pci_unregister_driver(&e752x_driver);
 }
 
index 9a9c1a5467977ca6bb69042651310b2830275757..9ff57f361a43384e0d86be624067fb64cdc6e36b 100644 (file)
@@ -166,7 +166,7 @@ static const struct e7xxx_dev_info e7xxx_devs[] = {
 /* FIXME - is this valid for both SECDED and S4ECD4ED? */
 static inline int e7xxx_find_channel(u16 syndrome)
 {
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        if ((syndrome & 0xff00) == 0)
                return 0;
@@ -186,7 +186,7 @@ static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
        u32 remap;
        struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        if ((page < pvt->tolm) ||
                ((page >= 0x100000) && (page < pvt->remapbase)))
@@ -208,7 +208,7 @@ static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
        int row;
        int channel;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
        /* read the error address */
        error_1b = info->dram_celog_add;
        /* FIXME - should use PAGE_SHIFT */
@@ -219,15 +219,15 @@ static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
        row = edac_mc_find_csrow_by_page(mci, page);
        /* convert syndrome to channel */
        channel = e7xxx_find_channel(syndrome);
-       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, page, 0, syndrome,
-                            row, channel, -1, "e7xxx CE", "", NULL);
+       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, page, 0, syndrome,
+                            row, channel, -1, "e7xxx CE", "");
 }
 
 static void process_ce_no_info(struct mem_ctl_info *mci)
 {
-       debugf3("%s()\n", __func__);
-       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, -1, -1, -1,
-                            "e7xxx CE log register overflow", "", NULL);
+       edac_dbg(3, "\n");
+       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, -1, -1, -1,
+                            "e7xxx CE log register overflow", "");
 }
 
 static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
@@ -235,23 +235,23 @@ static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
        u32 error_2b, block_page;
        int row;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
        /* read the error address */
        error_2b = info->dram_uelog_add;
        /* FIXME - should use PAGE_SHIFT */
        block_page = error_2b >> 6;     /* convert to 4k address */
        row = edac_mc_find_csrow_by_page(mci, block_page);
 
-       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, block_page, 0, 0,
-                            row, -1, -1, "e7xxx UE", "", NULL);
+       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, block_page, 0, 0,
+                            row, -1, -1, "e7xxx UE", "");
 }
 
 static void process_ue_no_info(struct mem_ctl_info *mci)
 {
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
-       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, -1, -1, -1,
-                            "e7xxx UE log register overflow", "", NULL);
+       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0, -1, -1, -1,
+                            "e7xxx UE log register overflow", "");
 }
 
 static void e7xxx_get_error_info(struct mem_ctl_info *mci,
@@ -334,7 +334,7 @@ static void e7xxx_check(struct mem_ctl_info *mci)
 {
        struct e7xxx_error_info info;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
        e7xxx_get_error_info(mci, &info);
        e7xxx_process_error_info(mci, &info, 1);
 }
@@ -362,6 +362,7 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
        int drc_chan, drc_drbg, drc_ddim, mem_dev;
        struct csrow_info *csrow;
        struct dimm_info *dimm;
+       enum edac_type edac_mode;
 
        pci_read_config_dword(pdev, E7XXX_DRA, &dra);
        drc_chan = dual_channel_active(drc, dev_idx);
@@ -377,13 +378,12 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
        for (index = 0; index < mci->nr_csrows; index++) {
                /* mem_dev 0=x8, 1=x4 */
                mem_dev = (dra >> (index * 4 + 3)) & 0x1;
-               csrow = &mci->csrows[index];
+               csrow = mci->csrows[index];
 
                pci_read_config_byte(pdev, E7XXX_DRB + index, &value);
                /* convert a 64 or 32 MiB DRB to a page size. */
                cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
-               debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
-                       cumul_size);
+               edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size);
                if (cumul_size == last_cumul_size)
                        continue;       /* not populated */
 
@@ -392,28 +392,29 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
                nr_pages = cumul_size - last_cumul_size;
                last_cumul_size = cumul_size;
 
+               /*
+               * if single channel or x8 devices then SECDED
+               * if dual channel and x4 then S4ECD4ED
+               */
+               if (drc_ddim) {
+                       if (drc_chan && mem_dev) {
+                               edac_mode = EDAC_S4ECD4ED;
+                               mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
+                       } else {
+                               edac_mode = EDAC_SECDED;
+                               mci->edac_cap |= EDAC_FLAG_SECDED;
+                       }
+               } else
+                       edac_mode = EDAC_NONE;
+
                for (j = 0; j < drc_chan + 1; j++) {
-                       dimm = csrow->channels[j].dimm;
+                       dimm = csrow->channels[j]->dimm;
 
                        dimm->nr_pages = nr_pages / (drc_chan + 1);
                        dimm->grain = 1 << 12;  /* 4KiB - resolution of CELOG */
                        dimm->mtype = MEM_RDDR; /* only one type supported */
                        dimm->dtype = mem_dev ? DEV_X4 : DEV_X8;
-
-                       /*
-                       * if single channel or x8 devices then SECDED
-                       * if dual channel and x4 then S4ECD4ED
-                       */
-                       if (drc_ddim) {
-                               if (drc_chan && mem_dev) {
-                                       dimm->edac_mode = EDAC_S4ECD4ED;
-                                       mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
-                               } else {
-                                       dimm->edac_mode = EDAC_SECDED;
-                                       mci->edac_cap |= EDAC_FLAG_SECDED;
-                               }
-                       } else
-                               dimm->edac_mode = EDAC_NONE;
+                       dimm->edac_mode = edac_mode;
                }
        }
 }
@@ -428,7 +429,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
        int drc_chan;
        struct e7xxx_error_info discard;
 
-       debugf0("%s(): mci\n", __func__);
+       edac_dbg(0, "mci\n");
 
        pci_read_config_dword(pdev, E7XXX_DRC, &drc);
 
@@ -451,15 +452,15 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
        if (mci == NULL)
                return -ENOMEM;
 
-       debugf3("%s(): init mci\n", __func__);
+       edac_dbg(3, "init mci\n");
        mci->mtype_cap = MEM_FLAG_RDDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
                EDAC_FLAG_S4ECD4ED;
        /* FIXME - what if different memory types are in different csrows? */
        mci->mod_name = EDAC_MOD_STR;
        mci->mod_ver = E7XXX_REVISION;
-       mci->dev = &pdev->dev;
-       debugf3("%s(): init pvt\n", __func__);
+       mci->pdev = &pdev->dev;
+       edac_dbg(3, "init pvt\n");
        pvt = (struct e7xxx_pvt *)mci->pvt_info;
        pvt->dev_info = &e7xxx_devs[dev_idx];
        pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
@@ -472,14 +473,14 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
                goto fail0;
        }
 
-       debugf3("%s(): more mci init\n", __func__);
+       edac_dbg(3, "more mci init\n");
        mci->ctl_name = pvt->dev_info->ctl_name;
        mci->dev_name = pci_name(pdev);
        mci->edac_check = e7xxx_check;
        mci->ctl_page_to_phys = ctl_page_to_phys;
        e7xxx_init_csrows(mci, pdev, dev_idx, drc);
        mci->edac_cap |= EDAC_FLAG_NONE;
-       debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
+       edac_dbg(3, "tolm, remapbase, remaplimit\n");
        /* load the top of low memory, remap base, and remap limit vars */
        pci_read_config_word(pdev, E7XXX_TOLM, &pci_data);
        pvt->tolm = ((u32) pci_data) << 4;
@@ -498,7 +499,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
         * type of memory controller.  The ID is therefore hardcoded to 0.
         */
        if (edac_mc_add_mc(mci)) {
-               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "failed edac_mc_add_mc()\n");
                goto fail1;
        }
 
@@ -514,7 +515,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
        }
 
        /* get this far and it's successful */
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
        return 0;
 
 fail1:
@@ -530,7 +531,7 @@ fail0:
 static int __devinit e7xxx_init_one(struct pci_dev *pdev,
                                const struct pci_device_id *ent)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* wake up and enable device */
        return pci_enable_device(pdev) ?
@@ -542,7 +543,7 @@ static void __devexit e7xxx_remove_one(struct pci_dev *pdev)
        struct mem_ctl_info *mci;
        struct e7xxx_pvt *pvt;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        if (e7xxx_pci)
                edac_pci_release_generic_ctl(e7xxx_pci);
index 117490d4f8359d0fbe9ab50729270e1e0424fe09..23bb99fa44f1e7ffc6307eeb9d64fbda43f591d4 100644 (file)
@@ -71,26 +71,21 @@ extern const char *edac_mem_types[];
 #ifdef CONFIG_EDAC_DEBUG
 extern int edac_debug_level;
 
-#define edac_debug_printk(level, fmt, arg...)                           \
-       do {                                                            \
-               if (level <= edac_debug_level)                          \
-                       edac_printk(KERN_DEBUG, EDAC_DEBUG,             \
-                                   "%s: " fmt, __func__, ##arg);       \
-       } while (0)
-
-#define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
-#define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ )
-#define debugf2( ... ) edac_debug_printk(2, __VA_ARGS__ )
-#define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ )
-#define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ )
+#define edac_dbg(level, fmt, ...)                                      \
+do {                                                                   \
+       if (level <= edac_debug_level)                                  \
+               edac_printk(KERN_DEBUG, EDAC_DEBUG,                     \
+                           "%s: " fmt, __func__, ##__VA_ARGS__);       \
+} while (0)
 
 #else                          /* !CONFIG_EDAC_DEBUG */
 
-#define debugf0( ... )
-#define debugf1( ... )
-#define debugf2( ... )
-#define debugf3( ... )
-#define debugf4( ... )
+#define edac_dbg(level, fmt, ...)                                      \
+do {                                                                   \
+       if (0)                                                          \
+               edac_printk(KERN_DEBUG, EDAC_DEBUG,                     \
+                           "%s: " fmt, __func__, ##__VA_ARGS__);       \
+} while (0)
 
 #endif                         /* !CONFIG_EDAC_DEBUG */
 
@@ -460,15 +455,15 @@ extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
                                      unsigned long page);
 void edac_mc_handle_error(const enum hw_event_mc_err_type type,
                          struct mem_ctl_info *mci,
+                         const u16 error_count,
                          const unsigned long page_frame_number,
                          const unsigned long offset_in_page,
                          const unsigned long syndrome,
-                         const int layer0,
-                         const int layer1,
-                         const int layer2,
+                         const int top_layer,
+                         const int mid_layer,
+                         const int low_layer,
                          const char *msg,
-                         const char *other_detail,
-                         const void *mcelog);
+                         const char *other_detail);
 
 /*
  * edac_device APIs
index ee3f1f810c1e094c27dbd012d51c4cdfa9b4ee55..211021dfec734a5e5466e2155eaf108ee4ec997c 100644 (file)
@@ -40,12 +40,13 @@ static LIST_HEAD(edac_device_list);
 #ifdef CONFIG_EDAC_DEBUG
 static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
 {
-       debugf3("\tedac_dev = %p dev_idx=%d \n", edac_dev, edac_dev->dev_idx);
-       debugf4("\tedac_dev->edac_check = %p\n", edac_dev->edac_check);
-       debugf3("\tdev = %p\n", edac_dev->dev);
-       debugf3("\tmod_name:ctl_name = %s:%s\n",
-               edac_dev->mod_name, edac_dev->ctl_name);
-       debugf3("\tpvt_info = %p\n\n", edac_dev->pvt_info);
+       edac_dbg(3, "\tedac_dev = %p dev_idx=%d\n",
+                edac_dev, edac_dev->dev_idx);
+       edac_dbg(4, "\tedac_dev->edac_check = %p\n", edac_dev->edac_check);
+       edac_dbg(3, "\tdev = %p\n", edac_dev->dev);
+       edac_dbg(3, "\tmod_name:ctl_name = %s:%s\n",
+                edac_dev->mod_name, edac_dev->ctl_name);
+       edac_dbg(3, "\tpvt_info = %p\n\n", edac_dev->pvt_info);
 }
 #endif                         /* CONFIG_EDAC_DEBUG */
 
@@ -82,8 +83,7 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
        void *pvt, *p;
        int err;
 
-       debugf4("%s() instances=%d blocks=%d\n",
-               __func__, nr_instances, nr_blocks);
+       edac_dbg(4, "instances=%d blocks=%d\n", nr_instances, nr_blocks);
 
        /* Calculate the size of memory we need to allocate AND
         * determine the offsets of the various item arrays
@@ -156,8 +156,8 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
        /* Name of this edac device */
        snprintf(dev_ctl->name,sizeof(dev_ctl->name),"%s",edac_device_name);
 
-       debugf4("%s() edac_dev=%p next after end=%p\n",
-               __func__, dev_ctl, pvt + sz_private );
+       edac_dbg(4, "edac_dev=%p next after end=%p\n",
+                dev_ctl, pvt + sz_private);
 
        /* Initialize every Instance */
        for (instance = 0; instance < nr_instances; instance++) {
@@ -178,10 +178,8 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
                        snprintf(blk->name, sizeof(blk->name),
                                 "%s%d", edac_block_name, block+offset_value);
 
-                       debugf4("%s() instance=%d inst_p=%p block=#%d "
-                               "block_p=%p name='%s'\n",
-                               __func__, instance, inst, block,
-                               blk, blk->name);
+                       edac_dbg(4, "instance=%d inst_p=%p block=#%d block_p=%p name='%s'\n",
+                                instance, inst, block, blk, blk->name);
 
                        /* if there are NO attributes OR no attribute pointer
                         * then continue on to next block iteration
@@ -194,8 +192,8 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
                        attrib_p = &dev_attrib[block*nr_instances*nr_attrib];
                        blk->block_attributes = attrib_p;
 
-                       debugf4("%s() THIS BLOCK_ATTRIB=%p\n",
-                               __func__, blk->block_attributes);
+                       edac_dbg(4, "THIS BLOCK_ATTRIB=%p\n",
+                                blk->block_attributes);
 
                        /* Initialize every user specified attribute in this
                         * block with the data the caller passed in
@@ -214,11 +212,10 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
 
                                attrib->block = blk;    /* up link */
 
-                               debugf4("%s() alloc-attrib=%p attrib_name='%s' "
-                                       "attrib-spec=%p spec-name=%s\n",
-                                       __func__, attrib, attrib->attr.name,
-                                       &attrib_spec[attr],
-                                       attrib_spec[attr].attr.name
+                               edac_dbg(4, "alloc-attrib=%p attrib_name='%s' attrib-spec=%p spec-name=%s\n",
+                                        attrib, attrib->attr.name,
+                                        &attrib_spec[attr],
+                                        attrib_spec[attr].attr.name
                                        );
                        }
                }
@@ -273,7 +270,7 @@ static struct edac_device_ctl_info *find_edac_device_by_dev(struct device *dev)
        struct edac_device_ctl_info *edac_dev;
        struct list_head *item;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        list_for_each(item, &edac_device_list) {
                edac_dev = list_entry(item, struct edac_device_ctl_info, link);
@@ -408,7 +405,7 @@ static void edac_device_workq_function(struct work_struct *work_req)
 void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
                                unsigned msec)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* take the arg 'msec' and set it into the control structure
         * to used in the time period calculation
@@ -496,7 +493,7 @@ EXPORT_SYMBOL_GPL(edac_device_alloc_index);
  */
 int edac_device_add_device(struct edac_device_ctl_info *edac_dev)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
 #ifdef CONFIG_EDAC_DEBUG
        if (edac_debug_level >= 3)
@@ -570,7 +567,7 @@ struct edac_device_ctl_info *edac_device_del_device(struct device *dev)
 {
        struct edac_device_ctl_info *edac_dev;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        mutex_lock(&device_ctls_mutex);
 
index b4ea185ccebf6f42e32536cae7f6c54e9064ecf5..fb68a06ad6837fcce67b3a3baefb98026ad146c3 100644 (file)
@@ -202,7 +202,7 @@ static void edac_device_ctrl_master_release(struct kobject *kobj)
 {
        struct edac_device_ctl_info *edac_dev = to_edacdev(kobj);
 
-       debugf4("%s() control index=%d\n", __func__, edac_dev->dev_idx);
+       edac_dbg(4, "control index=%d\n", edac_dev->dev_idx);
 
        /* decrement the EDAC CORE module ref count */
        module_put(edac_dev->owner);
@@ -233,12 +233,12 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
        struct bus_type *edac_subsys;
        int err;
 
-       debugf1("%s()\n", __func__);
+       edac_dbg(1, "\n");
 
        /* get the /sys/devices/system/edac reference */
        edac_subsys = edac_get_sysfs_subsys();
        if (edac_subsys == NULL) {
-               debugf1("%s() no edac_subsys error\n", __func__);
+               edac_dbg(1, "no edac_subsys error\n");
                err = -ENODEV;
                goto err_out;
        }
@@ -264,8 +264,8 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
                                   &edac_subsys->dev_root->kobj,
                                   "%s", edac_dev->name);
        if (err) {
-               debugf1("%s()Failed to register '.../edac/%s'\n",
-                       __func__, edac_dev->name);
+               edac_dbg(1, "Failed to register '.../edac/%s'\n",
+                        edac_dev->name);
                goto err_kobj_reg;
        }
        kobject_uevent(&edac_dev->kobj, KOBJ_ADD);
@@ -274,8 +274,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
         * edac_device_unregister_sysfs_main_kobj() must be used
         */
 
-       debugf4("%s() Registered '.../edac/%s' kobject\n",
-               __func__, edac_dev->name);
+       edac_dbg(4, "Registered '.../edac/%s' kobject\n", edac_dev->name);
 
        return 0;
 
@@ -296,9 +295,8 @@ err_out:
  */
 void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev)
 {
-       debugf0("%s()\n", __func__);
-       debugf4("%s() name of kobject is: %s\n",
-               __func__, kobject_name(&dev->kobj));
+       edac_dbg(0, "\n");
+       edac_dbg(4, "name of kobject is: %s\n", kobject_name(&dev->kobj));
 
        /*
         * Unregister the edac device's kobject and
@@ -336,7 +334,7 @@ static void edac_device_ctrl_instance_release(struct kobject *kobj)
 {
        struct edac_device_instance *instance;
 
-       debugf1("%s()\n", __func__);
+       edac_dbg(1, "\n");
 
        /* map from this kobj to the main control struct
         * and then dec the main kobj count
@@ -442,7 +440,7 @@ static void edac_device_ctrl_block_release(struct kobject *kobj)
 {
        struct edac_device_block *block;
 
-       debugf1("%s()\n", __func__);
+       edac_dbg(1, "\n");
 
        /* get the container of the kobj */
        block = to_block(kobj);
@@ -524,10 +522,10 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
        struct edac_dev_sysfs_block_attribute *sysfs_attrib;
        struct kobject *main_kobj;
 
-       debugf4("%s() Instance '%s' inst_p=%p  block '%s'  block_p=%p\n",
-               __func__, instance->name, instance, block->name, block);
-       debugf4("%s() block kobj=%p  block kobj->parent=%p\n",
-               __func__, &block->kobj, &block->kobj.parent);
+       edac_dbg(4, "Instance '%s' inst_p=%p  block '%s'  block_p=%p\n",
+                instance->name, instance, block->name, block);
+       edac_dbg(4, "block kobj=%p  block kobj->parent=%p\n",
+                &block->kobj, &block->kobj.parent);
 
        /* init this block's kobject */
        memset(&block->kobj, 0, sizeof(struct kobject));
@@ -546,8 +544,7 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
                                   &instance->kobj,
                                   "%s", block->name);
        if (err) {
-               debugf1("%s() Failed to register instance '%s'\n",
-                       __func__, block->name);
+               edac_dbg(1, "Failed to register instance '%s'\n", block->name);
                kobject_put(main_kobj);
                err = -ENODEV;
                goto err_out;
@@ -560,11 +557,9 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
        if (sysfs_attrib && block->nr_attribs) {
                for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
 
-                       debugf4("%s() creating block attrib='%s' "
-                               "attrib->%p to kobj=%p\n",
-                               __func__,
-                               sysfs_attrib->attr.name,
-                               sysfs_attrib, &block->kobj);
+                       edac_dbg(4, "creating block attrib='%s' attrib->%p to kobj=%p\n",
+                                sysfs_attrib->attr.name,
+                                sysfs_attrib, &block->kobj);
 
                        /* Create each block_attribute file */
                        err = sysfs_create_file(&block->kobj,
@@ -647,14 +642,14 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
        err = kobject_init_and_add(&instance->kobj, &ktype_instance_ctrl,
                                   &edac_dev->kobj, "%s", instance->name);
        if (err != 0) {
-               debugf2("%s() Failed to register instance '%s'\n",
-                       __func__, instance->name);
+               edac_dbg(2, "Failed to register instance '%s'\n",
+                        instance->name);
                kobject_put(main_kobj);
                goto err_out;
        }
 
-       debugf4("%s() now register '%d' blocks for instance %d\n",
-               __func__, instance->nr_blocks, idx);
+       edac_dbg(4, "now register '%d' blocks for instance %d\n",
+                instance->nr_blocks, idx);
 
        /* register all blocks of this instance */
        for (i = 0; i < instance->nr_blocks; i++) {
@@ -670,8 +665,8 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
        }
        kobject_uevent(&instance->kobj, KOBJ_ADD);
 
-       debugf4("%s() Registered instance %d '%s' kobject\n",
-               __func__, idx, instance->name);
+       edac_dbg(4, "Registered instance %d '%s' kobject\n",
+                idx, instance->name);
 
        return 0;
 
@@ -715,7 +710,7 @@ static int edac_device_create_instances(struct edac_device_ctl_info *edac_dev)
        int i, j;
        int err;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* iterate over creation of the instances */
        for (i = 0; i < edac_dev->nr_instances; i++) {
@@ -817,12 +812,12 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
        int err;
        struct kobject *edac_kobj = &edac_dev->kobj;
 
-       debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx);
+       edac_dbg(0, "idx=%d\n", edac_dev->dev_idx);
 
        /*  go create any main attributes callers wants */
        err = edac_device_add_main_sysfs_attributes(edac_dev);
        if (err) {
-               debugf0("%s() failed to add sysfs attribs\n", __func__);
+               edac_dbg(0, "failed to add sysfs attribs\n");
                goto err_out;
        }
 
@@ -832,8 +827,7 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
        err = sysfs_create_link(edac_kobj,
                                &edac_dev->dev->kobj, EDAC_DEVICE_SYMLINK);
        if (err) {
-               debugf0("%s() sysfs_create_link() returned err= %d\n",
-                       __func__, err);
+               edac_dbg(0, "sysfs_create_link() returned err= %d\n", err);
                goto err_remove_main_attribs;
        }
 
@@ -843,14 +837,13 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
         */
        err = edac_device_create_instances(edac_dev);
        if (err) {
-               debugf0("%s() edac_device_create_instances() "
-                       "returned err= %d\n", __func__, err);
+               edac_dbg(0, "edac_device_create_instances() returned err= %d\n",
+                        err);
                goto err_remove_link;
        }
 
 
-       debugf4("%s() create-instances done, idx=%d\n",
-               __func__, edac_dev->dev_idx);
+       edac_dbg(4, "create-instances done, idx=%d\n", edac_dev->dev_idx);
 
        return 0;
 
@@ -873,7 +866,7 @@ err_out:
  */
 void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* remove any main attributes for this device */
        edac_device_remove_main_sysfs_attributes(edac_dev);
index de5ba86e8b8998df830a0e62647378e4667489f4..616d90bcb3a4106929523c4a98fe32fb27f6a9a6 100644 (file)
 #include <linux/list.h>
 #include <linux/ctype.h>
 #include <linux/edac.h>
+#include <linux/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/edac.h>
 #include "edac_core.h"
 #include "edac_module.h"
 
+#define CREATE_TRACE_POINTS
+#define TRACE_INCLUDE_PATH ../../include/ras
+#include <ras/ras_event.h>
+
 /* lock to memory controller's control array */
 static DEFINE_MUTEX(mem_ctls_mutex);
 static LIST_HEAD(mc_devices);
 
+unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
+                                unsigned len)
+{
+       struct mem_ctl_info *mci = dimm->mci;
+       int i, n, count = 0;
+       char *p = buf;
+
+       for (i = 0; i < mci->n_layers; i++) {
+               n = snprintf(p, len, "%s %d ",
+                             edac_layer_name[mci->layers[i].type],
+                             dimm->location[i]);
+               p += n;
+               len -= n;
+               count += n;
+               if (!len)
+                       break;
+       }
+
+       return count;
+}
+
 #ifdef CONFIG_EDAC_DEBUG
 
 static void edac_mc_dump_channel(struct rank_info *chan)
 {
-       debugf4("\tchannel = %p\n", chan);
-       debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx);
-       debugf4("\tchannel->csrow = %p\n\n", chan->csrow);
-       debugf4("\tchannel->dimm = %p\n", chan->dimm);
+       edac_dbg(4, "  channel->chan_idx = %d\n", chan->chan_idx);
+       edac_dbg(4, "    channel = %p\n", chan);
+       edac_dbg(4, "    channel->csrow = %p\n", chan->csrow);
+       edac_dbg(4, "    channel->dimm = %p\n", chan->dimm);
 }
 
-static void edac_mc_dump_dimm(struct dimm_info *dimm)
+static void edac_mc_dump_dimm(struct dimm_info *dimm, int number)
 {
-       int i;
-
-       debugf4("\tdimm = %p\n", dimm);
-       debugf4("\tdimm->label = '%s'\n", dimm->label);
-       debugf4("\tdimm->nr_pages = 0x%x\n", dimm->nr_pages);
-       debugf4("\tdimm location ");
-       for (i = 0; i < dimm->mci->n_layers; i++) {
-               printk(KERN_CONT "%d", dimm->location[i]);
-               if (i < dimm->mci->n_layers - 1)
-                       printk(KERN_CONT ".");
-       }
-       printk(KERN_CONT "\n");
-       debugf4("\tdimm->grain = %d\n", dimm->grain);
-       debugf4("\tdimm->nr_pages = 0x%x\n", dimm->nr_pages);
+       char location[80];
+
+       edac_dimm_info_location(dimm, location, sizeof(location));
+
+       edac_dbg(4, "%s%i: %smapped as virtual row %d, chan %d\n",
+                dimm->mci->mem_is_per_rank ? "rank" : "dimm",
+                number, location, dimm->csrow, dimm->cschannel);
+       edac_dbg(4, "  dimm = %p\n", dimm);
+       edac_dbg(4, "  dimm->label = '%s'\n", dimm->label);
+       edac_dbg(4, "  dimm->nr_pages = 0x%x\n", dimm->nr_pages);
+       edac_dbg(4, "  dimm->grain = %d\n", dimm->grain);
+       edac_dbg(4, "  dimm->nr_pages = 0x%x\n", dimm->nr_pages);
 }
 
 static void edac_mc_dump_csrow(struct csrow_info *csrow)
 {
-       debugf4("\tcsrow = %p\n", csrow);
-       debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx);
-       debugf4("\tcsrow->first_page = 0x%lx\n", csrow->first_page);
-       debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page);
-       debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask);
-       debugf4("\tcsrow->nr_channels = %d\n", csrow->nr_channels);
-       debugf4("\tcsrow->channels = %p\n", csrow->channels);
-       debugf4("\tcsrow->mci = %p\n\n", csrow->mci);
+       edac_dbg(4, "csrow->csrow_idx = %d\n", csrow->csrow_idx);
+       edac_dbg(4, "  csrow = %p\n", csrow);
+       edac_dbg(4, "  csrow->first_page = 0x%lx\n", csrow->first_page);
+       edac_dbg(4, "  csrow->last_page = 0x%lx\n", csrow->last_page);
+       edac_dbg(4, "  csrow->page_mask = 0x%lx\n", csrow->page_mask);
+       edac_dbg(4, "  csrow->nr_channels = %d\n", csrow->nr_channels);
+       edac_dbg(4, "  csrow->channels = %p\n", csrow->channels);
+       edac_dbg(4, "  csrow->mci = %p\n", csrow->mci);
 }
 
 static void edac_mc_dump_mci(struct mem_ctl_info *mci)
 {
-       debugf3("\tmci = %p\n", mci);
-       debugf3("\tmci->mtype_cap = %lx\n", mci->mtype_cap);
-       debugf3("\tmci->edac_ctl_cap = %lx\n", mci->edac_ctl_cap);
-       debugf3("\tmci->edac_cap = %lx\n", mci->edac_cap);
-       debugf4("\tmci->edac_check = %p\n", mci->edac_check);
-       debugf3("\tmci->nr_csrows = %d, csrows = %p\n",
-               mci->nr_csrows, mci->csrows);
-       debugf3("\tmci->nr_dimms = %d, dimms = %p\n",
-               mci->tot_dimms, mci->dimms);
-       debugf3("\tdev = %p\n", mci->dev);
-       debugf3("\tmod_name:ctl_name = %s:%s\n", mci->mod_name, mci->ctl_name);
-       debugf3("\tpvt_info = %p\n\n", mci->pvt_info);
+       edac_dbg(3, "\tmci = %p\n", mci);
+       edac_dbg(3, "\tmci->mtype_cap = %lx\n", mci->mtype_cap);
+       edac_dbg(3, "\tmci->edac_ctl_cap = %lx\n", mci->edac_ctl_cap);
+       edac_dbg(3, "\tmci->edac_cap = %lx\n", mci->edac_cap);
+       edac_dbg(4, "\tmci->edac_check = %p\n", mci->edac_check);
+       edac_dbg(3, "\tmci->nr_csrows = %d, csrows = %p\n",
+                mci->nr_csrows, mci->csrows);
+       edac_dbg(3, "\tmci->nr_dimms = %d, dimms = %p\n",
+                mci->tot_dimms, mci->dimms);
+       edac_dbg(3, "\tdev = %p\n", mci->pdev);
+       edac_dbg(3, "\tmod_name:ctl_name = %s:%s\n",
+                mci->mod_name, mci->ctl_name);
+       edac_dbg(3, "\tpvt_info = %p\n\n", mci->pvt_info);
 }
 
 #endif                         /* CONFIG_EDAC_DEBUG */
@@ -205,15 +230,15 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 {
        struct mem_ctl_info *mci;
        struct edac_mc_layer *layer;
-       struct csrow_info *csi, *csr;
-       struct rank_info *chi, *chp, *chan;
+       struct csrow_info *csr;
+       struct rank_info *chan;
        struct dimm_info *dimm;
        u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
        unsigned pos[EDAC_MAX_LAYERS];
        unsigned size, tot_dimms = 1, count = 1;
        unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
        void *pvt, *p, *ptr = NULL;
-       int i, j, err, row, chn, n, len;
+       int i, j, row, chn, n, len, off;
        bool per_rank = false;
 
        BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0);
@@ -239,26 +264,24 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
         */
        mci = edac_align_ptr(&ptr, sizeof(*mci), 1);
        layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers);
-       csi = edac_align_ptr(&ptr, sizeof(*csi), tot_csrows);
-       chi = edac_align_ptr(&ptr, sizeof(*chi), tot_csrows * tot_channels);
-       dimm = edac_align_ptr(&ptr, sizeof(*dimm), tot_dimms);
        for (i = 0; i < n_layers; i++) {
                count *= layers[i].size;
-               debugf4("%s: errcount layer %d size %d\n", __func__, i, count);
+               edac_dbg(4, "errcount layer %d size %d\n", i, count);
                ce_per_layer[i] = edac_align_ptr(&ptr, sizeof(u32), count);
                ue_per_layer[i] = edac_align_ptr(&ptr, sizeof(u32), count);
                tot_errcount += 2 * count;
        }
 
-       debugf4("%s: allocating %d error counters\n", __func__, tot_errcount);
+       edac_dbg(4, "allocating %d error counters\n", tot_errcount);
        pvt = edac_align_ptr(&ptr, sz_pvt, 1);
        size = ((unsigned long)pvt) + sz_pvt;
 
-       debugf1("%s(): allocating %u bytes for mci data (%d %s, %d csrows/channels)\n",
-               __func__, size,
-               tot_dimms,
-               per_rank ? "ranks" : "dimms",
-               tot_csrows * tot_channels);
+       edac_dbg(1, "allocating %u bytes for mci data (%d %s, %d csrows/channels)\n",
+                size,
+                tot_dimms,
+                per_rank ? "ranks" : "dimms",
+                tot_csrows * tot_channels);
+
        mci = kzalloc(size, GFP_KERNEL);
        if (mci == NULL)
                return NULL;
@@ -267,9 +290,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
         * rather than an imaginary chunk of memory located at address 0.
         */
        layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer));
-       csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
-       chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi));
-       dimm = (struct dimm_info *)(((char *)mci) + ((unsigned long)dimm));
        for (i = 0; i < n_layers; i++) {
                mci->ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i]));
                mci->ue_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ue_per_layer[i]));
@@ -278,8 +298,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
 
        /* setup index and various internal pointers */
        mci->mc_idx = mc_num;
-       mci->csrows = csi;
-       mci->dimms  = dimm;
        mci->tot_dimms = tot_dimms;
        mci->pvt_info = pvt;
        mci->n_layers = n_layers;
@@ -290,40 +308,57 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
        mci->mem_is_per_rank = per_rank;
 
        /*
-        * Fill the csrow struct
+        * Alocate and fill the csrow/channels structs
         */
+       mci->csrows = kcalloc(sizeof(*mci->csrows), tot_csrows, GFP_KERNEL);
+       if (!mci->csrows)
+               goto error;
        for (row = 0; row < tot_csrows; row++) {
-               csr = &csi[row];
+               csr = kzalloc(sizeof(**mci->csrows), GFP_KERNEL);
+               if (!csr)
+                       goto error;
+               mci->csrows[row] = csr;
                csr->csrow_idx = row;
                csr->mci = mci;
                csr->nr_channels = tot_channels;
-               chp = &chi[row * tot_channels];
-               csr->channels = chp;
+               csr->channels = kcalloc(sizeof(*csr->channels), tot_channels,
+                                       GFP_KERNEL);
+               if (!csr->channels)
+                       goto error;
 
                for (chn = 0; chn < tot_channels; chn++) {
-                       chan = &chp[chn];
+                       chan = kzalloc(sizeof(**csr->channels), GFP_KERNEL);
+                       if (!chan)
+                               goto error;
+                       csr->channels[chn] = chan;
                        chan->chan_idx = chn;
                        chan->csrow = csr;
                }
        }
 
        /*
-        * Fill the dimm struct
+        * Allocate and fill the dimm structs
         */
+       mci->dimms  = kcalloc(sizeof(*mci->dimms), tot_dimms, GFP_KERNEL);
+       if (!mci->dimms)
+               goto error;
+
        memset(&pos, 0, sizeof(pos));
        row = 0;
        chn = 0;
-       debugf4("%s: initializing %d %s\n", __func__, tot_dimms,
-               per_rank ? "ranks" : "dimms");
        for (i = 0; i < tot_dimms; i++) {
-               chan = &csi[row].channels[chn];
-               dimm = EDAC_DIMM_PTR(layer, mci->dimms, n_layers,
-                              pos[0], pos[1], pos[2]);
-               dimm->mci = mci;
+               chan = mci->csrows[row]->channels[chn];
+               off = EDAC_DIMM_OFF(layer, n_layers, pos[0], pos[1], pos[2]);
+               if (off < 0 || off >= tot_dimms) {
+                       edac_mc_printk(mci, KERN_ERR, "EDAC core bug: EDAC_DIMM_OFF is trying to do an illegal data access\n");
+                       goto error;
+               }
 
-               debugf2("%s: %d: %s%zd (%d:%d:%d): row %d, chan %d\n", __func__,
-                       i, per_rank ? "rank" : "dimm", (dimm - mci->dimms),
-                       pos[0], pos[1], pos[2], row, chn);
+               dimm = kzalloc(sizeof(**mci->dimms), GFP_KERNEL);
+               if (!dimm)
+                       goto error;
+               mci->dimms[off] = dimm;
+               dimm->mci = mci;
 
                /*
                 * Copy DIMM location and initialize it.
@@ -367,16 +402,6 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
        }
 
        mci->op_state = OP_ALLOC;
-       INIT_LIST_HEAD(&mci->grp_kobj_list);
-
-       /*
-        * Initialize the 'root' kobj for the edac_mc controller
-        */
-       err = edac_mc_register_sysfs_main_kobj(mci);
-       if (err) {
-               kfree(mci);
-               return NULL;
-       }
 
        /* at this point, the root kobj is valid, and in order to
         * 'free' the object, then the function:
@@ -384,7 +409,30 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
         * which will perform kobj unregistration and the actual free
         * will occur during the kobject callback operation
         */
+
        return mci;
+
+error:
+       if (mci->dimms) {
+               for (i = 0; i < tot_dimms; i++)
+                       kfree(mci->dimms[i]);
+               kfree(mci->dimms);
+       }
+       if (mci->csrows) {
+               for (chn = 0; chn < tot_channels; chn++) {
+                       csr = mci->csrows[chn];
+                       if (csr) {
+                               for (chn = 0; chn < tot_channels; chn++)
+                                       kfree(csr->channels[chn]);
+                               kfree(csr);
+                       }
+                       kfree(mci->csrows[i]);
+               }
+               kfree(mci->csrows);
+       }
+       kfree(mci);
+
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
 
@@ -395,12 +443,10 @@ EXPORT_SYMBOL_GPL(edac_mc_alloc);
  */
 void edac_mc_free(struct mem_ctl_info *mci)
 {
-       debugf1("%s()\n", __func__);
+       edac_dbg(1, "\n");
 
-       edac_mc_unregister_sysfs_main_kobj(mci);
-
-       /* free the mci instance memory here */
-       kfree(mci);
+       /* the mci instance is freed here, when the sysfs object is dropped */
+       edac_unregister_sysfs(mci);
 }
 EXPORT_SYMBOL_GPL(edac_mc_free);
 
@@ -417,12 +463,12 @@ struct mem_ctl_info *find_mci_by_dev(struct device *dev)
        struct mem_ctl_info *mci;
        struct list_head *item;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        list_for_each(item, &mc_devices) {
                mci = list_entry(item, struct mem_ctl_info, link);
 
-               if (mci->dev == dev)
+               if (mci->pdev == dev)
                        return mci;
        }
 
@@ -485,7 +531,7 @@ static void edac_mc_workq_function(struct work_struct *work_req)
  */
 static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* if this instance is not in the POLL state, then simply return */
        if (mci->op_state != OP_RUNNING_POLL)
@@ -512,8 +558,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
 
        status = cancel_delayed_work(&mci->work);
        if (status == 0) {
-               debugf0("%s() not canceled, flush the queue\n",
-                       __func__);
+               edac_dbg(0, "not canceled, flush the queue\n");
 
                /* workq instance might be running, wait for it */
                flush_workqueue(edac_workqueue);
@@ -574,7 +619,7 @@ static int add_mc_to_global_list(struct mem_ctl_info *mci)
 
        insert_before = &mc_devices;
 
-       p = find_mci_by_dev(mci->dev);
+       p = find_mci_by_dev(mci->pdev);
        if (unlikely(p != NULL))
                goto fail0;
 
@@ -596,7 +641,7 @@ static int add_mc_to_global_list(struct mem_ctl_info *mci)
 
 fail0:
        edac_printk(KERN_WARNING, EDAC_MC,
-               "%s (%s) %s %s already assigned %d\n", dev_name(p->dev),
+               "%s (%s) %s %s already assigned %d\n", dev_name(p->pdev),
                edac_dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx);
        return 1;
 
@@ -660,7 +705,7 @@ EXPORT_SYMBOL(edac_mc_find);
 /* FIXME - should a warning be printed if no error detection? correction? */
 int edac_mc_add_mc(struct mem_ctl_info *mci)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
 #ifdef CONFIG_EDAC_DEBUG
        if (edac_debug_level >= 3)
@@ -670,15 +715,22 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
                int i;
 
                for (i = 0; i < mci->nr_csrows; i++) {
+                       struct csrow_info *csrow = mci->csrows[i];
+                       u32 nr_pages = 0;
                        int j;
 
-                       edac_mc_dump_csrow(&mci->csrows[i]);
-                       for (j = 0; j < mci->csrows[i].nr_channels; j++)
-                               edac_mc_dump_channel(&mci->csrows[i].
-                                               channels[j]);
+                       for (j = 0; j < csrow->nr_channels; j++)
+                               nr_pages += csrow->channels[j]->dimm->nr_pages;
+                       if (!nr_pages)
+                               continue;
+                       edac_mc_dump_csrow(csrow);
+                       for (j = 0; j < csrow->nr_channels; j++)
+                               if (csrow->channels[j]->dimm->nr_pages)
+                                       edac_mc_dump_channel(csrow->channels[j]);
                }
                for (i = 0; i < mci->tot_dimms; i++)
-                       edac_mc_dump_dimm(&mci->dimms[i]);
+                       if (mci->dimms[i]->nr_pages)
+                               edac_mc_dump_dimm(mci->dimms[i], i);
        }
 #endif
        mutex_lock(&mem_ctls_mutex);
@@ -732,7 +784,7 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        mutex_lock(&mem_ctls_mutex);
 
@@ -770,7 +822,7 @@ static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
        void *virt_addr;
        unsigned long flags = 0;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        /* ECC error page was not in our memory. Ignore it. */
        if (!pfn_valid(page))
@@ -797,26 +849,26 @@ static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
 /* FIXME - should return -1 */
 int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
 {
-       struct csrow_info *csrows = mci->csrows;
+       struct csrow_info **csrows = mci->csrows;
        int row, i, j, n;
 
-       debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page);
+       edac_dbg(1, "MC%d: 0x%lx\n", mci->mc_idx, page);
        row = -1;
 
        for (i = 0; i < mci->nr_csrows; i++) {
-               struct csrow_info *csrow = &csrows[i];
+               struct csrow_info *csrow = csrows[i];
                n = 0;
                for (j = 0; j < csrow->nr_channels; j++) {
-                       struct dimm_info *dimm = csrow->channels[j].dimm;
+                       struct dimm_info *dimm = csrow->channels[j]->dimm;
                        n += dimm->nr_pages;
                }
                if (n == 0)
                        continue;
 
-               debugf3("MC%d: %s(): first(0x%lx) page(0x%lx) last(0x%lx) "
-                       "mask(0x%lx)\n", mci->mc_idx, __func__,
-                       csrow->first_page, page, csrow->last_page,
-                       csrow->page_mask);
+               edac_dbg(3, "MC%d: first(0x%lx) page(0x%lx) last(0x%lx) mask(0x%lx)\n",
+                        mci->mc_idx,
+                        csrow->first_page, page, csrow->last_page,
+                        csrow->page_mask);
 
                if ((page >= csrow->first_page) &&
                    (page <= csrow->last_page) &&
@@ -845,15 +897,16 @@ const char *edac_layer_name[] = {
 EXPORT_SYMBOL_GPL(edac_layer_name);
 
 static void edac_inc_ce_error(struct mem_ctl_info *mci,
-                                   bool enable_per_layer_report,
-                                   const int pos[EDAC_MAX_LAYERS])
+                             bool enable_per_layer_report,
+                             const int pos[EDAC_MAX_LAYERS],
+                             const u16 count)
 {
        int i, index = 0;
 
-       mci->ce_mc++;
+       mci->ce_mc += count;
 
        if (!enable_per_layer_report) {
-               mci->ce_noinfo_count++;
+               mci->ce_noinfo_count += count;
                return;
        }
 
@@ -861,7 +914,7 @@ static void edac_inc_ce_error(struct mem_ctl_info *mci,
                if (pos[i] < 0)
                        break;
                index += pos[i];
-               mci->ce_per_layer[i][index]++;
+               mci->ce_per_layer[i][index] += count;
 
                if (i < mci->n_layers - 1)
                        index *= mci->layers[i + 1].size;
@@ -870,14 +923,15 @@ static void edac_inc_ce_error(struct mem_ctl_info *mci,
 
 static void edac_inc_ue_error(struct mem_ctl_info *mci,
                                    bool enable_per_layer_report,
-                                   const int pos[EDAC_MAX_LAYERS])
+                                   const int pos[EDAC_MAX_LAYERS],
+                                   const u16 count)
 {
        int i, index = 0;
 
-       mci->ue_mc++;
+       mci->ue_mc += count;
 
        if (!enable_per_layer_report) {
-               mci->ce_noinfo_count++;
+               mci->ce_noinfo_count += count;
                return;
        }
 
@@ -885,7 +939,7 @@ static void edac_inc_ue_error(struct mem_ctl_info *mci,
                if (pos[i] < 0)
                        break;
                index += pos[i];
-               mci->ue_per_layer[i][index]++;
+               mci->ue_per_layer[i][index] += count;
 
                if (i < mci->n_layers - 1)
                        index *= mci->layers[i + 1].size;
@@ -893,6 +947,7 @@ static void edac_inc_ue_error(struct mem_ctl_info *mci,
 }
 
 static void edac_ce_error(struct mem_ctl_info *mci,
+                         const u16 error_count,
                          const int pos[EDAC_MAX_LAYERS],
                          const char *msg,
                          const char *location,
@@ -902,23 +957,25 @@ static void edac_ce_error(struct mem_ctl_info *mci,
                          const bool enable_per_layer_report,
                          const unsigned long page_frame_number,
                          const unsigned long offset_in_page,
-                         u32 grain)
+                         long grain)
 {
        unsigned long remapped_page;
 
        if (edac_mc_get_log_ce()) {
                if (other_detail && *other_detail)
                        edac_mc_printk(mci, KERN_WARNING,
-                                      "CE %s on %s (%s%s - %s)\n",
+                                      "%d CE %s on %s (%s %s - %s)\n",
+                                      error_count,
                                       msg, label, location,
                                       detail, other_detail);
                else
                        edac_mc_printk(mci, KERN_WARNING,
-                                      "CE %s on %s (%s%s)\n",
+                                      "%d CE %s on %s (%s %s)\n",
+                                      error_count,
                                       msg, label, location,
                                       detail);
        }
-       edac_inc_ce_error(mci, enable_per_layer_report, pos);
+       edac_inc_ce_error(mci, enable_per_layer_report, pos, error_count);
 
        if (mci->scrub_mode & SCRUB_SW_SRC) {
                /*
@@ -942,6 +999,7 @@ static void edac_ce_error(struct mem_ctl_info *mci,
 }
 
 static void edac_ue_error(struct mem_ctl_info *mci,
+                         const u16 error_count,
                          const int pos[EDAC_MAX_LAYERS],
                          const char *msg,
                          const char *location,
@@ -953,12 +1011,14 @@ static void edac_ue_error(struct mem_ctl_info *mci,
        if (edac_mc_get_log_ue()) {
                if (other_detail && *other_detail)
                        edac_mc_printk(mci, KERN_WARNING,
-                                      "UE %s on %s (%s%s - %s)\n",
+                                      "%d UE %s on %s (%s %s - %s)\n",
+                                      error_count,
                                       msg, label, location, detail,
                                       other_detail);
                else
                        edac_mc_printk(mci, KERN_WARNING,
-                                      "UE %s on %s (%s%s)\n",
+                                      "%d UE %s on %s (%s %s)\n",
+                                      error_count,
                                       msg, label, location, detail);
        }
 
@@ -971,33 +1031,53 @@ static void edac_ue_error(struct mem_ctl_info *mci,
                              msg, label, location, detail);
        }
 
-       edac_inc_ue_error(mci, enable_per_layer_report, pos);
+       edac_inc_ue_error(mci, enable_per_layer_report, pos, error_count);
 }
 
 #define OTHER_LABEL " or "
+
+/**
+ * edac_mc_handle_error - reports a memory event to userspace
+ *
+ * @type:              severity of the error (CE/UE/Fatal)
+ * @mci:               a struct mem_ctl_info pointer
+ * @error_count:       Number of errors of the same type
+ * @page_frame_number: mem page where the error occurred
+ * @offset_in_page:    offset of the error inside the page
+ * @syndrome:          ECC syndrome
+ * @top_layer:         Memory layer[0] position
+ * @mid_layer:         Memory layer[1] position
+ * @low_layer:         Memory layer[2] position
+ * @msg:               Message meaningful to the end users that
+ *                     explains the event
+ * @other_detail:      Technical details about the event that
+ *                     may help hardware manufacturers and
+ *                     EDAC developers to analyse the event
+ */
 void edac_mc_handle_error(const enum hw_event_mc_err_type type,
                          struct mem_ctl_info *mci,
+                         const u16 error_count,
                          const unsigned long page_frame_number,
                          const unsigned long offset_in_page,
                          const unsigned long syndrome,
-                         const int layer0,
-                         const int layer1,
-                         const int layer2,
+                         const int top_layer,
+                         const int mid_layer,
+                         const int low_layer,
                          const char *msg,
-                         const char *other_detail,
-                         const void *mcelog)
+                         const char *other_detail)
 {
        /* FIXME: too much for stack: move it to some pre-alocated area */
        char detail[80], location[80];
        char label[(EDAC_MC_LABEL_LEN + 1 + sizeof(OTHER_LABEL)) * mci->tot_dimms];
        char *p;
        int row = -1, chan = -1;
-       int pos[EDAC_MAX_LAYERS] = { layer0, layer1, layer2 };
+       int pos[EDAC_MAX_LAYERS] = { top_layer, mid_layer, low_layer };
        int i;
-       u32 grain;
+       long grain;
        bool enable_per_layer_report = false;
+       u8 grain_bits;
 
-       debugf3("MC%d: %s()\n", mci->mc_idx, __func__);
+       edac_dbg(3, "MC%d\n", mci->mc_idx);
 
        /*
         * Check if the event report is consistent and if the memory
@@ -1043,13 +1123,13 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
        p = label;
        *p = '\0';
        for (i = 0; i < mci->tot_dimms; i++) {
-               struct dimm_info *dimm = &mci->dimms[i];
+               struct dimm_info *dimm = mci->dimms[i];
 
-               if (layer0 >= 0 && layer0 != dimm->location[0])
+               if (top_layer >= 0 && top_layer != dimm->location[0])
                        continue;
-               if (layer1 >= 0 && layer1 != dimm->location[1])
+               if (mid_layer >= 0 && mid_layer != dimm->location[1])
                        continue;
-               if (layer2 >= 0 && layer2 != dimm->location[2])
+               if (low_layer >= 0 && low_layer != dimm->location[2])
                        continue;
 
                /* get the max grain, over the error match range */
@@ -1075,11 +1155,9 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
                         * get csrow/channel of the DIMM, in order to allow
                         * incrementing the compat API counters
                         */
-                       debugf4("%s: %s csrows map: (%d,%d)\n",
-                               __func__,
-                               mci->mem_is_per_rank ? "rank" : "dimm",
-                               dimm->csrow, dimm->cschannel);
-
+                       edac_dbg(4, "%s csrows map: (%d,%d)\n",
+                                mci->mem_is_per_rank ? "rank" : "dimm",
+                                dimm->csrow, dimm->cschannel);
                        if (row == -1)
                                row = dimm->csrow;
                        else if (row >= 0 && row != dimm->csrow)
@@ -1095,19 +1173,18 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
        if (!enable_per_layer_report) {
                strcpy(label, "any memory");
        } else {
-               debugf4("%s: csrow/channel to increment: (%d,%d)\n",
-                       __func__, row, chan);
+               edac_dbg(4, "csrow/channel to increment: (%d,%d)\n", row, chan);
                if (p == label)
                        strcpy(label, "unknown memory");
                if (type == HW_EVENT_ERR_CORRECTED) {
                        if (row >= 0) {
-                               mci->csrows[row].ce_count++;
+                               mci->csrows[row]->ce_count += error_count;
                                if (chan >= 0)
-                                       mci->csrows[row].channels[chan].ce_count++;
+                                       mci->csrows[row]->channels[chan]->ce_count += error_count;
                        }
                } else
                        if (row >= 0)
-                               mci->csrows[row].ue_count++;
+                               mci->csrows[row]->ue_count += error_count;
        }
 
        /* Fill the RAM location data */
@@ -1120,23 +1197,33 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
                             edac_layer_name[mci->layers[i].type],
                             pos[i]);
        }
+       if (p > location)
+               *(p - 1) = '\0';
+
+       /* Report the error via the trace interface */
+
+       grain_bits = fls_long(grain) + 1;
+       trace_mc_event(type, msg, label, error_count,
+                      mci->mc_idx, top_layer, mid_layer, low_layer,
+                      PAGES_TO_MiB(page_frame_number) | offset_in_page,
+                      grain_bits, syndrome, other_detail);
 
        /* Memory type dependent details about the error */
        if (type == HW_EVENT_ERR_CORRECTED) {
                snprintf(detail, sizeof(detail),
-                       "page:0x%lx offset:0x%lx grain:%d syndrome:0x%lx",
+                       "page:0x%lx offset:0x%lx grain:%ld syndrome:0x%lx",
                        page_frame_number, offset_in_page,
                        grain, syndrome);
-               edac_ce_error(mci, pos, msg, location, label, detail,
-                             other_detail, enable_per_layer_report,
+               edac_ce_error(mci, error_count, pos, msg, location, label,
+                             detail, other_detail, enable_per_layer_report,
                              page_frame_number, offset_in_page, grain);
        } else {
                snprintf(detail, sizeof(detail),
-                       "page:0x%lx offset:0x%lx grain:%d",
+                       "page:0x%lx offset:0x%lx grain:%ld",
                        page_frame_number, offset_in_page, grain);
 
-               edac_ue_error(mci, pos, msg, location, label, detail,
-                             other_detail, enable_per_layer_report);
+               edac_ue_error(mci, error_count, pos, msg, location, label,
+                             detail, other_detail, enable_per_layer_report);
        }
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_error);
index f6a29b0eedc8535bb33769ca81cf8f88abe602e8..ed0bc07b85039deb78c09812e461e0c41e3b3670 100644 (file)
@@ -7,17 +7,21 @@
  *
  * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
  *
+ * (c) 2012 - Mauro Carvalho Chehab <mchehab@redhat.com>
+ *     The entire API were re-written, and ported to use struct device
+ *
  */
 
 #include <linux/ctype.h>
 #include <linux/slab.h>
 #include <linux/edac.h>
 #include <linux/bug.h>
+#include <linux/pm_runtime.h>
+#include <linux/uaccess.h>
 
 #include "edac_core.h"
 #include "edac_module.h"
 
-
 /* MC EDAC Controls, setable by module parameter, and sysfs */
 static int edac_mc_log_ue = 1;
 static int edac_mc_log_ce = 1;
@@ -78,6 +82,8 @@ module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_int,
                  &edac_mc_poll_msec, 0644);
 MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
 
+static struct device *mci_pdev;
+
 /*
  * various constants for Memory Controllers
  */
@@ -125,317 +131,526 @@ static const char *edac_caps[] = {
        [EDAC_S16ECD16ED] = "S16ECD16ED"
 };
 
-/* EDAC sysfs CSROW data structures and methods
+#ifdef CONFIG_EDAC_LEGACY_SYSFS
+/*
+ * EDAC sysfs CSROW data structures and methods
+ */
+
+#define to_csrow(k) container_of(k, struct csrow_info, dev)
+
+/*
+ * We need it to avoid namespace conflicts between the legacy API
+ * and the per-dimm/per-rank one
  */
+#define DEVICE_ATTR_LEGACY(_name, _mode, _show, _store) \
+       struct device_attribute dev_attr_legacy_##_name = __ATTR(_name, _mode, _show, _store)
+
+struct dev_ch_attribute {
+       struct device_attribute attr;
+       int channel;
+};
+
+#define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \
+       struct dev_ch_attribute dev_attr_legacy_##_name = \
+               { __ATTR(_name, _mode, _show, _store), (_var) }
+
+#define to_channel(k) (container_of(k, struct dev_ch_attribute, attr)->channel)
 
 /* Set of more default csrow<id> attribute show/store functions */
-static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data,
-                               int private)
+static ssize_t csrow_ue_count_show(struct device *dev,
+                                  struct device_attribute *mattr, char *data)
 {
+       struct csrow_info *csrow = to_csrow(dev);
+
        return sprintf(data, "%u\n", csrow->ue_count);
 }
 
-static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data,
-                               int private)
+static ssize_t csrow_ce_count_show(struct device *dev,
+                                  struct device_attribute *mattr, char *data)
 {
+       struct csrow_info *csrow = to_csrow(dev);
+
        return sprintf(data, "%u\n", csrow->ce_count);
 }
 
-static ssize_t csrow_size_show(struct csrow_info *csrow, char *data,
-                               int private)
+static ssize_t csrow_size_show(struct device *dev,
+                              struct device_attribute *mattr, char *data)
 {
+       struct csrow_info *csrow = to_csrow(dev);
        int i;
        u32 nr_pages = 0;
 
        for (i = 0; i < csrow->nr_channels; i++)
-               nr_pages += csrow->channels[i].dimm->nr_pages;
-
+               nr_pages += csrow->channels[i]->dimm->nr_pages;
        return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages));
 }
 
-static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data,
-                               int private)
+static ssize_t csrow_mem_type_show(struct device *dev,
+                                  struct device_attribute *mattr, char *data)
 {
-       return sprintf(data, "%s\n", mem_types[csrow->channels[0].dimm->mtype]);
+       struct csrow_info *csrow = to_csrow(dev);
+
+       return sprintf(data, "%s\n", mem_types[csrow->channels[0]->dimm->mtype]);
 }
 
-static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data,
-                               int private)
+static ssize_t csrow_dev_type_show(struct device *dev,
+                                  struct device_attribute *mattr, char *data)
 {
-       return sprintf(data, "%s\n", dev_types[csrow->channels[0].dimm->dtype]);
+       struct csrow_info *csrow = to_csrow(dev);
+
+       return sprintf(data, "%s\n", dev_types[csrow->channels[0]->dimm->dtype]);
 }
 
-static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data,
-                               int private)
+static ssize_t csrow_edac_mode_show(struct device *dev,
+                                   struct device_attribute *mattr,
+                                   char *data)
 {
-       return sprintf(data, "%s\n", edac_caps[csrow->channels[0].dimm->edac_mode]);
+       struct csrow_info *csrow = to_csrow(dev);
+
+       return sprintf(data, "%s\n", edac_caps[csrow->channels[0]->dimm->edac_mode]);
 }
 
 /* show/store functions for DIMM Label attributes */
-static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
-                               char *data, int channel)
+static ssize_t channel_dimm_label_show(struct device *dev,
+                                      struct device_attribute *mattr,
+                                      char *data)
 {
+       struct csrow_info *csrow = to_csrow(dev);
+       unsigned chan = to_channel(mattr);
+       struct rank_info *rank = csrow->channels[chan];
+
        /* if field has not been initialized, there is nothing to send */
-       if (!csrow->channels[channel].dimm->label[0])
+       if (!rank->dimm->label[0])
                return 0;
 
        return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n",
-                       csrow->channels[channel].dimm->label);
+                       rank->dimm->label);
 }
 
-static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
-                                       const char *data,
-                                       size_t count, int channel)
+static ssize_t channel_dimm_label_store(struct device *dev,
+                                       struct device_attribute *mattr,
+                                       const char *data, size_t count)
 {
+       struct csrow_info *csrow = to_csrow(dev);
+       unsigned chan = to_channel(mattr);
+       struct rank_info *rank = csrow->channels[chan];
+
        ssize_t max_size = 0;
 
        max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
-       strncpy(csrow->channels[channel].dimm->label, data, max_size);
-       csrow->channels[channel].dimm->label[max_size] = '\0';
+       strncpy(rank->dimm->label, data, max_size);
+       rank->dimm->label[max_size] = '\0';
 
        return max_size;
 }
 
 /* show function for dynamic chX_ce_count attribute */
-static ssize_t channel_ce_count_show(struct csrow_info *csrow,
-                               char *data, int channel)
+static ssize_t channel_ce_count_show(struct device *dev,
+                                    struct device_attribute *mattr, char *data)
 {
-       return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
+       struct csrow_info *csrow = to_csrow(dev);
+       unsigned chan = to_channel(mattr);
+       struct rank_info *rank = csrow->channels[chan];
+
+       return sprintf(data, "%u\n", rank->ce_count);
 }
 
-/* csrow specific attribute structure */
-struct csrowdev_attribute {
-       struct attribute attr;
-        ssize_t(*show) (struct csrow_info *, char *, int);
-        ssize_t(*store) (struct csrow_info *, const char *, size_t, int);
-       int private;
-};
+/* cwrow<id>/attribute files */
+DEVICE_ATTR_LEGACY(size_mb, S_IRUGO, csrow_size_show, NULL);
+DEVICE_ATTR_LEGACY(dev_type, S_IRUGO, csrow_dev_type_show, NULL);
+DEVICE_ATTR_LEGACY(mem_type, S_IRUGO, csrow_mem_type_show, NULL);
+DEVICE_ATTR_LEGACY(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL);
+DEVICE_ATTR_LEGACY(ue_count, S_IRUGO, csrow_ue_count_show, NULL);
+DEVICE_ATTR_LEGACY(ce_count, S_IRUGO, csrow_ce_count_show, NULL);
 
-#define to_csrow(k) container_of(k, struct csrow_info, kobj)
-#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
+/* default attributes of the CSROW<id> object */
+static struct attribute *csrow_attrs[] = {
+       &dev_attr_legacy_dev_type.attr,
+       &dev_attr_legacy_mem_type.attr,
+       &dev_attr_legacy_edac_mode.attr,
+       &dev_attr_legacy_size_mb.attr,
+       &dev_attr_legacy_ue_count.attr,
+       &dev_attr_legacy_ce_count.attr,
+       NULL,
+};
 
-/* Set of show/store higher level functions for default csrow attributes */
-static ssize_t csrowdev_show(struct kobject *kobj,
-                       struct attribute *attr, char *buffer)
-{
-       struct csrow_info *csrow = to_csrow(kobj);
-       struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
+static struct attribute_group csrow_attr_grp = {
+       .attrs  = csrow_attrs,
+};
 
-       if (csrowdev_attr->show)
-               return csrowdev_attr->show(csrow,
-                                       buffer, csrowdev_attr->private);
-       return -EIO;
-}
+static const struct attribute_group *csrow_attr_groups[] = {
+       &csrow_attr_grp,
+       NULL
+};
 
-static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
-                       const char *buffer, size_t count)
+static void csrow_attr_release(struct device *dev)
 {
-       struct csrow_info *csrow = to_csrow(kobj);
-       struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
-
-       if (csrowdev_attr->store)
-               return csrowdev_attr->store(csrow,
-                                       buffer,
-                                       count, csrowdev_attr->private);
-       return -EIO;
-}
+       struct csrow_info *csrow = container_of(dev, struct csrow_info, dev);
 
-static const struct sysfs_ops csrowfs_ops = {
-       .show = csrowdev_show,
-       .store = csrowdev_store
-};
+       edac_dbg(1, "Releasing csrow device %s\n", dev_name(dev));
+       kfree(csrow);
+}
 
-#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private)       \
-static struct csrowdev_attribute attr_##_name = {                      \
-       .attr = {.name = __stringify(_name), .mode = _mode },   \
-       .show   = _show,                                        \
-       .store  = _store,                                       \
-       .private = _private,                                    \
+static struct device_type csrow_attr_type = {
+       .groups         = csrow_attr_groups,
+       .release        = csrow_attr_release,
 };
 
-/* default cwrow<id>/attribute files */
-CSROWDEV_ATTR(size_mb, S_IRUGO, csrow_size_show, NULL, 0);
-CSROWDEV_ATTR(dev_type, S_IRUGO, csrow_dev_type_show, NULL, 0);
-CSROWDEV_ATTR(mem_type, S_IRUGO, csrow_mem_type_show, NULL, 0);
-CSROWDEV_ATTR(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL, 0);
-CSROWDEV_ATTR(ue_count, S_IRUGO, csrow_ue_count_show, NULL, 0);
-CSROWDEV_ATTR(ce_count, S_IRUGO, csrow_ce_count_show, NULL, 0);
+/*
+ * possible dynamic channel DIMM Label attribute files
+ *
+ */
 
-/* default attributes of the CSROW<id> object */
-static struct csrowdev_attribute *default_csrow_attr[] = {
-       &attr_dev_type,
-       &attr_mem_type,
-       &attr_edac_mode,
-       &attr_size_mb,
-       &attr_ue_count,
-       &attr_ce_count,
-       NULL,
-};
+#define EDAC_NR_CHANNELS       6
 
-/* possible dynamic channel DIMM Label attribute files */
-CSROWDEV_ATTR(ch0_dimm_label, S_IRUGO | S_IWUSR,
+DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR,
        channel_dimm_label_show, channel_dimm_label_store, 0);
-CSROWDEV_ATTR(ch1_dimm_label, S_IRUGO | S_IWUSR,
+DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR,
        channel_dimm_label_show, channel_dimm_label_store, 1);
-CSROWDEV_ATTR(ch2_dimm_label, S_IRUGO | S_IWUSR,
+DEVICE_CHANNEL(ch2_dimm_label, S_IRUGO | S_IWUSR,
        channel_dimm_label_show, channel_dimm_label_store, 2);
-CSROWDEV_ATTR(ch3_dimm_label, S_IRUGO | S_IWUSR,
+DEVICE_CHANNEL(ch3_dimm_label, S_IRUGO | S_IWUSR,
        channel_dimm_label_show, channel_dimm_label_store, 3);
-CSROWDEV_ATTR(ch4_dimm_label, S_IRUGO | S_IWUSR,
+DEVICE_CHANNEL(ch4_dimm_label, S_IRUGO | S_IWUSR,
        channel_dimm_label_show, channel_dimm_label_store, 4);
-CSROWDEV_ATTR(ch5_dimm_label, S_IRUGO | S_IWUSR,
+DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR,
        channel_dimm_label_show, channel_dimm_label_store, 5);
 
 /* Total possible dynamic DIMM Label attribute file table */
-static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
-       &attr_ch0_dimm_label,
-       &attr_ch1_dimm_label,
-       &attr_ch2_dimm_label,
-       &attr_ch3_dimm_label,
-       &attr_ch4_dimm_label,
-       &attr_ch5_dimm_label
+static struct device_attribute *dynamic_csrow_dimm_attr[] = {
+       &dev_attr_legacy_ch0_dimm_label.attr,
+       &dev_attr_legacy_ch1_dimm_label.attr,
+       &dev_attr_legacy_ch2_dimm_label.attr,
+       &dev_attr_legacy_ch3_dimm_label.attr,
+       &dev_attr_legacy_ch4_dimm_label.attr,
+       &dev_attr_legacy_ch5_dimm_label.attr
 };
 
 /* possible dynamic channel ce_count attribute files */
-CSROWDEV_ATTR(ch0_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 0);
-CSROWDEV_ATTR(ch1_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 1);
-CSROWDEV_ATTR(ch2_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 2);
-CSROWDEV_ATTR(ch3_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 3);
-CSROWDEV_ATTR(ch4_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 4);
-CSROWDEV_ATTR(ch5_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 5);
+DEVICE_CHANNEL(ch0_ce_count, S_IRUGO | S_IWUSR,
+                  channel_ce_count_show, NULL, 0);
+DEVICE_CHANNEL(ch1_ce_count, S_IRUGO | S_IWUSR,
+                  channel_ce_count_show, NULL, 1);
+DEVICE_CHANNEL(ch2_ce_count, S_IRUGO | S_IWUSR,
+                  channel_ce_count_show, NULL, 2);
+DEVICE_CHANNEL(ch3_ce_count, S_IRUGO | S_IWUSR,
+                  channel_ce_count_show, NULL, 3);
+DEVICE_CHANNEL(ch4_ce_count, S_IRUGO | S_IWUSR,
+                  channel_ce_count_show, NULL, 4);
+DEVICE_CHANNEL(ch5_ce_count, S_IRUGO | S_IWUSR,
+                  channel_ce_count_show, NULL, 5);
 
 /* Total possible dynamic ce_count attribute file table */
-static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
-       &attr_ch0_ce_count,
-       &attr_ch1_ce_count,
-       &attr_ch2_ce_count,
-       &attr_ch3_ce_count,
-       &attr_ch4_ce_count,
-       &attr_ch5_ce_count
+static struct device_attribute *dynamic_csrow_ce_count_attr[] = {
+       &dev_attr_legacy_ch0_ce_count.attr,
+       &dev_attr_legacy_ch1_ce_count.attr,
+       &dev_attr_legacy_ch2_ce_count.attr,
+       &dev_attr_legacy_ch3_ce_count.attr,
+       &dev_attr_legacy_ch4_ce_count.attr,
+       &dev_attr_legacy_ch5_ce_count.attr
 };
 
-#define EDAC_NR_CHANNELS       6
+static inline int nr_pages_per_csrow(struct csrow_info *csrow)
+{
+       int chan, nr_pages = 0;
+
+       for (chan = 0; chan < csrow->nr_channels; chan++)
+               nr_pages += csrow->channels[chan]->dimm->nr_pages;
+
+       return nr_pages;
+}
 
-/* Create dynamic CHANNEL files, indexed by 'chan',  under specifed CSROW */
-static int edac_create_channel_files(struct kobject *kobj, int chan)
+/* Create a CSROW object under specifed edac_mc_device */
+static int edac_create_csrow_object(struct mem_ctl_info *mci,
+                                   struct csrow_info *csrow, int index)
 {
-       int err = -ENODEV;
+       int err, chan;
+
+       if (csrow->nr_channels >= EDAC_NR_CHANNELS)
+               return -ENODEV;
+
+       csrow->dev.type = &csrow_attr_type;
+       csrow->dev.bus = &mci->bus;
+       device_initialize(&csrow->dev);
+       csrow->dev.parent = &mci->dev;
+       dev_set_name(&csrow->dev, "csrow%d", index);
+       dev_set_drvdata(&csrow->dev, csrow);
 
-       if (chan >= EDAC_NR_CHANNELS)
+       edac_dbg(0, "creating (virtual) csrow node %s\n",
+                dev_name(&csrow->dev));
+
+       err = device_add(&csrow->dev);
+       if (err < 0)
                return err;
 
-       /* create the DIMM label attribute file */
-       err = sysfs_create_file(kobj,
-                               (struct attribute *)
-                               dynamic_csrow_dimm_attr[chan]);
-
-       if (!err) {
-               /* create the CE Count attribute file */
-               err = sysfs_create_file(kobj,
-                                       (struct attribute *)
-                                       dynamic_csrow_ce_count_attr[chan]);
-       } else {
-               debugf1("%s()  dimm labels and ce_count files created",
-                       __func__);
+       for (chan = 0; chan < csrow->nr_channels; chan++) {
+               /* Only expose populated DIMMs */
+               if (!csrow->channels[chan]->dimm->nr_pages)
+                       continue;
+               err = device_create_file(&csrow->dev,
+                                        dynamic_csrow_dimm_attr[chan]);
+               if (err < 0)
+                       goto error;
+               err = device_create_file(&csrow->dev,
+                                        dynamic_csrow_ce_count_attr[chan]);
+               if (err < 0) {
+                       device_remove_file(&csrow->dev,
+                                          dynamic_csrow_dimm_attr[chan]);
+                       goto error;
+               }
+       }
+
+       return 0;
+
+error:
+       for (--chan; chan >= 0; chan--) {
+               device_remove_file(&csrow->dev,
+                                       dynamic_csrow_dimm_attr[chan]);
+               device_remove_file(&csrow->dev,
+                                          dynamic_csrow_ce_count_attr[chan]);
        }
+       put_device(&csrow->dev);
 
        return err;
 }
 
-/* No memory to release for this kobj */
-static void edac_csrow_instance_release(struct kobject *kobj)
+/* Create a CSROW object under specifed edac_mc_device */
+static int edac_create_csrow_objects(struct mem_ctl_info *mci)
 {
-       struct mem_ctl_info *mci;
-       struct csrow_info *cs;
+       int err, i, chan;
+       struct csrow_info *csrow;
+
+       for (i = 0; i < mci->nr_csrows; i++) {
+               csrow = mci->csrows[i];
+               if (!nr_pages_per_csrow(csrow))
+                       continue;
+               err = edac_create_csrow_object(mci, mci->csrows[i], i);
+               if (err < 0)
+                       goto error;
+       }
+       return 0;
 
-       debugf1("%s()\n", __func__);
+error:
+       for (--i; i >= 0; i--) {
+               csrow = mci->csrows[i];
+               if (!nr_pages_per_csrow(csrow))
+                       continue;
+               for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
+                       if (!csrow->channels[chan]->dimm->nr_pages)
+                               continue;
+                       device_remove_file(&csrow->dev,
+                                               dynamic_csrow_dimm_attr[chan]);
+                       device_remove_file(&csrow->dev,
+                                               dynamic_csrow_ce_count_attr[chan]);
+               }
+               put_device(&mci->csrows[i]->dev);
+       }
 
-       cs = container_of(kobj, struct csrow_info, kobj);
-       mci = cs->mci;
+       return err;
+}
 
-       kobject_put(&mci->edac_mci_kobj);
+static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
+{
+       int i, chan;
+       struct csrow_info *csrow;
+
+       for (i = mci->nr_csrows - 1; i >= 0; i--) {
+               csrow = mci->csrows[i];
+               if (!nr_pages_per_csrow(csrow))
+                       continue;
+               for (chan = csrow->nr_channels - 1; chan >= 0; chan--) {
+                       if (!csrow->channels[chan]->dimm->nr_pages)
+                               continue;
+                       edac_dbg(1, "Removing csrow %d channel %d sysfs nodes\n",
+                                i, chan);
+                       device_remove_file(&csrow->dev,
+                                               dynamic_csrow_dimm_attr[chan]);
+                       device_remove_file(&csrow->dev,
+                                               dynamic_csrow_ce_count_attr[chan]);
+               }
+               put_device(&mci->csrows[i]->dev);
+               device_del(&mci->csrows[i]->dev);
+       }
 }
+#endif
 
-/* the kobj_type instance for a CSROW */
-static struct kobj_type ktype_csrow = {
-       .release = edac_csrow_instance_release,
-       .sysfs_ops = &csrowfs_ops,
-       .default_attrs = (struct attribute **)default_csrow_attr,
+/*
+ * Per-dimm (or per-rank) devices
+ */
+
+#define to_dimm(k) container_of(k, struct dimm_info, dev)
+
+/* show/store functions for DIMM Label attributes */
+static ssize_t dimmdev_location_show(struct device *dev,
+                                    struct device_attribute *mattr, char *data)
+{
+       struct dimm_info *dimm = to_dimm(dev);
+
+       return edac_dimm_info_location(dimm, data, PAGE_SIZE);
+}
+
+static ssize_t dimmdev_label_show(struct device *dev,
+                                 struct device_attribute *mattr, char *data)
+{
+       struct dimm_info *dimm = to_dimm(dev);
+
+       /* if field has not been initialized, there is nothing to send */
+       if (!dimm->label[0])
+               return 0;
+
+       return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n", dimm->label);
+}
+
+static ssize_t dimmdev_label_store(struct device *dev,
+                                  struct device_attribute *mattr,
+                                  const char *data,
+                                  size_t count)
+{
+       struct dimm_info *dimm = to_dimm(dev);
+
+       ssize_t max_size = 0;
+
+       max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
+       strncpy(dimm->label, data, max_size);
+       dimm->label[max_size] = '\0';
+
+       return max_size;
+}
+
+static ssize_t dimmdev_size_show(struct device *dev,
+                                struct device_attribute *mattr, char *data)
+{
+       struct dimm_info *dimm = to_dimm(dev);
+
+       return sprintf(data, "%u\n", PAGES_TO_MiB(dimm->nr_pages));
+}
+
+static ssize_t dimmdev_mem_type_show(struct device *dev,
+                                    struct device_attribute *mattr, char *data)
+{
+       struct dimm_info *dimm = to_dimm(dev);
+
+       return sprintf(data, "%s\n", mem_types[dimm->mtype]);
+}
+
+static ssize_t dimmdev_dev_type_show(struct device *dev,
+                                    struct device_attribute *mattr, char *data)
+{
+       struct dimm_info *dimm = to_dimm(dev);
+
+       return sprintf(data, "%s\n", dev_types[dimm->dtype]);
+}
+
+static ssize_t dimmdev_edac_mode_show(struct device *dev,
+                                     struct device_attribute *mattr,
+                                     char *data)
+{
+       struct dimm_info *dimm = to_dimm(dev);
+
+       return sprintf(data, "%s\n", edac_caps[dimm->edac_mode]);
+}
+
+/* dimm/rank attribute files */
+static DEVICE_ATTR(dimm_label, S_IRUGO | S_IWUSR,
+                  dimmdev_label_show, dimmdev_label_store);
+static DEVICE_ATTR(dimm_location, S_IRUGO, dimmdev_location_show, NULL);
+static DEVICE_ATTR(size, S_IRUGO, dimmdev_size_show, NULL);
+static DEVICE_ATTR(dimm_mem_type, S_IRUGO, dimmdev_mem_type_show, NULL);
+static DEVICE_ATTR(dimm_dev_type, S_IRUGO, dimmdev_dev_type_show, NULL);
+static DEVICE_ATTR(dimm_edac_mode, S_IRUGO, dimmdev_edac_mode_show, NULL);
+
+/* attributes of the dimm<id>/rank<id> object */
+static struct attribute *dimm_attrs[] = {
+       &dev_attr_dimm_label.attr,
+       &dev_attr_dimm_location.attr,
+       &dev_attr_size.attr,
+       &dev_attr_dimm_mem_type.attr,
+       &dev_attr_dimm_dev_type.attr,
+       &dev_attr_dimm_edac_mode.attr,
+       NULL,
 };
 
-/* Create a CSROW object under specifed edac_mc_device */
-static int edac_create_csrow_object(struct mem_ctl_info *mci,
-                                       struct csrow_info *csrow, int index)
+static struct attribute_group dimm_attr_grp = {
+       .attrs  = dimm_attrs,
+};
+
+static const struct attribute_group *dimm_attr_groups[] = {
+       &dimm_attr_grp,
+       NULL
+};
+
+static void dimm_attr_release(struct device *dev)
 {
-       struct kobject *kobj_mci = &mci->edac_mci_kobj;
-       struct kobject *kobj;
-       int chan;
-       int err;
+       struct dimm_info *dimm = container_of(dev, struct dimm_info, dev);
 
-       /* generate ..../edac/mc/mc<id>/csrow<index>   */
-       memset(&csrow->kobj, 0, sizeof(csrow->kobj));
-       csrow->mci = mci;       /* include container up link */
+       edac_dbg(1, "Releasing dimm device %s\n", dev_name(dev));
+       kfree(dimm);
+}
 
-       /* bump the mci instance's kobject's ref count */
-       kobj = kobject_get(&mci->edac_mci_kobj);
-       if (!kobj) {
-               err = -ENODEV;
-               goto err_out;
-       }
+static struct device_type dimm_attr_type = {
+       .groups         = dimm_attr_groups,
+       .release        = dimm_attr_release,
+};
+
+/* Create a DIMM object under specifed memory controller device */
+static int edac_create_dimm_object(struct mem_ctl_info *mci,
+                                  struct dimm_info *dimm,
+                                  int index)
+{
+       int err;
+       dimm->mci = mci;
 
-       /* Instanstiate the csrow object */
-       err = kobject_init_and_add(&csrow->kobj, &ktype_csrow, kobj_mci,
-                                  "csrow%d", index);
-       if (err)
-               goto err_release_top_kobj;
+       dimm->dev.type = &dimm_attr_type;
+       dimm->dev.bus = &mci->bus;
+       device_initialize(&dimm->dev);
 
-       /* At this point, to release a csrow kobj, one must
-        * call the kobject_put and allow that tear down
-        * to work the releasing
-        */
+       dimm->dev.parent = &mci->dev;
+       if (mci->mem_is_per_rank)
+               dev_set_name(&dimm->dev, "rank%d", index);
+       else
+               dev_set_name(&dimm->dev, "dimm%d", index);
+       dev_set_drvdata(&dimm->dev, dimm);
+       pm_runtime_forbid(&mci->dev);
 
-       /* Create the dyanmic attribute files on this csrow,
-        * namely, the DIMM labels and the channel ce_count
-        */
-       for (chan = 0; chan < csrow->nr_channels; chan++) {
-               err = edac_create_channel_files(&csrow->kobj, chan);
-               if (err) {
-                       /* special case the unregister here */
-                       kobject_put(&csrow->kobj);
-                       goto err_out;
-               }
-       }
-       kobject_uevent(&csrow->kobj, KOBJ_ADD);
-       return 0;
+       err =  device_add(&dimm->dev);
 
-       /* error unwind stack */
-err_release_top_kobj:
-       kobject_put(&mci->edac_mci_kobj);
+       edac_dbg(0, "creating rank/dimm device %s\n", dev_name(&dimm->dev));
 
-err_out:
        return err;
 }
 
-/* default sysfs methods and data structures for the main MCI kobject */
+/*
+ * Memory controller device
+ */
+
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
 
-static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
+static ssize_t mci_reset_counters_store(struct device *dev,
+                                       struct device_attribute *mattr,
                                        const char *data, size_t count)
 {
-       int row, chan;
-
-       mci->ue_noinfo_count = 0;
-       mci->ce_noinfo_count = 0;
+       struct mem_ctl_info *mci = to_mci(dev);
+       int cnt, row, chan, i;
        mci->ue_mc = 0;
        mci->ce_mc = 0;
+       mci->ue_noinfo_count = 0;
+       mci->ce_noinfo_count = 0;
 
        for (row = 0; row < mci->nr_csrows; row++) {
-               struct csrow_info *ri = &mci->csrows[row];
+               struct csrow_info *ri = mci->csrows[row];
 
                ri->ue_count = 0;
                ri->ce_count = 0;
 
                for (chan = 0; chan < ri->nr_channels; chan++)
-                       ri->channels[chan].ce_count = 0;
+                       ri->channels[chan]->ce_count = 0;
+       }
+
+       cnt = 1;
+       for (i = 0; i < mci->n_layers; i++) {
+               cnt *= mci->layers[i].size;
+               memset(mci->ce_per_layer[i], 0, cnt * sizeof(u32));
+               memset(mci->ue_per_layer[i], 0, cnt * sizeof(u32));
        }
 
        mci->start_time = jiffies;
@@ -451,9 +666,11 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
  * Negative value still means that an error has occurred while setting
  * the scrub rate.
  */
-static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
+static ssize_t mci_sdram_scrub_rate_store(struct device *dev,
+                                         struct device_attribute *mattr,
                                          const char *data, size_t count)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        unsigned long bandwidth = 0;
        int new_bw = 0;
 
@@ -476,8 +693,11 @@ static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
 /*
  * ->get_sdram_scrub_rate() return value semantics same as above.
  */
-static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_sdram_scrub_rate_show(struct device *dev,
+                                        struct device_attribute *mattr,
+                                        char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        int bandwidth = 0;
 
        if (!mci->get_sdram_scrub_rate)
@@ -493,45 +713,72 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
 }
 
 /* default attribute files for the MCI object */
-static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_ue_count_show(struct device *dev,
+                                struct device_attribute *mattr,
+                                char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
+
        return sprintf(data, "%d\n", mci->ue_mc);
 }
 
-static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_ce_count_show(struct device *dev,
+                                struct device_attribute *mattr,
+                                char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
+
        return sprintf(data, "%d\n", mci->ce_mc);
 }
 
-static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_ce_noinfo_show(struct device *dev,
+                                 struct device_attribute *mattr,
+                                 char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
+
        return sprintf(data, "%d\n", mci->ce_noinfo_count);
 }
 
-static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_ue_noinfo_show(struct device *dev,
+                                 struct device_attribute *mattr,
+                                 char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
+
        return sprintf(data, "%d\n", mci->ue_noinfo_count);
 }
 
-static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_seconds_show(struct device *dev,
+                               struct device_attribute *mattr,
+                               char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
+
        return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ);
 }
 
-static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_ctl_name_show(struct device *dev,
+                                struct device_attribute *mattr,
+                                char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
+
        return sprintf(data, "%s\n", mci->ctl_name);
 }
 
-static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mci_size_mb_show(struct device *dev,
+                               struct device_attribute *mattr,
+                               char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        int total_pages = 0, csrow_idx, j;
 
        for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) {
-               struct csrow_info *csrow = &mci->csrows[csrow_idx];
+               struct csrow_info *csrow = mci->csrows[csrow_idx];
 
                for (j = 0; j < csrow->nr_channels; j++) {
-                       struct dimm_info *dimm = csrow->channels[j].dimm;
+                       struct dimm_info *dimm = csrow->channels[j]->dimm;
 
                        total_pages += dimm->nr_pages;
                }
@@ -540,361 +787,187 @@ static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
        return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));
 }
 
-#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
-#define to_mcidev_attr(a) container_of(a,struct mcidev_sysfs_attribute,attr)
-
-/* MCI show/store functions for top most object */
-static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
-                       char *buffer)
+static ssize_t mci_max_location_show(struct device *dev,
+                                    struct device_attribute *mattr,
+                                    char *data)
 {
-       struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
-       struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
-
-       debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+       struct mem_ctl_info *mci = to_mci(dev);
+       int i;
+       char *p = data;
 
-       if (mcidev_attr->show)
-               return mcidev_attr->show(mem_ctl_info, buffer);
+       for (i = 0; i < mci->n_layers; i++) {
+               p += sprintf(p, "%s %d ",
+                            edac_layer_name[mci->layers[i].type],
+                            mci->layers[i].size - 1);
+       }
 
-       return -EIO;
+       return p - data;
 }
 
-static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
-                       const char *buffer, size_t count)
+#ifdef CONFIG_EDAC_DEBUG
+static ssize_t edac_fake_inject_write(struct file *file,
+                                     const char __user *data,
+                                     size_t count, loff_t *ppos)
 {
-       struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
-       struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
-
-       debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
-
-       if (mcidev_attr->store)
-               return mcidev_attr->store(mem_ctl_info, buffer, count);
+       struct device *dev = file->private_data;
+       struct mem_ctl_info *mci = to_mci(dev);
+       static enum hw_event_mc_err_type type;
+       u16 errcount = mci->fake_inject_count;
+
+       if (!errcount)
+               errcount = 1;
+
+       type = mci->fake_inject_ue ? HW_EVENT_ERR_UNCORRECTED
+                                  : HW_EVENT_ERR_CORRECTED;
+
+       printk(KERN_DEBUG
+              "Generating %d %s fake error%s to %d.%d.%d to test core handling. NOTE: this won't test the driver-specific decoding logic.\n",
+               errcount,
+               (type == HW_EVENT_ERR_UNCORRECTED) ? "UE" : "CE",
+               errcount > 1 ? "s" : "",
+               mci->fake_inject_layer[0],
+               mci->fake_inject_layer[1],
+               mci->fake_inject_layer[2]
+              );
+       edac_mc_handle_error(type, mci, errcount, 0, 0, 0,
+                            mci->fake_inject_layer[0],
+                            mci->fake_inject_layer[1],
+                            mci->fake_inject_layer[2],
+                            "FAKE ERROR", "for EDAC testing only");
 
-       return -EIO;
+       return count;
 }
 
-/* Intermediate show/store table */
-static const struct sysfs_ops mci_ops = {
-       .show = mcidev_show,
-       .store = mcidev_store
-};
+static int debugfs_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
 
-#define MCIDEV_ATTR(_name,_mode,_show,_store)                  \
-static struct mcidev_sysfs_attribute mci_attr_##_name = {                      \
-       .attr = {.name = __stringify(_name), .mode = _mode },   \
-       .show   = _show,                                        \
-       .store  = _store,                                       \
+static const struct file_operations debug_fake_inject_fops = {
+       .open = debugfs_open,
+       .write = edac_fake_inject_write,
+       .llseek = generic_file_llseek,
 };
+#endif
 
 /* default Control file */
-MCIDEV_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
+DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
 
 /* default Attribute files */
-MCIDEV_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
-MCIDEV_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
-MCIDEV_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
-MCIDEV_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
-MCIDEV_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
-MCIDEV_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
-MCIDEV_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
+DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
+DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
+DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
+DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
+DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
+DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
+DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
+DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL);
 
 /* memory scrubber attribute file */
-MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
+DEVICE_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
        mci_sdram_scrub_rate_store);
 
-static struct mcidev_sysfs_attribute *mci_attr[] = {
-       &mci_attr_reset_counters,
-       &mci_attr_mc_name,
-       &mci_attr_size_mb,
-       &mci_attr_seconds_since_reset,
-       &mci_attr_ue_noinfo_count,
-       &mci_attr_ce_noinfo_count,
-       &mci_attr_ue_count,
-       &mci_attr_ce_count,
-       &mci_attr_sdram_scrub_rate,
+static struct attribute *mci_attrs[] = {
+       &dev_attr_reset_counters.attr,
+       &dev_attr_mc_name.attr,
+       &dev_attr_size_mb.attr,
+       &dev_attr_seconds_since_reset.attr,
+       &dev_attr_ue_noinfo_count.attr,
+       &dev_attr_ce_noinfo_count.attr,
+       &dev_attr_ue_count.attr,
+       &dev_attr_ce_count.attr,
+       &dev_attr_sdram_scrub_rate.attr,
+       &dev_attr_max_location.attr,
        NULL
 };
 
+static struct attribute_group mci_attr_grp = {
+       .attrs  = mci_attrs,
+};
 
-/*
- * Release of a MC controlling instance
- *
- *     each MC control instance has the following resources upon entry:
- *             a) a ref count on the top memctl kobj
- *             b) a ref count on this module
- *
- *     this function must decrement those ref counts and then
- *     issue a free on the instance's memory
- */
-static void edac_mci_control_release(struct kobject *kobj)
-{
-       struct mem_ctl_info *mci;
-
-       mci = to_mci(kobj);
+static const struct attribute_group *mci_attr_groups[] = {
+       &mci_attr_grp,
+       NULL
+};
 
-       debugf0("%s() mci instance idx=%d releasing\n", __func__, mci->mc_idx);
+static void mci_attr_release(struct device *dev)
+{
+       struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev);
 
-       /* decrement the module ref count */
-       module_put(mci->owner);
+       edac_dbg(1, "Releasing csrow device %s\n", dev_name(dev));
+       kfree(mci);
 }
 
-static struct kobj_type ktype_mci = {
-       .release = edac_mci_control_release,
-       .sysfs_ops = &mci_ops,
-       .default_attrs = (struct attribute **)mci_attr,
+static struct device_type mci_attr_type = {
+       .groups         = mci_attr_groups,
+       .release        = mci_attr_release,
 };
 
-/* EDAC memory controller sysfs kset:
- *     /sys/devices/system/edac/mc
- */
-static struct kset *mc_kset;
+#ifdef CONFIG_EDAC_DEBUG
+static struct dentry *edac_debugfs;
 
-/*
- * edac_mc_register_sysfs_main_kobj
- *
- *     setups and registers the main kobject for each mci
- */
-int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
+int __init edac_debugfs_init(void)
 {
-       struct kobject *kobj_mci;
-       int err;
-
-       debugf1("%s()\n", __func__);
-
-       kobj_mci = &mci->edac_mci_kobj;
-
-       /* Init the mci's kobject */
-       memset(kobj_mci, 0, sizeof(*kobj_mci));
-
-       /* Record which module 'owns' this control structure
-        * and bump the ref count of the module
-        */
-       mci->owner = THIS_MODULE;
-
-       /* bump ref count on this module */
-       if (!try_module_get(mci->owner)) {
-               err = -ENODEV;
-               goto fail_out;
-       }
-
-       /* this instance become part of the mc_kset */
-       kobj_mci->kset = mc_kset;
-
-       /* register the mc<id> kobject to the mc_kset */
-       err = kobject_init_and_add(kobj_mci, &ktype_mci, NULL,
-                                  "mc%d", mci->mc_idx);
-       if (err) {
-               debugf1("%s()Failed to register '.../edac/mc%d'\n",
-                       __func__, mci->mc_idx);
-               goto kobj_reg_fail;
+       edac_debugfs = debugfs_create_dir("edac", NULL);
+       if (IS_ERR(edac_debugfs)) {
+               edac_debugfs = NULL;
+               return -ENOMEM;
        }
-       kobject_uevent(kobj_mci, KOBJ_ADD);
-
-       /* At this point, to 'free' the control struct,
-        * edac_mc_unregister_sysfs_main_kobj() must be used
-        */
-
-       debugf1("%s() Registered '.../edac/mc%d' kobject\n",
-               __func__, mci->mc_idx);
-
        return 0;
-
-       /* Error exit stack */
-
-kobj_reg_fail:
-       module_put(mci->owner);
-
-fail_out:
-       return err;
-}
-
-/*
- * edac_mc_register_sysfs_main_kobj
- *
- *     tears down and the main mci kobject from the mc_kset
- */
-void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
-{
-       debugf1("%s()\n", __func__);
-
-       /* delete the kobj from the mc_kset */
-       kobject_put(&mci->edac_mci_kobj);
-}
-
-#define EDAC_DEVICE_SYMLINK    "device"
-
-#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group_kobj, kobj)->mci)
-
-/* MCI show/store functions for top most object */
-static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr,
-                       char *buffer)
-{
-       struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
-       struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
-
-       debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
-
-       if (mcidev_attr->show)
-               return mcidev_attr->show(mem_ctl_info, buffer);
-
-       return -EIO;
 }
 
-static ssize_t inst_grp_store(struct kobject *kobj, struct attribute *attr,
-                       const char *buffer, size_t count)
+void __exit edac_debugfs_exit(void)
 {
-       struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
-       struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
-
-       debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
-
-       if (mcidev_attr->store)
-               return mcidev_attr->store(mem_ctl_info, buffer, count);
-
-       return -EIO;
+       debugfs_remove(edac_debugfs);
 }
 
-/* No memory to release for this kobj */
-static void edac_inst_grp_release(struct kobject *kobj)
+int edac_create_debug_nodes(struct mem_ctl_info *mci)
 {
-       struct mcidev_sysfs_group_kobj *grp;
-       struct mem_ctl_info *mci;
-
-       debugf1("%s()\n", __func__);
-
-       grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj);
-       mci = grp->mci;
-}
-
-/* Intermediate show/store table */
-static struct sysfs_ops inst_grp_ops = {
-       .show = inst_grp_show,
-       .store = inst_grp_store
-};
-
-/* the kobj_type instance for a instance group */
-static struct kobj_type ktype_inst_grp = {
-       .release = edac_inst_grp_release,
-       .sysfs_ops = &inst_grp_ops,
-};
-
+       struct dentry *d, *parent;
+       char name[80];
+       int i;
 
-/*
- * edac_create_mci_instance_attributes
- *     create MC driver specific attributes bellow an specified kobj
- * This routine calls itself recursively, in order to create an entire
- * object tree.
- */
-static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
-                               const struct mcidev_sysfs_attribute *sysfs_attrib,
-                               struct kobject *kobj)
-{
-       int err;
+       if (!edac_debugfs)
+               return -ENODEV;
 
-       debugf4("%s()\n", __func__);
-
-       while (sysfs_attrib) {
-               debugf4("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
-               if (sysfs_attrib->grp) {
-                       struct mcidev_sysfs_group_kobj *grp_kobj;
-
-                       grp_kobj = kzalloc(sizeof(*grp_kobj), GFP_KERNEL);
-                       if (!grp_kobj)
-                               return -ENOMEM;
-
-                       grp_kobj->grp = sysfs_attrib->grp;
-                       grp_kobj->mci = mci;
-                       list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
-
-                       debugf0("%s() grp %s, mci %p\n", __func__,
-                               sysfs_attrib->grp->name, mci);
-
-                       err = kobject_init_and_add(&grp_kobj->kobj,
-                                               &ktype_inst_grp,
-                                               &mci->edac_mci_kobj,
-                                               sysfs_attrib->grp->name);
-                       if (err < 0) {
-                               printk(KERN_ERR "kobject_init_and_add failed: %d\n", err);
-                               return err;
-                       }
-                       err = edac_create_mci_instance_attributes(mci,
-                                       grp_kobj->grp->mcidev_attr,
-                                       &grp_kobj->kobj);
-
-                       if (err < 0)
-                               return err;
-               } else if (sysfs_attrib->attr.name) {
-                       debugf4("%s() file %s\n", __func__,
-                               sysfs_attrib->attr.name);
-
-                       err = sysfs_create_file(kobj, &sysfs_attrib->attr);
-                       if (err < 0) {
-                               printk(KERN_ERR "sysfs_create_file failed: %d\n", err);
-                               return err;
-                       }
-               } else
-                       break;
-
-               sysfs_attrib++;
+       d = debugfs_create_dir(mci->dev.kobj.name, edac_debugfs);
+       if (!d)
+               return -ENOMEM;
+       parent = d;
+
+       for (i = 0; i < mci->n_layers; i++) {
+               sprintf(name, "fake_inject_%s",
+                            edac_layer_name[mci->layers[i].type]);
+               d = debugfs_create_u8(name, S_IRUGO | S_IWUSR, parent,
+                                     &mci->fake_inject_layer[i]);
+               if (!d)
+                       goto nomem;
        }
 
-       return 0;
-}
+       d = debugfs_create_bool("fake_inject_ue", S_IRUGO | S_IWUSR, parent,
+                               &mci->fake_inject_ue);
+       if (!d)
+               goto nomem;
 
-/*
- * edac_remove_mci_instance_attributes
- *     remove MC driver specific attributes at the topmost level
- *     directory of this mci instance.
- */
-static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
-                               const struct mcidev_sysfs_attribute *sysfs_attrib,
-                               struct kobject *kobj, int count)
-{
-       struct mcidev_sysfs_group_kobj *grp_kobj, *tmp;
+       d = debugfs_create_u16("fake_inject_count", S_IRUGO | S_IWUSR, parent,
+                               &mci->fake_inject_count);
+       if (!d)
+               goto nomem;
 
-       debugf1("%s()\n", __func__);
-
-       /*
-        * loop if there are attributes and until we hit a NULL entry
-        * Remove first all the attributes
-        */
-       while (sysfs_attrib) {
-               debugf4("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
-               if (sysfs_attrib->grp) {
-                       debugf4("%s() seeking for group %s\n",
-                               __func__, sysfs_attrib->grp->name);
-                       list_for_each_entry(grp_kobj,
-                                           &mci->grp_kobj_list, list) {
-                               debugf4("%s() grp_kobj->grp = %p\n",__func__, grp_kobj->grp);
-                               if (grp_kobj->grp == sysfs_attrib->grp) {
-                                       edac_remove_mci_instance_attributes(mci,
-                                                   grp_kobj->grp->mcidev_attr,
-                                                   &grp_kobj->kobj, count + 1);
-                                       debugf4("%s() group %s\n", __func__,
-                                               sysfs_attrib->grp->name);
-                                       kobject_put(&grp_kobj->kobj);
-                               }
-                       }
-                       debugf4("%s() end of seeking for group %s\n",
-                               __func__, sysfs_attrib->grp->name);
-               } else if (sysfs_attrib->attr.name) {
-                       debugf4("%s() file %s\n", __func__,
-                               sysfs_attrib->attr.name);
-                       sysfs_remove_file(kobj, &sysfs_attrib->attr);
-               } else
-                       break;
-               sysfs_attrib++;
-       }
+       d = debugfs_create_file("fake_inject", S_IWUSR, parent,
+                               &mci->dev,
+                               &debug_fake_inject_fops);
+       if (!d)
+               goto nomem;
 
-       /* Remove the group objects */
-       if (count)
-               return;
-       list_for_each_entry_safe(grp_kobj, tmp,
-                                &mci->grp_kobj_list, list) {
-               list_del(&grp_kobj->list);
-               kfree(grp_kobj);
-       }
+       mci->debugfs = parent;
+       return 0;
+nomem:
+       debugfs_remove(mci->debugfs);
+       return -ENOMEM;
 }
-
+#endif
 
 /*
  * Create a new Memory Controller kobject instance,
@@ -906,77 +979,87 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
  */
 int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
 {
-       int i, j;
-       int err;
-       struct csrow_info *csrow;
-       struct kobject *kobj_mci = &mci->edac_mci_kobj;
+       int i, err;
 
-       debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
-
-       INIT_LIST_HEAD(&mci->grp_kobj_list);
+       /*
+        * The memory controller needs its own bus, in order to avoid
+        * namespace conflicts at /sys/bus/edac.
+        */
+       mci->bus.name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
+       if (!mci->bus.name)
+               return -ENOMEM;
+       edac_dbg(0, "creating bus %s\n", mci->bus.name);
+       err = bus_register(&mci->bus);
+       if (err < 0)
+               return err;
 
-       /* create a symlink for the device */
-       err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
-                               EDAC_DEVICE_SYMLINK);
-       if (err) {
-               debugf1("%s() failure to create symlink\n", __func__);
-               goto fail0;
+       /* get the /sys/devices/system/edac subsys reference */
+       mci->dev.type = &mci_attr_type;
+       device_initialize(&mci->dev);
+
+       mci->dev.parent = mci_pdev;
+       mci->dev.bus = &mci->bus;
+       dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
+       dev_set_drvdata(&mci->dev, mci);
+       pm_runtime_forbid(&mci->dev);
+
+       edac_dbg(0, "creating device %s\n", dev_name(&mci->dev));
+       err = device_add(&mci->dev);
+       if (err < 0) {
+               bus_unregister(&mci->bus);
+               kfree(mci->bus.name);
+               return err;
        }
 
-       /* If the low level driver desires some attributes,
-        * then create them now for the driver.
+       /*
+        * Create the dimm/rank devices
         */
-       if (mci->mc_driver_sysfs_attributes) {
-               err = edac_create_mci_instance_attributes(mci,
-                                       mci->mc_driver_sysfs_attributes,
-                                       &mci->edac_mci_kobj);
+       for (i = 0; i < mci->tot_dimms; i++) {
+               struct dimm_info *dimm = mci->dimms[i];
+               /* Only expose populated DIMMs */
+               if (dimm->nr_pages == 0)
+                       continue;
+#ifdef CONFIG_EDAC_DEBUG
+               edac_dbg(1, "creating dimm%d, located at ", i);
+               if (edac_debug_level >= 1) {
+                       int lay;
+                       for (lay = 0; lay < mci->n_layers; lay++)
+                               printk(KERN_CONT "%s %d ",
+                                       edac_layer_name[mci->layers[lay].type],
+                                       dimm->location[lay]);
+                       printk(KERN_CONT "\n");
+               }
+#endif
+               err = edac_create_dimm_object(mci, dimm, i);
                if (err) {
-                       debugf1("%s() failure to create mci attributes\n",
-                               __func__);
-                       goto fail0;
+                       edac_dbg(1, "failure: create dimm %d obj\n", i);
+                       goto fail;
                }
        }
 
-       /* Make directories for each CSROW object under the mc<id> kobject
-        */
-       for (i = 0; i < mci->nr_csrows; i++) {
-               int nr_pages = 0;
-
-               csrow = &mci->csrows[i];
-               for (j = 0; j < csrow->nr_channels; j++)
-                       nr_pages += csrow->channels[j].dimm->nr_pages;
-
-               if (nr_pages > 0) {
-                       err = edac_create_csrow_object(mci, csrow, i);
-                       if (err) {
-                               debugf1("%s() failure: create csrow %d obj\n",
-                                       __func__, i);
-                               goto fail1;
-                       }
-               }
-       }
+#ifdef CONFIG_EDAC_LEGACY_SYSFS
+       err = edac_create_csrow_objects(mci);
+       if (err < 0)
+               goto fail;
+#endif
 
+#ifdef CONFIG_EDAC_DEBUG
+       edac_create_debug_nodes(mci);
+#endif
        return 0;
 
-fail1:
+fail:
        for (i--; i >= 0; i--) {
-               int nr_pages = 0;
-
-               csrow = &mci->csrows[i];
-               for (j = 0; j < csrow->nr_channels; j++)
-                       nr_pages += csrow->channels[j].dimm->nr_pages;
-               if (nr_pages > 0)
-                       kobject_put(&mci->csrows[i].kobj);
+               struct dimm_info *dimm = mci->dimms[i];
+               if (dimm->nr_pages == 0)
+                       continue;
+               put_device(&dimm->dev);
+               device_del(&dimm->dev);
        }
-
-       /* remove the mci instance's attributes, if any */
-       edac_remove_mci_instance_attributes(mci,
-               mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0);
-
-       /* remove the symlink */
-       sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
-
-fail0:
+       put_device(&mci->dev);
+       device_del(&mci->dev);
+       bus_unregister(&mci->bus);
+       kfree(mci->bus.name);
        return err;
 }
 
@@ -985,98 +1068,84 @@ fail0:
  */
 void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
 {
-       struct csrow_info *csrow;
-       int i, j;
-
-       debugf0("%s()\n", __func__);
-
-       /* remove all csrow kobjects */
-       debugf4("%s()  unregister this mci kobj\n", __func__);
-       for (i = 0; i < mci->nr_csrows; i++) {
-               int nr_pages = 0;
-
-               csrow = &mci->csrows[i];
-               for (j = 0; j < csrow->nr_channels; j++)
-                       nr_pages += csrow->channels[j].dimm->nr_pages;
-               if (nr_pages > 0) {
-                       debugf0("%s()  unreg csrow-%d\n", __func__, i);
-                       kobject_put(&mci->csrows[i].kobj);
-               }
-       }
+       int i;
 
-       /* remove this mci instance's attribtes */
-       if (mci->mc_driver_sysfs_attributes) {
-               debugf4("%s()  unregister mci private attributes\n", __func__);
-               edac_remove_mci_instance_attributes(mci,
-                                               mci->mc_driver_sysfs_attributes,
-                                               &mci->edac_mci_kobj, 0);
+       edac_dbg(0, "\n");
+
+#ifdef CONFIG_EDAC_DEBUG
+       debugfs_remove(mci->debugfs);
+#endif
+#ifdef CONFIG_EDAC_LEGACY_SYSFS
+       edac_delete_csrow_objects(mci);
+#endif
+
+       for (i = 0; i < mci->tot_dimms; i++) {
+               struct dimm_info *dimm = mci->dimms[i];
+               if (dimm->nr_pages == 0)
+                       continue;
+               edac_dbg(0, "removing device %s\n", dev_name(&dimm->dev));
+               put_device(&dimm->dev);
+               device_del(&dimm->dev);
        }
-
-       /* remove the symlink */
-       debugf4("%s()  remove_link\n", __func__);
-       sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
-
-       /* unregister this instance's kobject */
-       debugf4("%s()  remove_mci_instance\n", __func__);
-       kobject_put(&mci->edac_mci_kobj);
 }
 
+void edac_unregister_sysfs(struct mem_ctl_info *mci)
+{
+       edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
+       put_device(&mci->dev);
+       device_del(&mci->dev);
+       bus_unregister(&mci->bus);
+       kfree(mci->bus.name);
+}
 
+static void mc_attr_release(struct device *dev)
+{
+       /*
+        * There's no container structure here, as this is just the mci
+        * parent device, used to create the /sys/devices/mc sysfs node.
+        * So, there are no attributes on it.
+        */
+       edac_dbg(1, "Releasing device %s\n", dev_name(dev));
+       kfree(dev);
+}
 
-
+static struct device_type mc_attr_type = {
+       .release        = mc_attr_release,
+};
 /*
- * edac_setup_sysfs_mc_kset(void)
- *
- * Initialize the mc_kset for the 'mc' entry
- *     This requires creating the top 'mc' directory with a kset
- *     and its controls/attributes.
- *
- *     To this 'mc' kset, instance 'mci' will be grouped as children.
- *
- * Return:  0 SUCCESS
- *         !0 FAILURE error code
+ * Init/exit code for the module. Basically, creates/removes /sys/class/rc
  */
-int edac_sysfs_setup_mc_kset(void)
+int __init edac_mc_sysfs_init(void)
 {
-       int err = -EINVAL;
        struct bus_type *edac_subsys;
-
-       debugf1("%s()\n", __func__);
+       int err;
 
        /* get the /sys/devices/system/edac subsys reference */
        edac_subsys = edac_get_sysfs_subsys();
        if (edac_subsys == NULL) {
-               debugf1("%s() no edac_subsys error=%d\n", __func__, err);
-               goto fail_out;
+               edac_dbg(1, "no edac_subsys\n");
+               return -EINVAL;
        }
 
-       /* Init the MC's kobject */
-       mc_kset = kset_create_and_add("mc", NULL, &edac_subsys->dev_root->kobj);
-       if (!mc_kset) {
-               err = -ENOMEM;
-               debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
-               goto fail_kset;
-       }
+       mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
 
-       debugf1("%s() Registered '.../edac/mc' kobject\n", __func__);
+       mci_pdev->bus = edac_subsys;
+       mci_pdev->type = &mc_attr_type;
+       device_initialize(mci_pdev);
+       dev_set_name(mci_pdev, "mc");
 
-       return 0;
+       err = device_add(mci_pdev);
+       if (err < 0)
+               return err;
 
-fail_kset:
-       edac_put_sysfs_subsys();
+       edac_dbg(0, "device %s created\n", dev_name(mci_pdev));
 
-fail_out:
-       return err;
+       return 0;
 }
 
-/*
- * edac_sysfs_teardown_mc_kset
- *
- *     deconstruct the mc_ket for memory controllers
- */
-void edac_sysfs_teardown_mc_kset(void)
+void __exit edac_mc_sysfs_exit(void)
 {
-       kset_unregister(mc_kset);
+       put_device(mci_pdev);
+       device_del(mci_pdev);
        edac_put_sysfs_subsys();
 }
-
index 5ddaa86d6a6e86ef8ed0671070168d7541cd7073..58a28d838f37bfef26450bacdf11c8a338f6dcc7 100644 (file)
@@ -15,7 +15,7 @@
 #include "edac_core.h"
 #include "edac_module.h"
 
-#define EDAC_VERSION "Ver: 2.1.0"
+#define EDAC_VERSION "Ver: 3.0.0"
 
 #ifdef CONFIG_EDAC_DEBUG
 /* Values of 0 to 4 will generate output */
@@ -90,26 +90,21 @@ static int __init edac_init(void)
         */
        edac_pci_clear_parity_errors();
 
-       /*
-        * now set up the mc_kset under the edac class object
-        */
-       err = edac_sysfs_setup_mc_kset();
+       err = edac_mc_sysfs_init();
        if (err)
                goto error;
 
+       edac_debugfs_init();
+
        /* Setup/Initialize the workq for this core */
        err = edac_workqueue_setup();
        if (err) {
                edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
-               goto workq_fail;
+               goto error;
        }
 
        return 0;
 
-       /* Error teardown stack */
-workq_fail:
-       edac_sysfs_teardown_mc_kset();
-
 error:
        return err;
 }
@@ -120,11 +115,12 @@ error:
  */
 static void __exit edac_exit(void)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* tear down the various subsystems */
        edac_workqueue_teardown();
-       edac_sysfs_teardown_mc_kset();
+       edac_mc_sysfs_exit();
+       edac_debugfs_exit();
 }
 
 /*
index 0ea7d14cb930748e75aadbb18e48e4616fdc315e..3d139c6e7fe325719b7ddaf4b38127f5895f8bb8 100644 (file)
  *
  * edac_mc objects
  */
-extern int edac_sysfs_setup_mc_kset(void);
-extern void edac_sysfs_teardown_mc_kset(void);
-extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci);
-extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci);
+       /* on edac_mc_sysfs.c */
+int edac_mc_sysfs_init(void);
+void edac_mc_sysfs_exit(void);
 extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci);
 extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
+void edac_unregister_sysfs(struct mem_ctl_info *mci);
 extern int edac_get_log_ue(void);
 extern int edac_get_log_ce(void);
 extern int edac_get_panic_on_ue(void);
@@ -34,6 +34,10 @@ extern int edac_mc_get_panic_on_ue(void);
 extern int edac_get_poll_msec(void);
 extern int edac_mc_get_poll_msec(void);
 
+unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
+                                unsigned len);
+
+       /* on edac_device.c */
 extern int edac_device_register_sysfs_main_kobj(
                                struct edac_device_ctl_info *edac_dev);
 extern void edac_device_unregister_sysfs_main_kobj(
@@ -52,6 +56,20 @@ extern void edac_mc_reset_delay_period(int value);
 
 extern void *edac_align_ptr(void **p, unsigned size, int n_elems);
 
+/*
+ * EDAC debugfs functions
+ */
+#ifdef CONFIG_EDAC_DEBUG
+int edac_debugfs_init(void);
+void edac_debugfs_exit(void);
+#else
+static inline int edac_debugfs_init(void)
+{
+       return -ENODEV;
+}
+static inline void edac_debugfs_exit(void) {}
+#endif
+
 /*
  * EDAC PCI functions
  */
index f1ac866498864dfbfc8e73ad091860d790142a68..ee87ef972ead7667a60a1359e9347e9ebaf60bda 100644 (file)
@@ -45,7 +45,7 @@ struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
        void *p = NULL, *pvt;
        unsigned int size;
 
-       debugf1("%s()\n", __func__);
+       edac_dbg(1, "\n");
 
        pci = edac_align_ptr(&p, sizeof(*pci), 1);
        pvt = edac_align_ptr(&p, 1, sz_pvt);
@@ -80,7 +80,7 @@ EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info);
  */
 void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci)
 {
-       debugf1("%s()\n", __func__);
+       edac_dbg(1, "\n");
 
        edac_pci_remove_sysfs(pci);
 }
@@ -97,7 +97,7 @@ static struct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev)
        struct edac_pci_ctl_info *pci;
        struct list_head *item;
 
-       debugf1("%s()\n", __func__);
+       edac_dbg(1, "\n");
 
        list_for_each(item, &edac_pci_list) {
                pci = list_entry(item, struct edac_pci_ctl_info, link);
@@ -122,7 +122,7 @@ static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci)
        struct list_head *item, *insert_before;
        struct edac_pci_ctl_info *rover;
 
-       debugf1("%s()\n", __func__);
+       edac_dbg(1, "\n");
 
        insert_before = &edac_pci_list;
 
@@ -226,7 +226,7 @@ static void edac_pci_workq_function(struct work_struct *work_req)
        int msec;
        unsigned long delay;
 
-       debugf3("%s() checking\n", __func__);
+       edac_dbg(3, "checking\n");
 
        mutex_lock(&edac_pci_ctls_mutex);
 
@@ -261,7 +261,7 @@ static void edac_pci_workq_function(struct work_struct *work_req)
 static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
                                 unsigned int msec)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
        queue_delayed_work(edac_workqueue, &pci->work,
@@ -276,7 +276,7 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
 {
        int status;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        status = cancel_delayed_work(&pci->work);
        if (status == 0)
@@ -293,7 +293,7 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
 void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
                                 unsigned long value)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        edac_pci_workq_teardown(pci);
 
@@ -333,7 +333,7 @@ EXPORT_SYMBOL_GPL(edac_pci_alloc_index);
  */
 int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        pci->pci_idx = edac_idx;
        pci->start_time = jiffies;
@@ -393,7 +393,7 @@ struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
 {
        struct edac_pci_ctl_info *pci;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        mutex_lock(&edac_pci_ctls_mutex);
 
@@ -430,7 +430,7 @@ EXPORT_SYMBOL_GPL(edac_pci_del_device);
  */
 static void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
 {
-       debugf4("%s()\n", __func__);
+       edac_dbg(4, "\n");
        edac_pci_do_parity_check();
 }
 
@@ -475,7 +475,7 @@ struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev,
        pdata->edac_idx = edac_pci_idx++;
 
        if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
-               debugf3("%s(): failed edac_pci_add_device()\n", __func__);
+               edac_dbg(3, "failed edac_pci_add_device()\n");
                edac_pci_free_ctl_info(pci);
                return NULL;
        }
@@ -491,7 +491,7 @@ EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl);
  */
 void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci)
 {
-       debugf0("%s() pci mod=%s\n", __func__, pci->mod_name);
+       edac_dbg(0, "pci mod=%s\n", pci->mod_name);
 
        edac_pci_del_device(pci->dev);
        edac_pci_free_ctl_info(pci);
index 97f5064e39924deb504fc54922fec0941aa043ca..e164c555a337fb3818817dbef13f1673532ac260 100644 (file)
@@ -78,7 +78,7 @@ static void edac_pci_instance_release(struct kobject *kobj)
 {
        struct edac_pci_ctl_info *pci;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* Form pointer to containing struct, the pci control struct */
        pci = to_instance(kobj);
@@ -161,7 +161,7 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
        struct kobject *main_kobj;
        int err;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* First bump the ref count on the top main kobj, which will
         * track the number of PCI instances we have, and thus nest
@@ -177,14 +177,13 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
        err = kobject_init_and_add(&pci->kobj, &ktype_pci_instance,
                                   edac_pci_top_main_kobj, "pci%d", idx);
        if (err != 0) {
-               debugf2("%s() failed to register instance pci%d\n",
-                       __func__, idx);
+               edac_dbg(2, "failed to register instance pci%d\n", idx);
                kobject_put(edac_pci_top_main_kobj);
                goto error_out;
        }
 
        kobject_uevent(&pci->kobj, KOBJ_ADD);
-       debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx);
+       edac_dbg(1, "Register instance 'pci%d' kobject\n", idx);
 
        return 0;
 
@@ -201,7 +200,7 @@ error_out:
 static void edac_pci_unregister_sysfs_instance_kobj(
                        struct edac_pci_ctl_info *pci)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* Unregister the instance kobject and allow its release
         * function release the main reference count and then
@@ -317,7 +316,7 @@ static struct edac_pci_dev_attribute *edac_pci_attr[] = {
  */
 static void edac_pci_release_main_kobj(struct kobject *kobj)
 {
-       debugf0("%s() here to module_put(THIS_MODULE)\n", __func__);
+       edac_dbg(0, "here to module_put(THIS_MODULE)\n");
 
        kfree(kobj);
 
@@ -345,7 +344,7 @@ static int edac_pci_main_kobj_setup(void)
        int err;
        struct bus_type *edac_subsys;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* check and count if we have already created the main kobject */
        if (atomic_inc_return(&edac_pci_sysfs_refcount) != 1)
@@ -356,7 +355,7 @@ static int edac_pci_main_kobj_setup(void)
         */
        edac_subsys = edac_get_sysfs_subsys();
        if (edac_subsys == NULL) {
-               debugf1("%s() no edac_subsys\n", __func__);
+               edac_dbg(1, "no edac_subsys\n");
                err = -ENODEV;
                goto decrement_count_fail;
        }
@@ -366,14 +365,14 @@ static int edac_pci_main_kobj_setup(void)
         * level main kobj for EDAC PCI
         */
        if (!try_module_get(THIS_MODULE)) {
-               debugf1("%s() try_module_get() failed\n", __func__);
+               edac_dbg(1, "try_module_get() failed\n");
                err = -ENODEV;
                goto mod_get_fail;
        }
 
        edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
        if (!edac_pci_top_main_kobj) {
-               debugf1("Failed to allocate\n");
+               edac_dbg(1, "Failed to allocate\n");
                err = -ENOMEM;
                goto kzalloc_fail;
        }
@@ -383,7 +382,7 @@ static int edac_pci_main_kobj_setup(void)
                                   &ktype_edac_pci_main_kobj,
                                   &edac_subsys->dev_root->kobj, "pci");
        if (err) {
-               debugf1("Failed to register '.../edac/pci'\n");
+               edac_dbg(1, "Failed to register '.../edac/pci'\n");
                goto kobject_init_and_add_fail;
        }
 
@@ -392,7 +391,7 @@ static int edac_pci_main_kobj_setup(void)
         * must be used, for resources to be cleaned up properly
         */
        kobject_uevent(edac_pci_top_main_kobj, KOBJ_ADD);
-       debugf1("Registered '.../edac/pci' kobject\n");
+       edac_dbg(1, "Registered '.../edac/pci' kobject\n");
 
        return 0;
 
@@ -421,15 +420,14 @@ decrement_count_fail:
  */
 static void edac_pci_main_kobj_teardown(void)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* Decrement the count and only if no more controller instances
         * are connected perform the unregisteration of the top level
         * main kobj
         */
        if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
-               debugf0("%s() called kobject_put on main kobj\n",
-                       __func__);
+               edac_dbg(0, "called kobject_put on main kobj\n");
                kobject_put(edac_pci_top_main_kobj);
        }
        edac_put_sysfs_subsys();
@@ -446,7 +444,7 @@ int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)
        int err;
        struct kobject *edac_kobj = &pci->kobj;
 
-       debugf0("%s() idx=%d\n", __func__, pci->pci_idx);
+       edac_dbg(0, "idx=%d\n", pci->pci_idx);
 
        /* create the top main EDAC PCI kobject, IF needed */
        err = edac_pci_main_kobj_setup();
@@ -460,8 +458,7 @@ int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)
 
        err = sysfs_create_link(edac_kobj, &pci->dev->kobj, EDAC_PCI_SYMLINK);
        if (err) {
-               debugf0("%s() sysfs_create_link() returned err= %d\n",
-                       __func__, err);
+               edac_dbg(0, "sysfs_create_link() returned err= %d\n", err);
                goto symlink_fail;
        }
 
@@ -484,7 +481,7 @@ unregister_cleanup:
  */
 void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)
 {
-       debugf0("%s() index=%d\n", __func__, pci->pci_idx);
+       edac_dbg(0, "index=%d\n", pci->pci_idx);
 
        /* Remove the symlink */
        sysfs_remove_link(&pci->kobj, EDAC_PCI_SYMLINK);
@@ -496,7 +493,7 @@ void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)
         * if this 'pci' is the last instance.
         * If it is, the main kobject will be unregistered as a result
         */
-       debugf0("%s() calling edac_pci_main_kobj_teardown()\n", __func__);
+       edac_dbg(0, "calling edac_pci_main_kobj_teardown()\n");
        edac_pci_main_kobj_teardown();
 }
 
@@ -572,7 +569,7 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev)
 
        local_irq_restore(flags);
 
-       debugf4("PCI STATUS= 0x%04x %s\n", status, dev_name(&dev->dev));
+       edac_dbg(4, "PCI STATUS= 0x%04x %s\n", status, dev_name(&dev->dev));
 
        /* check the status reg for errors on boards NOT marked as broken
         * if broken, we cannot trust any of the status bits
@@ -603,13 +600,15 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev)
        }
 
 
-       debugf4("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev_name(&dev->dev));
+       edac_dbg(4, "PCI HEADER TYPE= 0x%02x %s\n",
+                header_type, dev_name(&dev->dev));
 
        if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
                /* On bridges, need to examine secondary status register  */
                status = get_pci_parity_status(dev, 1);
 
-               debugf4("PCI SEC_STATUS= 0x%04x %s\n", status, dev_name(&dev->dev));
+               edac_dbg(4, "PCI SEC_STATUS= 0x%04x %s\n",
+                        status, dev_name(&dev->dev));
 
                /* check the secondary status reg for errors,
                 * on NOT broken boards
@@ -671,7 +670,7 @@ void edac_pci_do_parity_check(void)
 {
        int before_count;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        /* if policy has PCI check off, leave now */
        if (!check_pci_errors)
diff --git a/drivers/edac/highbank_l2_edac.c b/drivers/edac/highbank_l2_edac.c
new file mode 100644 (file)
index 0000000..e599b00
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2011-2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define SR_CLR_SB_ECC_INTR     0x0
+#define SR_CLR_DB_ECC_INTR     0x4
+
+struct hb_l2_drvdata {
+       void __iomem *base;
+       int sb_irq;
+       int db_irq;
+};
+
+static irqreturn_t highbank_l2_err_handler(int irq, void *dev_id)
+{
+       struct edac_device_ctl_info *dci = dev_id;
+       struct hb_l2_drvdata *drvdata = dci->pvt_info;
+
+       if (irq == drvdata->sb_irq) {
+               writel(1, drvdata->base + SR_CLR_SB_ECC_INTR);
+               edac_device_handle_ce(dci, 0, 0, dci->ctl_name);
+       }
+       if (irq == drvdata->db_irq) {
+               writel(1, drvdata->base + SR_CLR_DB_ECC_INTR);
+               edac_device_handle_ue(dci, 0, 0, dci->ctl_name);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit highbank_l2_err_probe(struct platform_device *pdev)
+{
+       struct edac_device_ctl_info *dci;
+       struct hb_l2_drvdata *drvdata;
+       struct resource *r;
+       int res = 0;
+
+       dci = edac_device_alloc_ctl_info(sizeof(*drvdata), "cpu",
+               1, "L", 1, 2, NULL, 0, 0);
+       if (!dci)
+               return -ENOMEM;
+
+       drvdata = dci->pvt_info;
+       dci->dev = &pdev->dev;
+       platform_set_drvdata(pdev, dci);
+
+       if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))
+               return -ENOMEM;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pdev->dev, "Unable to get mem resource\n");
+               res = -ENODEV;
+               goto err;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev, r->start,
+                                    resource_size(r), dev_name(&pdev->dev))) {
+               dev_err(&pdev->dev, "Error while requesting mem region\n");
+               res = -EBUSY;
+               goto err;
+       }
+
+       drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+       if (!drvdata->base) {
+               dev_err(&pdev->dev, "Unable to map regs\n");
+               res = -ENOMEM;
+               goto err;
+       }
+
+       drvdata->db_irq = platform_get_irq(pdev, 0);
+       res = devm_request_irq(&pdev->dev, drvdata->db_irq,
+                              highbank_l2_err_handler,
+                              0, dev_name(&pdev->dev), dci);
+       if (res < 0)
+               goto err;
+
+       drvdata->sb_irq = platform_get_irq(pdev, 1);
+       res = devm_request_irq(&pdev->dev, drvdata->sb_irq,
+                              highbank_l2_err_handler,
+                              0, dev_name(&pdev->dev), dci);
+       if (res < 0)
+               goto err;
+
+       dci->mod_name = dev_name(&pdev->dev);
+       dci->dev_name = dev_name(&pdev->dev);
+
+       if (edac_device_add_device(dci))
+               goto err;
+
+       devres_close_group(&pdev->dev, NULL);
+       return 0;
+err:
+       devres_release_group(&pdev->dev, NULL);
+       edac_device_free_ctl_info(dci);
+       return res;
+}
+
+static int highbank_l2_err_remove(struct platform_device *pdev)
+{
+       struct edac_device_ctl_info *dci = platform_get_drvdata(pdev);
+
+       edac_device_del_device(&pdev->dev);
+       edac_device_free_ctl_info(dci);
+       return 0;
+}
+
+static const struct of_device_id hb_l2_err_of_match[] = {
+       { .compatible = "calxeda,hb-sregs-l2-ecc", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, hb_l2_err_of_match);
+
+static struct platform_driver highbank_l2_edac_driver = {
+       .probe = highbank_l2_err_probe,
+       .remove = highbank_l2_err_remove,
+       .driver = {
+               .name = "hb_l2_edac",
+               .of_match_table = hb_l2_err_of_match,
+       },
+};
+
+module_platform_driver(highbank_l2_edac_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Calxeda, Inc.");
+MODULE_DESCRIPTION("EDAC Driver for Calxeda Highbank L2 Cache");
diff --git a/drivers/edac/highbank_mc_edac.c b/drivers/edac/highbank_mc_edac.c
new file mode 100644 (file)
index 0000000..c769f47
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2011-2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/uaccess.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+/* DDR Ctrlr Error Registers */
+#define HB_DDR_ECC_OPT                 0x128
+#define HB_DDR_ECC_U_ERR_ADDR          0x130
+#define HB_DDR_ECC_U_ERR_STAT          0x134
+#define HB_DDR_ECC_U_ERR_DATAL         0x138
+#define HB_DDR_ECC_U_ERR_DATAH         0x13c
+#define HB_DDR_ECC_C_ERR_ADDR          0x140
+#define HB_DDR_ECC_C_ERR_STAT          0x144
+#define HB_DDR_ECC_C_ERR_DATAL         0x148
+#define HB_DDR_ECC_C_ERR_DATAH         0x14c
+#define HB_DDR_ECC_INT_STATUS          0x180
+#define HB_DDR_ECC_INT_ACK             0x184
+#define HB_DDR_ECC_U_ERR_ID            0x424
+#define HB_DDR_ECC_C_ERR_ID            0x428
+
+#define HB_DDR_ECC_INT_STAT_CE         0x8
+#define HB_DDR_ECC_INT_STAT_DOUBLE_CE  0x10
+#define HB_DDR_ECC_INT_STAT_UE         0x20
+#define HB_DDR_ECC_INT_STAT_DOUBLE_UE  0x40
+
+#define HB_DDR_ECC_OPT_MODE_MASK       0x3
+#define HB_DDR_ECC_OPT_FWC             0x100
+#define HB_DDR_ECC_OPT_XOR_SHIFT       16
+
+struct hb_mc_drvdata {
+       void __iomem *mc_vbase;
+};
+
+static irqreturn_t highbank_mc_err_handler(int irq, void *dev_id)
+{
+       struct mem_ctl_info *mci = dev_id;
+       struct hb_mc_drvdata *drvdata = mci->pvt_info;
+       u32 status, err_addr;
+
+       /* Read the interrupt status register */
+       status = readl(drvdata->mc_vbase + HB_DDR_ECC_INT_STATUS);
+
+       if (status & HB_DDR_ECC_INT_STAT_UE) {
+               err_addr = readl(drvdata->mc_vbase + HB_DDR_ECC_U_ERR_ADDR);
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
+                                    err_addr >> PAGE_SHIFT,
+                                    err_addr & ~PAGE_MASK, 0,
+                                    0, 0, -1,
+                                    mci->ctl_name, "");
+       }
+       if (status & HB_DDR_ECC_INT_STAT_CE) {
+               u32 syndrome = readl(drvdata->mc_vbase + HB_DDR_ECC_C_ERR_STAT);
+               syndrome = (syndrome >> 8) & 0xff;
+               err_addr = readl(drvdata->mc_vbase + HB_DDR_ECC_C_ERR_ADDR);
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
+                                    err_addr >> PAGE_SHIFT,
+                                    err_addr & ~PAGE_MASK, syndrome,
+                                    0, 0, -1,
+                                    mci->ctl_name, "");
+       }
+
+       /* clear the error, clears the interrupt */
+       writel(status, drvdata->mc_vbase + HB_DDR_ECC_INT_ACK);
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_EDAC_DEBUG
+static ssize_t highbank_mc_err_inject_write(struct file *file,
+                                     const char __user *data,
+                                     size_t count, loff_t *ppos)
+{
+       struct mem_ctl_info *mci = file->private_data;
+       struct hb_mc_drvdata *pdata = mci->pvt_info;
+       char buf[32];
+       size_t buf_size;
+       u32 reg;
+       u8 synd;
+
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, data, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       if (!kstrtou8(buf, 16, &synd)) {
+               reg = readl(pdata->mc_vbase + HB_DDR_ECC_OPT);
+               reg &= HB_DDR_ECC_OPT_MODE_MASK;
+               reg |= (synd << HB_DDR_ECC_OPT_XOR_SHIFT) | HB_DDR_ECC_OPT_FWC;
+               writel(reg, pdata->mc_vbase + HB_DDR_ECC_OPT);
+       }
+
+       return count;
+}
+
+static int debugfs_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+static const struct file_operations highbank_mc_debug_inject_fops = {
+       .open = debugfs_open,
+       .write = highbank_mc_err_inject_write,
+       .llseek = generic_file_llseek,
+};
+
+static void __devinit highbank_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
+{
+       if (mci->debugfs)
+               debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci,
+                                   &highbank_mc_debug_inject_fops);
+;
+}
+#else
+static void __devinit highbank_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
+{}
+#endif
+
+static int __devinit highbank_mc_probe(struct platform_device *pdev)
+{
+       struct edac_mc_layer layers[2];
+       struct mem_ctl_info *mci;
+       struct hb_mc_drvdata *drvdata;
+       struct dimm_info *dimm;
+       struct resource *r;
+       u32 control;
+       int irq;
+       int res = 0;
+
+       layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+       layers[0].size = 1;
+       layers[0].is_virt_csrow = true;
+       layers[1].type = EDAC_MC_LAYER_CHANNEL;
+       layers[1].size = 1;
+       layers[1].is_virt_csrow = false;
+       mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
+                           sizeof(struct hb_mc_drvdata));
+       if (!mci)
+               return -ENOMEM;
+
+       mci->pdev = &pdev->dev;
+       drvdata = mci->pvt_info;
+       platform_set_drvdata(pdev, mci);
+
+       if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))
+               return -ENOMEM;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pdev->dev, "Unable to get mem resource\n");
+               res = -ENODEV;
+               goto err;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev, r->start,
+                                    resource_size(r), dev_name(&pdev->dev))) {
+               dev_err(&pdev->dev, "Error while requesting mem region\n");
+               res = -EBUSY;
+               goto err;
+       }
+
+       drvdata->mc_vbase = devm_ioremap(&pdev->dev,
+                                         r->start, resource_size(r));
+       if (!drvdata->mc_vbase) {
+               dev_err(&pdev->dev, "Unable to map regs\n");
+               res = -ENOMEM;
+               goto err;
+       }
+
+       control = readl(drvdata->mc_vbase + HB_DDR_ECC_OPT) & 0x3;
+       if (!control || (control == 0x2)) {
+               dev_err(&pdev->dev, "No ECC present, or ECC disabled\n");
+               res = -ENODEV;
+               goto err;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       res = devm_request_irq(&pdev->dev, irq, highbank_mc_err_handler,
+                              0, dev_name(&pdev->dev), mci);
+       if (res < 0) {
+               dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
+               goto err;
+       }
+
+       mci->mtype_cap = MEM_FLAG_DDR3;
+       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+       mci->edac_cap = EDAC_FLAG_SECDED;
+       mci->mod_name = dev_name(&pdev->dev);
+       mci->mod_ver = "1";
+       mci->ctl_name = dev_name(&pdev->dev);
+       mci->scrub_mode = SCRUB_SW_SRC;
+
+       /* Only a single 4GB DIMM is supported */
+       dimm = *mci->dimms;
+       dimm->nr_pages = (~0UL >> PAGE_SHIFT) + 1;
+       dimm->grain = 8;
+       dimm->dtype = DEV_X8;
+       dimm->mtype = MEM_DDR3;
+       dimm->edac_mode = EDAC_SECDED;
+
+       res = edac_mc_add_mc(mci);
+       if (res < 0)
+               goto err;
+
+       highbank_mc_create_debugfs_nodes(mci);
+
+       devres_close_group(&pdev->dev, NULL);
+       return 0;
+err:
+       devres_release_group(&pdev->dev, NULL);
+       edac_mc_free(mci);
+       return res;
+}
+
+static int highbank_mc_remove(struct platform_device *pdev)
+{
+       struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+       edac_mc_del_mc(&pdev->dev);
+       edac_mc_free(mci);
+       return 0;
+}
+
+static const struct of_device_id hb_ddr_ctrl_of_match[] = {
+       { .compatible = "calxeda,hb-ddr-ctrl", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, hb_ddr_ctrl_of_match);
+
+static struct platform_driver highbank_mc_edac_driver = {
+       .probe = highbank_mc_probe,
+       .remove = highbank_mc_remove,
+       .driver = {
+               .name = "hb_mc_edac",
+               .of_match_table = hb_ddr_ctrl_of_match,
+       },
+};
+
+module_platform_driver(highbank_mc_edac_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Calxeda, Inc.");
+MODULE_DESCRIPTION("EDAC Driver for Calxeda Highbank");
index 8ad1744faacd9559f6f4ab66eb1bf1b960fd4ee0..d3d19cc4e9a1a48eccb84820dbe8df519955cc96 100644 (file)
@@ -194,7 +194,7 @@ static void i3000_get_error_info(struct mem_ctl_info *mci,
 {
        struct pci_dev *pdev;
 
-       pdev = to_pci_dev(mci->dev);
+       pdev = to_pci_dev(mci->pdev);
 
        /*
         * This is a mess because there is no atomic way to read all the
@@ -236,7 +236,7 @@ static int i3000_process_error_info(struct mem_ctl_info *mci,
        int row, multi_chan, channel;
        unsigned long pfn, offset;
 
-       multi_chan = mci->csrows[0].nr_channels - 1;
+       multi_chan = mci->csrows[0]->nr_channels - 1;
 
        if (!(info->errsts & I3000_ERRSTS_BITS))
                return 0;
@@ -245,9 +245,9 @@ static int i3000_process_error_info(struct mem_ctl_info *mci,
                return 1;
 
        if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) {
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
                                     -1, -1, -1,
-                                    "UE overwrote CE", "", NULL);
+                                    "UE overwrote CE", "");
                info->errsts = info->errsts2;
        }
 
@@ -258,15 +258,15 @@ static int i3000_process_error_info(struct mem_ctl_info *mci,
        row = edac_mc_find_csrow_by_page(mci, pfn);
 
        if (info->errsts & I3000_ERRSTS_UE)
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                     pfn, offset, 0,
                                     row, -1, -1,
-                                    "i3000 UE", "", NULL);
+                                    "i3000 UE", "");
        else
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                     pfn, offset, info->derrsyn,
                                     row, multi_chan ? channel : 0, -1,
-                                    "i3000 CE", "", NULL);
+                                    "i3000 CE", "");
 
        return 1;
 }
@@ -275,7 +275,7 @@ static void i3000_check(struct mem_ctl_info *mci)
 {
        struct i3000_error_info info;
 
-       debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+       edac_dbg(1, "MC%d\n", mci->mc_idx);
        i3000_get_error_info(mci, &info);
        i3000_process_error_info(mci, &info, 1);
 }
@@ -322,7 +322,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
        unsigned long mchbar;
        void __iomem *window;
 
-       debugf0("MC: %s()\n", __func__);
+       edac_dbg(0, "MC:\n");
 
        pci_read_config_dword(pdev, I3000_MCHBAR, (u32 *) & mchbar);
        mchbar &= I3000_MCHBAR_MASK;
@@ -366,9 +366,9 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
        if (!mci)
                return -ENOMEM;
 
-       debugf3("MC: %s(): init mci\n", __func__);
+       edac_dbg(3, "MC: init mci\n");
 
-       mci->dev = &pdev->dev;
+       mci->pdev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_DDR2;
 
        mci->edac_ctl_cap = EDAC_FLAG_SECDED;
@@ -393,14 +393,13 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
        for (last_cumul_size = i = 0; i < mci->nr_csrows; i++) {
                u8 value;
                u32 cumul_size;
-               struct csrow_info *csrow = &mci->csrows[i];
+               struct csrow_info *csrow = mci->csrows[i];
 
                value = drb[i];
                cumul_size = value << (I3000_DRB_SHIFT - PAGE_SHIFT);
                if (interleaved)
                        cumul_size <<= 1;
-               debugf3("MC: %s(): (%d) cumul_size 0x%x\n",
-                       __func__, i, cumul_size);
+               edac_dbg(3, "MC: (%d) cumul_size 0x%x\n", i, cumul_size);
                if (cumul_size == last_cumul_size)
                        continue;
 
@@ -410,7 +409,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
                last_cumul_size = cumul_size;
 
                for (j = 0; j < nr_channels; j++) {
-                       struct dimm_info *dimm = csrow->channels[j].dimm;
+                       struct dimm_info *dimm = csrow->channels[j]->dimm;
 
                        dimm->nr_pages = nr_pages / nr_channels;
                        dimm->grain = I3000_DEAP_GRAIN;
@@ -429,7 +428,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 
        rc = -ENODEV;
        if (edac_mc_add_mc(mci)) {
-               debugf3("MC: %s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "MC: failed edac_mc_add_mc()\n");
                goto fail;
        }
 
@@ -445,7 +444,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
        }
 
        /* get this far and it's successful */
-       debugf3("MC: %s(): success\n", __func__);
+       edac_dbg(3, "MC: success\n");
        return 0;
 
 fail:
@@ -461,7 +460,7 @@ static int __devinit i3000_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("MC: %s()\n", __func__);
+       edac_dbg(0, "MC:\n");
 
        if (pci_enable_device(pdev) < 0)
                return -EIO;
@@ -477,7 +476,7 @@ static void __devexit i3000_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        if (i3000_pci)
                edac_pci_release_generic_ctl(i3000_pci);
@@ -511,7 +510,7 @@ static int __init i3000_init(void)
 {
        int pci_rc;
 
-       debugf3("MC: %s()\n", __func__);
+       edac_dbg(3, "MC:\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -525,14 +524,14 @@ static int __init i3000_init(void)
                mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                        PCI_DEVICE_ID_INTEL_3000_HB, NULL);
                if (!mci_pdev) {
-                       debugf0("i3000 pci_get_device fail\n");
+                       edac_dbg(0, "i3000 pci_get_device fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
 
                pci_rc = i3000_init_one(mci_pdev, i3000_pci_tbl);
                if (pci_rc < 0) {
-                       debugf0("i3000 init fail\n");
+                       edac_dbg(0, "i3000 init fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
@@ -552,7 +551,7 @@ fail0:
 
 static void __exit i3000_exit(void)
 {
-       debugf3("MC: %s()\n", __func__);
+       edac_dbg(3, "MC:\n");
 
        pci_unregister_driver(&i3000_driver);
        if (!i3000_registered) {
index bbe43ef718238c72d159affd4d2f80e22141f88f..47180a08edad28c7c95fea0cd51e9b7b15172f27 100644 (file)
@@ -110,10 +110,10 @@ static int how_many_channels(struct pci_dev *pdev)
 
        pci_read_config_byte(pdev, I3200_CAPID0 + 8, &capid0_8b);
        if (capid0_8b & 0x20) { /* check DCD: Dual Channel Disable */
-               debugf0("In single channel mode.\n");
+               edac_dbg(0, "In single channel mode\n");
                return 1;
        } else {
-               debugf0("In dual channel mode.\n");
+               edac_dbg(0, "In dual channel mode\n");
                return 2;
        }
 }
@@ -159,7 +159,7 @@ static void i3200_clear_error_info(struct mem_ctl_info *mci)
 {
        struct pci_dev *pdev;
 
-       pdev = to_pci_dev(mci->dev);
+       pdev = to_pci_dev(mci->pdev);
 
        /*
         * Clear any error bits.
@@ -176,7 +176,7 @@ static void i3200_get_and_clear_error_info(struct mem_ctl_info *mci,
        struct i3200_priv *priv = mci->pvt_info;
        void __iomem *window = priv->window;
 
-       pdev = to_pci_dev(mci->dev);
+       pdev = to_pci_dev(mci->pdev);
 
        /*
         * This is a mess because there is no atomic way to read all the
@@ -218,25 +218,25 @@ static void i3200_process_error_info(struct mem_ctl_info *mci,
                return;
 
        if ((info->errsts ^ info->errsts2) & I3200_ERRSTS_BITS) {
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
-                                    -1, -1, -1, "UE overwrote CE", "", NULL);
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
+                                    -1, -1, -1, "UE overwrote CE", "");
                info->errsts = info->errsts2;
        }
 
        for (channel = 0; channel < nr_channels; channel++) {
                log = info->eccerrlog[channel];
                if (log & I3200_ECCERRLOG_UE) {
-                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                             0, 0, 0,
                                             eccerrlog_row(channel, log),
                                             -1, -1,
-                                            "i3000 UE", "", NULL);
+                                            "i3000 UE", "");
                } else if (log & I3200_ECCERRLOG_CE) {
-                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                             0, 0, eccerrlog_syndrome(log),
                                             eccerrlog_row(channel, log),
                                             -1, -1,
-                                            "i3000 UE", "", NULL);
+                                            "i3000 UE", "");
                }
        }
 }
@@ -245,7 +245,7 @@ static void i3200_check(struct mem_ctl_info *mci)
 {
        struct i3200_error_info info;
 
-       debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+       edac_dbg(1, "MC%d\n", mci->mc_idx);
        i3200_get_and_clear_error_info(mci, &info);
        i3200_process_error_info(mci, &info);
 }
@@ -332,7 +332,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
        void __iomem *window;
        struct i3200_priv *priv;
 
-       debugf0("MC: %s()\n", __func__);
+       edac_dbg(0, "MC:\n");
 
        window = i3200_map_mchbar(pdev);
        if (!window)
@@ -352,9 +352,9 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
        if (!mci)
                return -ENOMEM;
 
-       debugf3("MC: %s(): init mci\n", __func__);
+       edac_dbg(3, "MC: init mci\n");
 
-       mci->dev = &pdev->dev;
+       mci->pdev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_DDR2;
 
        mci->edac_ctl_cap = EDAC_FLAG_SECDED;
@@ -379,7 +379,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
         */
        for (i = 0; i < mci->nr_csrows; i++) {
                unsigned long nr_pages;
-               struct csrow_info *csrow = &mci->csrows[i];
+               struct csrow_info *csrow = mci->csrows[i];
 
                nr_pages = drb_to_nr_pages(drbs, stacked,
                        i / I3200_RANKS_PER_CHANNEL,
@@ -389,7 +389,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
                        continue;
 
                for (j = 0; j < nr_channels; j++) {
-                       struct dimm_info *dimm = csrow->channels[j].dimm;
+                       struct dimm_info *dimm = csrow->channels[j]->dimm;
 
                        dimm->nr_pages = nr_pages / nr_channels;
                        dimm->grain = nr_pages << PAGE_SHIFT;
@@ -403,12 +403,12 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 
        rc = -ENODEV;
        if (edac_mc_add_mc(mci)) {
-               debugf3("MC: %s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "MC: failed edac_mc_add_mc()\n");
                goto fail;
        }
 
        /* get this far and it's successful */
-       debugf3("MC: %s(): success\n", __func__);
+       edac_dbg(3, "MC: success\n");
        return 0;
 
 fail:
@@ -424,7 +424,7 @@ static int __devinit i3200_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("MC: %s()\n", __func__);
+       edac_dbg(0, "MC:\n");
 
        if (pci_enable_device(pdev) < 0)
                return -EIO;
@@ -441,7 +441,7 @@ static void __devexit i3200_remove_one(struct pci_dev *pdev)
        struct mem_ctl_info *mci;
        struct i3200_priv *priv;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        mci = edac_mc_del_mc(&pdev->dev);
        if (!mci)
@@ -475,7 +475,7 @@ static int __init i3200_init(void)
 {
        int pci_rc;
 
-       debugf3("MC: %s()\n", __func__);
+       edac_dbg(3, "MC:\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -489,14 +489,14 @@ static int __init i3200_init(void)
                mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                PCI_DEVICE_ID_INTEL_3200_HB, NULL);
                if (!mci_pdev) {
-                       debugf0("i3200 pci_get_device fail\n");
+                       edac_dbg(0, "i3200 pci_get_device fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
 
                pci_rc = i3200_init_one(mci_pdev, i3200_pci_tbl);
                if (pci_rc < 0) {
-                       debugf0("i3200 init fail\n");
+                       edac_dbg(0, "i3200 init fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
@@ -516,7 +516,7 @@ fail0:
 
 static void __exit i3200_exit(void)
 {
-       debugf3("MC: %s()\n", __func__);
+       edac_dbg(3, "MC:\n");
 
        pci_unregister_driver(&i3200_driver);
        if (!i3200_registered) {
index 11ea835f155a840dc2ae3048ca67b904e1385801..39c63757c2a14fd7bc988c23d7ee6be2e84d0a06 100644 (file)
 #define CHANNELS_PER_BRANCH    2
 #define MAX_BRANCHES           2
 
-/* Defines to extract the vaious fields from the
+/* Defines to extract the various fields from the
  *     MTRx - Memory Technology Registers
  */
 #define MTR_DIMMS_PRESENT(mtr)         ((mtr) & (0x1 << 8))
 #define MTR_DIMM_COLS(mtr)             ((mtr) & 0x3)
 #define MTR_DIMM_COLS_ADDR_BITS(mtr)   (MTR_DIMM_COLS(mtr) + 10)
 
-#ifdef CONFIG_EDAC_DEBUG
-static char *numrow_toString[] = {
-       "8,192 - 13 rows",
-       "16,384 - 14 rows",
-       "32,768 - 15 rows",
-       "reserved"
-};
-
-static char *numcol_toString[] = {
-       "1,024 - 10 columns",
-       "2,048 - 11 columns",
-       "4,096 - 12 columns",
-       "reserved"
-};
-#endif
-
 /* enables the report of miscellaneous messages as CE errors - default off */
 static int misc_messages;
 
@@ -344,7 +328,13 @@ struct i5000_pvt {
        struct pci_dev *branch_1;       /* 22.0 */
 
        u16 tolm;               /* top of low memory */
-       u64 ambase;             /* AMB BAR */
+       union {
+               u64 ambase;             /* AMB BAR */
+               struct {
+                       u32 ambase_bottom;
+                       u32 ambase_top;
+               } u __packed;
+       };
 
        u16 mir0, mir1, mir2;
 
@@ -494,10 +484,9 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
        ras = NREC_RAS(info->nrecmemb);
        cas = NREC_CAS(info->nrecmemb);
 
-       debugf0("\t\tCSROW= %d  Channel= %d "
-               "(DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
-               rank, channel, bank,
-               rdwr ? "Write" : "Read", ras, cas);
+       edac_dbg(0, "\t\tCSROW= %d  Channel= %d (DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+                rank, channel, bank,
+                rdwr ? "Write" : "Read", ras, cas);
 
        /* Only 1 bit will be on */
        switch (allErrors) {
@@ -536,10 +525,10 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
                 bank, ras, cas, allErrors, specific);
 
        /* Call the helper to output message */
-       edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 0, 0, 0,
+       edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 1, 0, 0, 0,
                             channel >> 1, channel & 1, rank,
                             rdwr ? "Write error" : "Read error",
-                            msg, NULL);
+                            msg);
 }
 
 /*
@@ -574,7 +563,7 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
        /* ONLY ONE of the possible error bits will be set, as per the docs */
        ue_errors = allErrors & FERR_NF_UNCORRECTABLE;
        if (ue_errors) {
-               debugf0("\tUncorrected bits= 0x%x\n", ue_errors);
+               edac_dbg(0, "\tUncorrected bits= 0x%x\n", ue_errors);
 
                branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
 
@@ -590,11 +579,9 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
                ras = NREC_RAS(info->nrecmemb);
                cas = NREC_CAS(info->nrecmemb);
 
-               debugf0
-                       ("\t\tCSROW= %d  Channels= %d,%d  (Branch= %d "
-                       "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
-                       rank, channel, channel + 1, branch >> 1, bank,
-                       rdwr ? "Write" : "Read", ras, cas);
+               edac_dbg(0, "\t\tCSROW= %d  Channels= %d,%d  (Branch= %d DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+                        rank, channel, channel + 1, branch >> 1, bank,
+                        rdwr ? "Write" : "Read", ras, cas);
 
                switch (ue_errors) {
                case FERR_NF_M12ERR:
@@ -637,16 +624,16 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
                         rank, bank, ras, cas, ue_errors, specific);
 
                /* Call the helper to output message */
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
                                channel >> 1, -1, rank,
                                rdwr ? "Write error" : "Read error",
-                               msg, NULL);
+                               msg);
        }
 
        /* Check correctable errors */
        ce_errors = allErrors & FERR_NF_CORRECTABLE;
        if (ce_errors) {
-               debugf0("\tCorrected bits= 0x%x\n", ce_errors);
+               edac_dbg(0, "\tCorrected bits= 0x%x\n", ce_errors);
 
                branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
 
@@ -664,10 +651,9 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
                ras = REC_RAS(info->recmemb);
                cas = REC_CAS(info->recmemb);
 
-               debugf0("\t\tCSROW= %d Channel= %d  (Branch %d "
-                       "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
-                       rank, channel, branch >> 1, bank,
-                       rdwr ? "Write" : "Read", ras, cas);
+               edac_dbg(0, "\t\tCSROW= %d Channel= %d  (Branch %d DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+                        rank, channel, branch >> 1, bank,
+                        rdwr ? "Write" : "Read", ras, cas);
 
                switch (ce_errors) {
                case FERR_NF_M17ERR:
@@ -692,10 +678,10 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
                         specific);
 
                /* Call the helper to output message */
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0,
                                channel >> 1, channel % 2, rank,
                                rdwr ? "Write error" : "Read error",
-                               msg, NULL);
+                               msg);
        }
 
        if (!misc_messages)
@@ -738,9 +724,9 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
                         "Err=%#x (%s)", misc_errors, specific);
 
                /* Call the helper to output message */
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0,
                                branch >> 1, -1, -1,
-                               "Misc error", msg, NULL);
+                               "Misc error", msg);
        }
 }
 
@@ -779,7 +765,7 @@ static void i5000_clear_error(struct mem_ctl_info *mci)
 static void i5000_check_error(struct mem_ctl_info *mci)
 {
        struct i5000_error_info info;
-       debugf4("MC%d: %s: %s()\n", mci->mc_idx, __FILE__, __func__);
+       edac_dbg(4, "MC%d\n", mci->mc_idx);
        i5000_get_error_info(mci, &info);
        i5000_process_error_info(mci, &info, 1);
 }
@@ -850,15 +836,16 @@ static int i5000_get_devices(struct mem_ctl_info *mci, int dev_idx)
 
        pvt->fsb_error_regs = pdev;
 
-       debugf1("System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
-               pci_name(pvt->system_address),
-               pvt->system_address->vendor, pvt->system_address->device);
-       debugf1("Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
-               pci_name(pvt->branchmap_werrors),
-               pvt->branchmap_werrors->vendor, pvt->branchmap_werrors->device);
-       debugf1("FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
-               pci_name(pvt->fsb_error_regs),
-               pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device);
+       edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
+                pci_name(pvt->system_address),
+                pvt->system_address->vendor, pvt->system_address->device);
+       edac_dbg(1, "Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
+                pci_name(pvt->branchmap_werrors),
+                pvt->branchmap_werrors->vendor,
+                pvt->branchmap_werrors->device);
+       edac_dbg(1, "FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
+                pci_name(pvt->fsb_error_regs),
+                pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device);
 
        pdev = NULL;
        pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
@@ -981,16 +968,25 @@ static void decode_mtr(int slot_row, u16 mtr)
 
        ans = MTR_DIMMS_PRESENT(mtr);
 
-       debugf2("\tMTR%d=0x%x:  DIMMs are %s\n", slot_row, mtr,
-               ans ? "Present" : "NOT Present");
+       edac_dbg(2, "\tMTR%d=0x%x:  DIMMs are %sPresent\n",
+                slot_row, mtr, ans ? "" : "NOT ");
        if (!ans)
                return;
 
-       debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
-       debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
-       debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANK(mtr) ? "double" : "single");
-       debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
-       debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
+       edac_dbg(2, "\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
+       edac_dbg(2, "\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
+       edac_dbg(2, "\t\tNUMRANK: %s\n",
+                MTR_DIMM_RANK(mtr) ? "double" : "single");
+       edac_dbg(2, "\t\tNUMROW: %s\n",
+                MTR_DIMM_ROWS(mtr) == 0 ? "8,192 - 13 rows" :
+                MTR_DIMM_ROWS(mtr) == 1 ? "16,384 - 14 rows" :
+                MTR_DIMM_ROWS(mtr) == 2 ? "32,768 - 15 rows" :
+                "reserved");
+       edac_dbg(2, "\t\tNUMCOL: %s\n",
+                MTR_DIMM_COLS(mtr) == 0 ? "1,024 - 10 columns" :
+                MTR_DIMM_COLS(mtr) == 1 ? "2,048 - 11 columns" :
+                MTR_DIMM_COLS(mtr) == 2 ? "4,096 - 12 columns" :
+                "reserved");
 }
 
 static void handle_channel(struct i5000_pvt *pvt, int slot, int channel,
@@ -1061,7 +1057,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
                                "--------------------------------");
                        p += n;
                        space -= n;
-                       debugf2("%s\n", mem_buffer);
+                       edac_dbg(2, "%s\n", mem_buffer);
                        p = mem_buffer;
                        space = PAGE_SIZE;
                }
@@ -1082,7 +1078,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
                }
                p += n;
                space -= n;
-               debugf2("%s\n", mem_buffer);
+               edac_dbg(2, "%s\n", mem_buffer);
                p = mem_buffer;
                space = PAGE_SIZE;
        }
@@ -1092,7 +1088,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
                "--------------------------------");
        p += n;
        space -= n;
-       debugf2("%s\n", mem_buffer);
+       edac_dbg(2, "%s\n", mem_buffer);
        p = mem_buffer;
        space = PAGE_SIZE;
 
@@ -1105,7 +1101,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
                p += n;
                space -= n;
        }
-       debugf2("%s\n", mem_buffer);
+       edac_dbg(2, "%s\n", mem_buffer);
        p = mem_buffer;
        space = PAGE_SIZE;
 
@@ -1118,7 +1114,7 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
        }
 
        /* output the last message and free buffer */
-       debugf2("%s\n", mem_buffer);
+       edac_dbg(2, "%s\n", mem_buffer);
        kfree(mem_buffer);
 }
 
@@ -1141,24 +1137,25 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
        pvt = mci->pvt_info;
 
        pci_read_config_dword(pvt->system_address, AMBASE,
-                       (u32 *) & pvt->ambase);
+                       &pvt->u.ambase_bottom);
        pci_read_config_dword(pvt->system_address, AMBASE + sizeof(u32),
-                       ((u32 *) & pvt->ambase) + sizeof(u32));
+                       &pvt->u.ambase_top);
 
        maxdimmperch = pvt->maxdimmperch;
        maxch = pvt->maxch;
 
-       debugf2("AMBASE= 0x%lx  MAXCH= %d  MAX-DIMM-Per-CH= %d\n",
-               (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
+       edac_dbg(2, "AMBASE= 0x%lx  MAXCH= %d  MAX-DIMM-Per-CH= %d\n",
+                (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
 
        /* Get the Branch Map regs */
        pci_read_config_word(pvt->branchmap_werrors, TOLM, &pvt->tolm);
        pvt->tolm >>= 12;
-       debugf2("\nTOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
-               pvt->tolm);
+       edac_dbg(2, "TOLM (number of 256M regions) =%u (0x%x)\n",
+                pvt->tolm, pvt->tolm);
 
        actual_tolm = pvt->tolm << 28;
-       debugf2("Actual TOLM byte addr=%u (0x%x)\n", actual_tolm, actual_tolm);
+       edac_dbg(2, "Actual TOLM byte addr=%u (0x%x)\n",
+                actual_tolm, actual_tolm);
 
        pci_read_config_word(pvt->branchmap_werrors, MIR0, &pvt->mir0);
        pci_read_config_word(pvt->branchmap_werrors, MIR1, &pvt->mir1);
@@ -1168,15 +1165,18 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
        limit = (pvt->mir0 >> 4) & 0x0FFF;
        way0 = pvt->mir0 & 0x1;
        way1 = pvt->mir0 & 0x2;
-       debugf2("MIR0: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+       edac_dbg(2, "MIR0: limit= 0x%x  WAY1= %u  WAY0= %x\n",
+                limit, way1, way0);
        limit = (pvt->mir1 >> 4) & 0x0FFF;
        way0 = pvt->mir1 & 0x1;
        way1 = pvt->mir1 & 0x2;
-       debugf2("MIR1: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+       edac_dbg(2, "MIR1: limit= 0x%x  WAY1= %u  WAY0= %x\n",
+                limit, way1, way0);
        limit = (pvt->mir2 >> 4) & 0x0FFF;
        way0 = pvt->mir2 & 0x1;
        way1 = pvt->mir2 & 0x2;
-       debugf2("MIR2: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+       edac_dbg(2, "MIR2: limit= 0x%x  WAY1= %u  WAY0= %x\n",
+                limit, way1, way0);
 
        /* Get the MTR[0-3] regs */
        for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
@@ -1185,31 +1185,31 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
                pci_read_config_word(pvt->branch_0, where,
                                &pvt->b0_mtr[slot_row]);
 
-               debugf2("MTR%d where=0x%x B0 value=0x%x\n", slot_row, where,
-                       pvt->b0_mtr[slot_row]);
+               edac_dbg(2, "MTR%d where=0x%x B0 value=0x%x\n",
+                        slot_row, where, pvt->b0_mtr[slot_row]);
 
                if (pvt->maxch >= CHANNELS_PER_BRANCH) {
                        pci_read_config_word(pvt->branch_1, where,
                                        &pvt->b1_mtr[slot_row]);
-                       debugf2("MTR%d where=0x%x B1 value=0x%x\n", slot_row,
-                               where, pvt->b1_mtr[slot_row]);
+                       edac_dbg(2, "MTR%d where=0x%x B1 value=0x%x\n",
+                                slot_row, where, pvt->b1_mtr[slot_row]);
                } else {
                        pvt->b1_mtr[slot_row] = 0;
                }
        }
 
        /* Read and dump branch 0's MTRs */
-       debugf2("\nMemory Technology Registers:\n");
-       debugf2("   Branch 0:\n");
+       edac_dbg(2, "Memory Technology Registers:\n");
+       edac_dbg(2, "   Branch 0:\n");
        for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
                decode_mtr(slot_row, pvt->b0_mtr[slot_row]);
        }
        pci_read_config_word(pvt->branch_0, AMB_PRESENT_0,
                        &pvt->b0_ambpresent0);
-       debugf2("\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0);
+       edac_dbg(2, "\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0);
        pci_read_config_word(pvt->branch_0, AMB_PRESENT_1,
                        &pvt->b0_ambpresent1);
-       debugf2("\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1);
+       edac_dbg(2, "\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1);
 
        /* Only if we have 2 branchs (4 channels) */
        if (pvt->maxch < CHANNELS_PER_BRANCH) {
@@ -1217,18 +1217,18 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
                pvt->b1_ambpresent1 = 0;
        } else {
                /* Read and dump  branch 1's MTRs */
-               debugf2("   Branch 1:\n");
+               edac_dbg(2, "   Branch 1:\n");
                for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
                        decode_mtr(slot_row, pvt->b1_mtr[slot_row]);
                }
                pci_read_config_word(pvt->branch_1, AMB_PRESENT_0,
                                &pvt->b1_ambpresent0);
-               debugf2("\t\tAMB-Branch 1-present0 0x%x:\n",
-                       pvt->b1_ambpresent0);
+               edac_dbg(2, "\t\tAMB-Branch 1-present0 0x%x:\n",
+                        pvt->b1_ambpresent0);
                pci_read_config_word(pvt->branch_1, AMB_PRESENT_1,
                                &pvt->b1_ambpresent1);
-               debugf2("\t\tAMB-Branch 1-present1 0x%x:\n",
-                       pvt->b1_ambpresent1);
+               edac_dbg(2, "\t\tAMB-Branch 1-present1 0x%x:\n",
+                        pvt->b1_ambpresent1);
        }
 
        /* Go and determine the size of each DIMM and place in an
@@ -1363,10 +1363,9 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
        int num_channels;
        int num_dimms_per_channel;
 
-       debugf0("MC: %s: %s(), pdev bus %u dev=0x%x fn=0x%x\n",
-               __FILE__, __func__,
-               pdev->bus->number,
-               PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+       edac_dbg(0, "MC: pdev bus %u dev=0x%x fn=0x%x\n",
+                pdev->bus->number,
+                PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
        /* We only are looking for func 0 of the set */
        if (PCI_FUNC(pdev->devfn) != 0)
@@ -1388,8 +1387,8 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
        i5000_get_dimm_and_channel_counts(pdev, &num_dimms_per_channel,
                                        &num_channels);
 
-       debugf0("MC: %s(): Number of Branches=2 Channels= %d  DIMMS= %d\n",
-               __func__, num_channels, num_dimms_per_channel);
+       edac_dbg(0, "MC: Number of Branches=2 Channels= %d  DIMMS= %d\n",
+                num_channels, num_dimms_per_channel);
 
        /* allocate a new MC control structure */
 
@@ -1406,10 +1405,9 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
        if (mci == NULL)
                return -ENOMEM;
 
-       kobject_get(&mci->edac_mci_kobj);
-       debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
+       edac_dbg(0, "MC: mci = %p\n", mci);
 
-       mci->dev = &pdev->dev;  /* record ptr  to the generic device */
+       mci->pdev = &pdev->dev; /* record ptr  to the generic device */
 
        pvt = mci->pvt_info;
        pvt->system_address = pdev;     /* Record this device in our private */
@@ -1439,19 +1437,16 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
        /* initialize the MC control structure 'csrows' table
         * with the mapping and control information */
        if (i5000_init_csrows(mci)) {
-               debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
-                       "    because i5000_init_csrows() returned nonzero "
-                       "value\n");
+               edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i5000_init_csrows() returned nonzero value\n");
                mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */
        } else {
-               debugf1("MC: Enable error reporting now\n");
+               edac_dbg(1, "MC: Enable error reporting now\n");
                i5000_enable_error_reporting(mci);
        }
 
        /* add this new MC control structure to EDAC's list of MCs */
        if (edac_mc_add_mc(mci)) {
-               debugf0("MC: %s: %s(): failed edac_mc_add_mc()\n",
-                       __FILE__, __func__);
+               edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
                /* FIXME: perhaps some code should go here that disables error
                 * reporting if we just enabled it
                 */
@@ -1479,7 +1474,6 @@ fail1:
        i5000_put_devices(mci);
 
 fail0:
-       kobject_put(&mci->edac_mci_kobj);
        edac_mc_free(mci);
        return -ENODEV;
 }
@@ -1496,7 +1490,7 @@ static int __devinit i5000_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("MC: %s: %s()\n", __FILE__, __func__);
+       edac_dbg(0, "MC:\n");
 
        /* wake up device */
        rc = pci_enable_device(pdev);
@@ -1515,7 +1509,7 @@ static void __devexit i5000_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0("%s: %s()\n", __FILE__, __func__);
+       edac_dbg(0, "\n");
 
        if (i5000_pci)
                edac_pci_release_generic_ctl(i5000_pci);
@@ -1525,7 +1519,6 @@ static void __devexit i5000_remove_one(struct pci_dev *pdev)
 
        /* retrieve references to resources, and free those resources */
        i5000_put_devices(mci);
-       kobject_put(&mci->edac_mci_kobj);
        edac_mc_free(mci);
 }
 
@@ -1562,7 +1555,7 @@ static int __init i5000_init(void)
 {
        int pci_rc;
 
-       debugf2("MC: %s: %s()\n", __FILE__, __func__);
+       edac_dbg(2, "MC:\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -1578,7 +1571,7 @@ static int __init i5000_init(void)
  */
 static void __exit i5000_exit(void)
 {
-       debugf2("MC: %s: %s()\n", __FILE__, __func__);
+       edac_dbg(2, "MC:\n");
        pci_unregister_driver(&i5000_driver);
 }
 
index e9e7c2a29dc389d9462f50e5b1d17367b9a7d194..c4b5e5f868e85ea1e60b0a301d0a7bdc68585a2e 100644 (file)
@@ -431,10 +431,10 @@ static void i5100_handle_ce(struct mem_ctl_info *mci,
                 "bank %u, cas %u, ras %u\n",
                 bank, cas, ras);
 
-       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                             0, 0, syndrome,
                             chan, rank, -1,
-                            msg, detail, NULL);
+                            msg, detail);
 }
 
 static void i5100_handle_ue(struct mem_ctl_info *mci,
@@ -453,10 +453,10 @@ static void i5100_handle_ue(struct mem_ctl_info *mci,
                 "bank %u, cas %u, ras %u\n",
                 bank, cas, ras);
 
-       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                             0, 0, syndrome,
                             chan, rank, -1,
-                            msg, detail, NULL);
+                            msg, detail);
 }
 
 static void i5100_read_log(struct mem_ctl_info *mci, int chan,
@@ -859,8 +859,8 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
                                i5100_rank_to_slot(mci, chan, rank));
                }
 
-               debugf2("dimm channel %d, rank %d, size %ld\n",
-                       chan, rank, (long)PAGES_TO_MiB(npages));
+               edac_dbg(2, "dimm channel %d, rank %d, size %ld\n",
+                        chan, rank, (long)PAGES_TO_MiB(npages));
        }
 }
 
@@ -943,7 +943,7 @@ static int __devinit i5100_init_one(struct pci_dev *pdev,
                goto bail_disable_ch1;
        }
 
-       mci->dev = &pdev->dev;
+       mci->pdev = &pdev->dev;
 
        priv = mci->pvt_info;
        priv->ranksperchan = ranksperch;
index 6640c29e1885a814d8f7e69318541d1afd666037..277246998b805024517f0641841996e8bfd85d29 100644 (file)
@@ -300,24 +300,6 @@ static inline int extract_fbdchan_indx(u32 x)
        return (x>>28) & 0x3;
 }
 
-#ifdef CONFIG_EDAC_DEBUG
-/* MTR NUMROW */
-static const char *numrow_toString[] = {
-       "8,192 - 13 rows",
-       "16,384 - 14 rows",
-       "32,768 - 15 rows",
-       "65,536 - 16 rows"
-};
-
-/* MTR NUMCOL */
-static const char *numcol_toString[] = {
-       "1,024 - 10 columns",
-       "2,048 - 11 columns",
-       "4,096 - 12 columns",
-       "reserved"
-};
-#endif
-
 /* Device name and register DID (Device ID) */
 struct i5400_dev_info {
        const char *ctl_name;   /* name for this device */
@@ -345,7 +327,13 @@ struct i5400_pvt {
        struct pci_dev *branch_1;               /* 22.0 */
 
        u16 tolm;                               /* top of low memory */
-       u64 ambase;                             /* AMB BAR */
+       union {
+               u64 ambase;                             /* AMB BAR */
+               struct {
+                       u32 ambase_bottom;
+                       u32 ambase_top;
+               } u __packed;
+       };
 
        u16 mir0, mir1;
 
@@ -560,10 +548,9 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
        ras = nrec_ras(info);
        cas = nrec_cas(info);
 
-       debugf0("\t\tDIMM= %d  Channels= %d,%d  (Branch= %d "
-               "DRAM Bank= %d Buffer ID = %d rdwr= %s ras= %d cas= %d)\n",
-               rank, channel, channel + 1, branch >> 1, bank,
-               buf_id, rdwr_str(rdwr), ras, cas);
+       edac_dbg(0, "\t\tDIMM= %d  Channels= %d,%d  (Branch= %d DRAM Bank= %d Buffer ID = %d rdwr= %s ras= %d cas= %d)\n",
+                rank, channel, channel + 1, branch >> 1, bank,
+                buf_id, rdwr_str(rdwr), ras, cas);
 
        /* Only 1 bit will be on */
        errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name));
@@ -573,10 +560,10 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
                 "Bank=%d Buffer ID = %d RAS=%d CAS=%d Err=0x%lx (%s)",
                 bank, buf_id, ras, cas, allErrors, error_name[errnum]);
 
-       edac_mc_handle_error(tp_event, mci, 0, 0, 0,
+       edac_mc_handle_error(tp_event, mci, 1, 0, 0, 0,
                             branch >> 1, -1, rank,
                             rdwr ? "Write error" : "Read error",
-                            msg, NULL);
+                            msg);
 }
 
 /*
@@ -613,7 +600,7 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci,
 
        /* Correctable errors */
        if (allErrors & ERROR_NF_CORRECTABLE) {
-               debugf0("\tCorrected bits= 0x%lx\n", allErrors);
+               edac_dbg(0, "\tCorrected bits= 0x%lx\n", allErrors);
 
                branch = extract_fbdchan_indx(info->ferr_nf_fbd);
 
@@ -634,10 +621,9 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci,
                /* Only 1 bit will be on */
                errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name));
 
-               debugf0("\t\tDIMM= %d Channel= %d  (Branch %d "
-                       "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
-                       rank, channel, branch >> 1, bank,
-                       rdwr_str(rdwr), ras, cas);
+               edac_dbg(0, "\t\tDIMM= %d Channel= %d  (Branch %d DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+                        rank, channel, branch >> 1, bank,
+                        rdwr_str(rdwr), ras, cas);
 
                /* Form out message */
                snprintf(msg, sizeof(msg),
@@ -646,10 +632,10 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci,
                         branch >> 1, bank, rdwr_str(rdwr), ras, cas,
                         allErrors, error_name[errnum]);
 
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 0,
                                     branch >> 1, channel % 2, rank,
                                     rdwr ? "Write error" : "Read error",
-                                    msg, NULL);
+                                    msg);
 
                return;
        }
@@ -700,7 +686,7 @@ static void i5400_clear_error(struct mem_ctl_info *mci)
 static void i5400_check_error(struct mem_ctl_info *mci)
 {
        struct i5400_error_info info;
-       debugf4("MC%d: %s: %s()\n", mci->mc_idx, __FILE__, __func__);
+       edac_dbg(4, "MC%d\n", mci->mc_idx);
        i5400_get_error_info(mci, &info);
        i5400_process_error_info(mci, &info);
 }
@@ -786,15 +772,16 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
        }
        pvt->fsb_error_regs = pdev;
 
-       debugf1("System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
-               pci_name(pvt->system_address),
-               pvt->system_address->vendor, pvt->system_address->device);
-       debugf1("Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
-               pci_name(pvt->branchmap_werrors),
-               pvt->branchmap_werrors->vendor, pvt->branchmap_werrors->device);
-       debugf1("FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
-               pci_name(pvt->fsb_error_regs),
-               pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device);
+       edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
+                pci_name(pvt->system_address),
+                pvt->system_address->vendor, pvt->system_address->device);
+       edac_dbg(1, "Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
+                pci_name(pvt->branchmap_werrors),
+                pvt->branchmap_werrors->vendor,
+                pvt->branchmap_werrors->device);
+       edac_dbg(1, "FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
+                pci_name(pvt->fsb_error_regs),
+                pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device);
 
        pvt->branch_0 = pci_get_device(PCI_VENDOR_ID_INTEL,
                                       PCI_DEVICE_ID_INTEL_5400_FBD0, NULL);
@@ -882,8 +869,8 @@ static int determine_mtr(struct i5400_pvt *pvt, int dimm, int channel)
        n = dimm;
 
        if (n >= DIMMS_PER_CHANNEL) {
-               debugf0("ERROR: trying to access an invalid dimm: %d\n",
-                       dimm);
+               edac_dbg(0, "ERROR: trying to access an invalid dimm: %d\n",
+                        dimm);
                return 0;
        }
 
@@ -903,20 +890,29 @@ static void decode_mtr(int slot_row, u16 mtr)
 
        ans = MTR_DIMMS_PRESENT(mtr);
 
-       debugf2("\tMTR%d=0x%x:  DIMMs are %s\n", slot_row, mtr,
-               ans ? "Present" : "NOT Present");
+       edac_dbg(2, "\tMTR%d=0x%x:  DIMMs are %sPresent\n",
+                slot_row, mtr, ans ? "" : "NOT ");
        if (!ans)
                return;
 
-       debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
-
-       debugf2("\t\tELECTRICAL THROTTLING is %s\n",
-               MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled");
-
-       debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
-       debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANK(mtr) ? "double" : "single");
-       debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
-       debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
+       edac_dbg(2, "\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
+
+       edac_dbg(2, "\t\tELECTRICAL THROTTLING is %s\n",
+                MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled");
+
+       edac_dbg(2, "\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
+       edac_dbg(2, "\t\tNUMRANK: %s\n",
+                MTR_DIMM_RANK(mtr) ? "double" : "single");
+       edac_dbg(2, "\t\tNUMROW: %s\n",
+                MTR_DIMM_ROWS(mtr) == 0 ? "8,192 - 13 rows" :
+                MTR_DIMM_ROWS(mtr) == 1 ? "16,384 - 14 rows" :
+                MTR_DIMM_ROWS(mtr) == 2 ? "32,768 - 15 rows" :
+                "65,536 - 16 rows");
+       edac_dbg(2, "\t\tNUMCOL: %s\n",
+                MTR_DIMM_COLS(mtr) == 0 ? "1,024 - 10 columns" :
+                MTR_DIMM_COLS(mtr) == 1 ? "2,048 - 11 columns" :
+                MTR_DIMM_COLS(mtr) == 2 ? "4,096 - 12 columns" :
+                "reserved");
 }
 
 static void handle_channel(struct i5400_pvt *pvt, int dimm, int channel,
@@ -989,7 +985,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
                                        "-------------------------------");
                        p += n;
                        space -= n;
-                       debugf2("%s\n", mem_buffer);
+                       edac_dbg(2, "%s\n", mem_buffer);
                        p = mem_buffer;
                        space = PAGE_SIZE;
                }
@@ -1004,7 +1000,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
                        p += n;
                        space -= n;
                }
-               debugf2("%s\n", mem_buffer);
+               edac_dbg(2, "%s\n", mem_buffer);
                p = mem_buffer;
                space = PAGE_SIZE;
        }
@@ -1014,7 +1010,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
                        "-------------------------------");
        p += n;
        space -= n;
-       debugf2("%s\n", mem_buffer);
+       edac_dbg(2, "%s\n", mem_buffer);
        p = mem_buffer;
        space = PAGE_SIZE;
 
@@ -1029,7 +1025,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
        }
 
        space -= n;
-       debugf2("%s\n", mem_buffer);
+       edac_dbg(2, "%s\n", mem_buffer);
        p = mem_buffer;
        space = PAGE_SIZE;
 
@@ -1042,7 +1038,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
        }
 
        /* output the last message and free buffer */
-       debugf2("%s\n", mem_buffer);
+       edac_dbg(2, "%s\n", mem_buffer);
        kfree(mem_buffer);
 }
 
@@ -1065,25 +1061,25 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
        pvt = mci->pvt_info;
 
        pci_read_config_dword(pvt->system_address, AMBASE,
-                       (u32 *) &pvt->ambase);
+                       &pvt->u.ambase_bottom);
        pci_read_config_dword(pvt->system_address, AMBASE + sizeof(u32),
-                       ((u32 *) &pvt->ambase) + sizeof(u32));
+                       &pvt->u.ambase_top);
 
        maxdimmperch = pvt->maxdimmperch;
        maxch = pvt->maxch;
 
-       debugf2("AMBASE= 0x%lx  MAXCH= %d  MAX-DIMM-Per-CH= %d\n",
-               (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
+       edac_dbg(2, "AMBASE= 0x%lx  MAXCH= %d  MAX-DIMM-Per-CH= %d\n",
+                (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
 
        /* Get the Branch Map regs */
        pci_read_config_word(pvt->branchmap_werrors, TOLM, &pvt->tolm);
        pvt->tolm >>= 12;
-       debugf2("\nTOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
-               pvt->tolm);
+       edac_dbg(2, "\nTOLM (number of 256M regions) =%u (0x%x)\n",
+                pvt->tolm, pvt->tolm);
 
        actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28));
-       debugf2("Actual TOLM byte addr=%u.%03u GB (0x%x)\n",
-               actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28);
+       edac_dbg(2, "Actual TOLM byte addr=%u.%03u GB (0x%x)\n",
+                actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28);
 
        pci_read_config_word(pvt->branchmap_werrors, MIR0, &pvt->mir0);
        pci_read_config_word(pvt->branchmap_werrors, MIR1, &pvt->mir1);
@@ -1092,11 +1088,13 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
        limit = (pvt->mir0 >> 4) & 0x0fff;
        way0 = pvt->mir0 & 0x1;
        way1 = pvt->mir0 & 0x2;
-       debugf2("MIR0: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+       edac_dbg(2, "MIR0: limit= 0x%x  WAY1= %u  WAY0= %x\n",
+                limit, way1, way0);
        limit = (pvt->mir1 >> 4) & 0xfff;
        way0 = pvt->mir1 & 0x1;
        way1 = pvt->mir1 & 0x2;
-       debugf2("MIR1: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+       edac_dbg(2, "MIR1: limit= 0x%x  WAY1= %u  WAY0= %x\n",
+                limit, way1, way0);
 
        /* Get the set of MTR[0-3] regs by each branch */
        for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++) {
@@ -1106,8 +1104,8 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
                pci_read_config_word(pvt->branch_0, where,
                                &pvt->b0_mtr[slot_row]);
 
-               debugf2("MTR%d where=0x%x B0 value=0x%x\n", slot_row, where,
-                       pvt->b0_mtr[slot_row]);
+               edac_dbg(2, "MTR%d where=0x%x B0 value=0x%x\n",
+                        slot_row, where, pvt->b0_mtr[slot_row]);
 
                if (pvt->maxch < CHANNELS_PER_BRANCH) {
                        pvt->b1_mtr[slot_row] = 0;
@@ -1117,22 +1115,22 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
                /* Branch 1 set of MTR registers */
                pci_read_config_word(pvt->branch_1, where,
                                &pvt->b1_mtr[slot_row]);
-               debugf2("MTR%d where=0x%x B1 value=0x%x\n", slot_row, where,
-                       pvt->b1_mtr[slot_row]);
+               edac_dbg(2, "MTR%d where=0x%x B1 value=0x%x\n",
+                        slot_row, where, pvt->b1_mtr[slot_row]);
        }
 
        /* Read and dump branch 0's MTRs */
-       debugf2("\nMemory Technology Registers:\n");
-       debugf2("   Branch 0:\n");
+       edac_dbg(2, "Memory Technology Registers:\n");
+       edac_dbg(2, "   Branch 0:\n");
        for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++)
                decode_mtr(slot_row, pvt->b0_mtr[slot_row]);
 
        pci_read_config_word(pvt->branch_0, AMBPRESENT_0,
                        &pvt->b0_ambpresent0);
-       debugf2("\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0);
+       edac_dbg(2, "\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0);
        pci_read_config_word(pvt->branch_0, AMBPRESENT_1,
                        &pvt->b0_ambpresent1);
-       debugf2("\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1);
+       edac_dbg(2, "\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1);
 
        /* Only if we have 2 branchs (4 channels) */
        if (pvt->maxch < CHANNELS_PER_BRANCH) {
@@ -1140,18 +1138,18 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
                pvt->b1_ambpresent1 = 0;
        } else {
                /* Read and dump  branch 1's MTRs */
-               debugf2("   Branch 1:\n");
+               edac_dbg(2, "   Branch 1:\n");
                for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++)
                        decode_mtr(slot_row, pvt->b1_mtr[slot_row]);
 
                pci_read_config_word(pvt->branch_1, AMBPRESENT_0,
                                &pvt->b1_ambpresent0);
-               debugf2("\t\tAMB-Branch 1-present0 0x%x:\n",
-                       pvt->b1_ambpresent0);
+               edac_dbg(2, "\t\tAMB-Branch 1-present0 0x%x:\n",
+                        pvt->b1_ambpresent0);
                pci_read_config_word(pvt->branch_1, AMBPRESENT_1,
                                &pvt->b1_ambpresent1);
-               debugf2("\t\tAMB-Branch 1-present1 0x%x:\n",
-                       pvt->b1_ambpresent1);
+               edac_dbg(2, "\t\tAMB-Branch 1-present1 0x%x:\n",
+                        pvt->b1_ambpresent1);
        }
 
        /* Go and determine the size of each DIMM and place in an
@@ -1203,10 +1201,9 @@ static int i5400_init_dimms(struct mem_ctl_info *mci)
 
                        size_mb =  pvt->dimm_info[slot][channel].megabytes;
 
-                       debugf2("%s: dimm%zd (branch %d channel %d slot %d): %d.%03d GB\n",
-                               __func__, dimm - mci->dimms,
-                               channel / 2, channel % 2, slot,
-                               size_mb / 1000, size_mb % 1000);
+                       edac_dbg(2, "dimm (branch %d channel %d slot %d): %d.%03d GB\n",
+                                channel / 2, channel % 2, slot,
+                                size_mb / 1000, size_mb % 1000);
 
                        dimm->nr_pages = size_mb << 8;
                        dimm->grain = 8;
@@ -1227,7 +1224,7 @@ static int i5400_init_dimms(struct mem_ctl_info *mci)
         * With such single-DIMM mode, the SDCC algorithm degrades to SECDEC+.
         */
        if (ndimms == 1)
-               mci->dimms[0].edac_mode = EDAC_SECDED;
+               mci->dimms[0]->edac_mode = EDAC_SECDED;
 
        return (ndimms == 0);
 }
@@ -1270,10 +1267,9 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
        if (dev_idx >= ARRAY_SIZE(i5400_devs))
                return -EINVAL;
 
-       debugf0("MC: %s: %s(), pdev bus %u dev=0x%x fn=0x%x\n",
-               __FILE__, __func__,
-               pdev->bus->number,
-               PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+       edac_dbg(0, "MC: pdev bus %u dev=0x%x fn=0x%x\n",
+                pdev->bus->number,
+                PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
        /* We only are looking for func 0 of the set */
        if (PCI_FUNC(pdev->devfn) != 0)
@@ -1297,9 +1293,9 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
        if (mci == NULL)
                return -ENOMEM;
 
-       debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
+       edac_dbg(0, "MC: mci = %p\n", mci);
 
-       mci->dev = &pdev->dev;  /* record ptr  to the generic device */
+       mci->pdev = &pdev->dev; /* record ptr  to the generic device */
 
        pvt = mci->pvt_info;
        pvt->system_address = pdev;     /* Record this device in our private */
@@ -1329,19 +1325,16 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
        /* initialize the MC control structure 'dimms' table
         * with the mapping and control information */
        if (i5400_init_dimms(mci)) {
-               debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
-                       "    because i5400_init_dimms() returned nonzero "
-                       "value\n");
+               edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i5400_init_dimms() returned nonzero value\n");
                mci->edac_cap = EDAC_FLAG_NONE; /* no dimms found */
        } else {
-               debugf1("MC: Enable error reporting now\n");
+               edac_dbg(1, "MC: Enable error reporting now\n");
                i5400_enable_error_reporting(mci);
        }
 
        /* add this new MC control structure to EDAC's list of MCs */
        if (edac_mc_add_mc(mci)) {
-               debugf0("MC: %s: %s(): failed edac_mc_add_mc()\n",
-                       __FILE__, __func__);
+               edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
                /* FIXME: perhaps some code should go here that disables error
                 * reporting if we just enabled it
                 */
@@ -1385,7 +1378,7 @@ static int __devinit i5400_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("MC: %s: %s()\n", __FILE__, __func__);
+       edac_dbg(0, "MC:\n");
 
        /* wake up device */
        rc = pci_enable_device(pdev);
@@ -1404,7 +1397,7 @@ static void __devexit i5400_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0("%s: %s()\n", __FILE__, __func__);
+       edac_dbg(0, "\n");
 
        if (i5400_pci)
                edac_pci_release_generic_ctl(i5400_pci);
@@ -1450,7 +1443,7 @@ static int __init i5400_init(void)
 {
        int pci_rc;
 
-       debugf2("MC: %s: %s()\n", __FILE__, __func__);
+       edac_dbg(2, "MC:\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -1466,7 +1459,7 @@ static int __init i5400_init(void)
  */
 static void __exit i5400_exit(void)
 {
-       debugf2("MC: %s: %s()\n", __FILE__, __func__);
+       edac_dbg(2, "MC:\n");
        pci_unregister_driver(&i5400_driver);
 }
 
index 97c22fd650eec1953dfba7b3c773c1ddf082d700..a09d0667f72acb4aca4dda012b0d172a927182eb 100644 (file)
@@ -182,24 +182,6 @@ static const u16 mtr_regs[MAX_SLOTS] = {
 #define MTR_DIMM_COLS(mtr)             ((mtr) & 0x3)
 #define MTR_DIMM_COLS_ADDR_BITS(mtr)   (MTR_DIMM_COLS(mtr) + 10)
 
-#ifdef CONFIG_EDAC_DEBUG
-/* MTR NUMROW */
-static const char *numrow_toString[] = {
-       "8,192 - 13 rows",
-       "16,384 - 14 rows",
-       "32,768 - 15 rows",
-       "65,536 - 16 rows"
-};
-
-/* MTR NUMCOL */
-static const char *numcol_toString[] = {
-       "1,024 - 10 columns",
-       "2,048 - 11 columns",
-       "4,096 - 12 columns",
-       "reserved"
-};
-#endif
-
 /************************************************
  * i7300 Register definitions for error detection
  ************************************************/
@@ -467,10 +449,10 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
                         "Bank=%d RAS=%d CAS=%d Err=0x%lx (%s))",
                         bank, ras, cas, errors, specific);
 
-               edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 0, 0, 0,
+               edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 1, 0, 0, 0,
                                     branch, -1, rank,
                                     is_wr ? "Write error" : "Read error",
-                                    pvt->tmp_prt_buffer, NULL);
+                                    pvt->tmp_prt_buffer);
 
        }
 
@@ -513,11 +495,11 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
                         "DRAM-Bank=%d RAS=%d CAS=%d, Err=0x%lx (%s))",
                         bank, ras, cas, errors, specific);
 
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0,
                                     syndrome,
                                     branch >> 1, channel % 2, rank,
                                     is_wr ? "Write error" : "Read error",
-                                    pvt->tmp_prt_buffer, NULL);
+                                    pvt->tmp_prt_buffer);
        }
        return;
 }
@@ -614,9 +596,8 @@ static int decode_mtr(struct i7300_pvt *pvt,
        mtr = pvt->mtr[slot][branch];
        ans = MTR_DIMMS_PRESENT(mtr) ? 1 : 0;
 
-       debugf2("\tMTR%d CH%d: DIMMs are %s (mtr)\n",
-               slot, channel,
-               ans ? "Present" : "NOT Present");
+       edac_dbg(2, "\tMTR%d CH%d: DIMMs are %sPresent (mtr)\n",
+                slot, channel, ans ? "" : "NOT ");
 
        /* Determine if there is a DIMM present in this DIMM slot */
        if (!ans)
@@ -638,16 +619,25 @@ static int decode_mtr(struct i7300_pvt *pvt,
 
        dinfo->megabytes = 1 << addrBits;
 
-       debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
-
-       debugf2("\t\tELECTRICAL THROTTLING is %s\n",
-               MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled");
-
-       debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
-       debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANKS(mtr) ? "double" : "single");
-       debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
-       debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
-       debugf2("\t\tSIZE: %d MB\n", dinfo->megabytes);
+       edac_dbg(2, "\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
+
+       edac_dbg(2, "\t\tELECTRICAL THROTTLING is %s\n",
+                MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled");
+
+       edac_dbg(2, "\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
+       edac_dbg(2, "\t\tNUMRANK: %s\n",
+                MTR_DIMM_RANKS(mtr) ? "double" : "single");
+       edac_dbg(2, "\t\tNUMROW: %s\n",
+                MTR_DIMM_ROWS(mtr) == 0 ? "8,192 - 13 rows" :
+                MTR_DIMM_ROWS(mtr) == 1 ? "16,384 - 14 rows" :
+                MTR_DIMM_ROWS(mtr) == 2 ? "32,768 - 15 rows" :
+                "65,536 - 16 rows");
+       edac_dbg(2, "\t\tNUMCOL: %s\n",
+                MTR_DIMM_COLS(mtr) == 0 ? "1,024 - 10 columns" :
+                MTR_DIMM_COLS(mtr) == 1 ? "2,048 - 11 columns" :
+                MTR_DIMM_COLS(mtr) == 2 ? "4,096 - 12 columns" :
+                "reserved");
+       edac_dbg(2, "\t\tSIZE: %d MB\n", dinfo->megabytes);
 
        /*
         * The type of error detection actually depends of the
@@ -663,9 +653,9 @@ static int decode_mtr(struct i7300_pvt *pvt,
        dimm->mtype = MEM_FB_DDR2;
        if (IS_SINGLE_MODE(pvt->mc_settings_a)) {
                dimm->edac_mode = EDAC_SECDED;
-               debugf2("\t\tECC code is 8-byte-over-32-byte SECDED+ code\n");
+               edac_dbg(2, "\t\tECC code is 8-byte-over-32-byte SECDED+ code\n");
        } else {
-               debugf2("\t\tECC code is on Lockstep mode\n");
+               edac_dbg(2, "\t\tECC code is on Lockstep mode\n");
                if (MTR_DRAM_WIDTH(mtr) == 8)
                        dimm->edac_mode = EDAC_S8ECD8ED;
                else
@@ -674,9 +664,9 @@ static int decode_mtr(struct i7300_pvt *pvt,
 
        /* ask what device type on this row */
        if (MTR_DRAM_WIDTH(mtr) == 8) {
-               debugf2("\t\tScrub algorithm for x8 is on %s mode\n",
-                       IS_SCRBALGO_ENHANCED(pvt->mc_settings) ?
-                                           "enhanced" : "normal");
+               edac_dbg(2, "\t\tScrub algorithm for x8 is on %s mode\n",
+                        IS_SCRBALGO_ENHANCED(pvt->mc_settings) ?
+                        "enhanced" : "normal");
 
                dimm->dtype = DEV_X8;
        } else
@@ -710,14 +700,14 @@ static void print_dimm_size(struct i7300_pvt *pvt)
                p += n;
                space -= n;
        }
-       debugf2("%s\n", pvt->tmp_prt_buffer);
+       edac_dbg(2, "%s\n", pvt->tmp_prt_buffer);
        p = pvt->tmp_prt_buffer;
        space = PAGE_SIZE;
        n = snprintf(p, space, "-------------------------------"
                               "------------------------------");
        p += n;
        space -= n;
-       debugf2("%s\n", pvt->tmp_prt_buffer);
+       edac_dbg(2, "%s\n", pvt->tmp_prt_buffer);
        p = pvt->tmp_prt_buffer;
        space = PAGE_SIZE;
 
@@ -733,7 +723,7 @@ static void print_dimm_size(struct i7300_pvt *pvt)
                        space -= n;
                }
 
-               debugf2("%s\n", pvt->tmp_prt_buffer);
+               edac_dbg(2, "%s\n", pvt->tmp_prt_buffer);
                p = pvt->tmp_prt_buffer;
                space = PAGE_SIZE;
        }
@@ -742,7 +732,7 @@ static void print_dimm_size(struct i7300_pvt *pvt)
                               "------------------------------");
        p += n;
        space -= n;
-       debugf2("%s\n", pvt->tmp_prt_buffer);
+       edac_dbg(2, "%s\n", pvt->tmp_prt_buffer);
        p = pvt->tmp_prt_buffer;
        space = PAGE_SIZE;
 #endif
@@ -765,7 +755,7 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
 
        pvt = mci->pvt_info;
 
-       debugf2("Memory Technology Registers:\n");
+       edac_dbg(2, "Memory Technology Registers:\n");
 
        /* Get the AMB present registers for the four channels */
        for (branch = 0; branch < MAX_BRANCHES; branch++) {
@@ -774,15 +764,15 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
                pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
                                     AMBPRESENT_0,
                                &pvt->ambpresent[channel]);
-               debugf2("\t\tAMB-present CH%d = 0x%x:\n",
-                       channel, pvt->ambpresent[channel]);
+               edac_dbg(2, "\t\tAMB-present CH%d = 0x%x:\n",
+                        channel, pvt->ambpresent[channel]);
 
                channel = to_channel(1, branch);
                pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
                                     AMBPRESENT_1,
                                &pvt->ambpresent[channel]);
-               debugf2("\t\tAMB-present CH%d = 0x%x:\n",
-                       channel, pvt->ambpresent[channel]);
+               edac_dbg(2, "\t\tAMB-present CH%d = 0x%x:\n",
+                        channel, pvt->ambpresent[channel]);
        }
 
        /* Get the set of MTR[0-7] regs by each branch */
@@ -824,12 +814,11 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
 static void decode_mir(int mir_no, u16 mir[MAX_MIR])
 {
        if (mir[mir_no] & 3)
-               debugf2("MIR%d: limit= 0x%x Branch(es) that participate:"
-                       " %s %s\n",
-                       mir_no,
-                       (mir[mir_no] >> 4) & 0xfff,
-                       (mir[mir_no] & 1) ? "B0" : "",
-                       (mir[mir_no] & 2) ? "B1" : "");
+               edac_dbg(2, "MIR%d: limit= 0x%x Branch(es) that participate: %s %s\n",
+                        mir_no,
+                        (mir[mir_no] >> 4) & 0xfff,
+                        (mir[mir_no] & 1) ? "B0" : "",
+                        (mir[mir_no] & 2) ? "B1" : "");
 }
 
 /**
@@ -849,17 +838,17 @@ static int i7300_get_mc_regs(struct mem_ctl_info *mci)
        pci_read_config_dword(pvt->pci_dev_16_0_fsb_ctlr, AMBASE,
                        (u32 *) &pvt->ambase);
 
-       debugf2("AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase);
+       edac_dbg(2, "AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase);
 
        /* Get the Branch Map regs */
        pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, TOLM, &pvt->tolm);
        pvt->tolm >>= 12;
-       debugf2("TOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
-               pvt->tolm);
+       edac_dbg(2, "TOLM (number of 256M regions) =%u (0x%x)\n",
+                pvt->tolm, pvt->tolm);
 
        actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28));
-       debugf2("Actual TOLM byte addr=%u.%03u GB (0x%x)\n",
-               actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28);
+       edac_dbg(2, "Actual TOLM byte addr=%u.%03u GB (0x%x)\n",
+                actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28);
 
        /* Get memory controller settings */
        pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS,
@@ -868,15 +857,15 @@ static int i7300_get_mc_regs(struct mem_ctl_info *mci)
                             &pvt->mc_settings_a);
 
        if (IS_SINGLE_MODE(pvt->mc_settings_a))
-               debugf0("Memory controller operating on single mode\n");
+               edac_dbg(0, "Memory controller operating on single mode\n");
        else
-               debugf0("Memory controller operating on %s mode\n",
-               IS_MIRRORED(pvt->mc_settings) ? "mirrored" : "non-mirrored");
+               edac_dbg(0, "Memory controller operating on %smirrored mode\n",
+                        IS_MIRRORED(pvt->mc_settings) ? "" : "non-");
 
-       debugf0("Error detection is %s\n",
-               IS_ECC_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
-       debugf0("Retry is %s\n",
-               IS_RETRY_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
+       edac_dbg(0, "Error detection is %s\n",
+                IS_ECC_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
+       edac_dbg(0, "Retry is %s\n",
+                IS_RETRY_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
 
        /* Get Memory Interleave Range registers */
        pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR0,
@@ -970,18 +959,18 @@ static int __devinit i7300_get_devices(struct mem_ctl_info *mci)
                }
        }
 
-       debugf1("System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
-               pci_name(pvt->pci_dev_16_0_fsb_ctlr),
-               pvt->pci_dev_16_0_fsb_ctlr->vendor,
-               pvt->pci_dev_16_0_fsb_ctlr->device);
-       debugf1("Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
-               pci_name(pvt->pci_dev_16_1_fsb_addr_map),
-               pvt->pci_dev_16_1_fsb_addr_map->vendor,
-               pvt->pci_dev_16_1_fsb_addr_map->device);
-       debugf1("FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
-               pci_name(pvt->pci_dev_16_2_fsb_err_regs),
-               pvt->pci_dev_16_2_fsb_err_regs->vendor,
-               pvt->pci_dev_16_2_fsb_err_regs->device);
+       edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
+                pci_name(pvt->pci_dev_16_0_fsb_ctlr),
+                pvt->pci_dev_16_0_fsb_ctlr->vendor,
+                pvt->pci_dev_16_0_fsb_ctlr->device);
+       edac_dbg(1, "Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
+                pci_name(pvt->pci_dev_16_1_fsb_addr_map),
+                pvt->pci_dev_16_1_fsb_addr_map->vendor,
+                pvt->pci_dev_16_1_fsb_addr_map->device);
+       edac_dbg(1, "FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
+                pci_name(pvt->pci_dev_16_2_fsb_err_regs),
+                pvt->pci_dev_16_2_fsb_err_regs->vendor,
+                pvt->pci_dev_16_2_fsb_err_regs->device);
 
        pvt->pci_dev_2x_0_fbd_branch[0] = pci_get_device(PCI_VENDOR_ID_INTEL,
                                            PCI_DEVICE_ID_INTEL_I7300_MCH_FB0,
@@ -1032,10 +1021,9 @@ static int __devinit i7300_init_one(struct pci_dev *pdev,
        if (rc == -EIO)
                return rc;
 
-       debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
-               __func__,
-               pdev->bus->number,
-               PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+       edac_dbg(0, "MC: pdev bus %u dev=0x%x fn=0x%x\n",
+                pdev->bus->number,
+                PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
        /* We only are looking for func 0 of the set */
        if (PCI_FUNC(pdev->devfn) != 0)
@@ -1055,9 +1043,9 @@ static int __devinit i7300_init_one(struct pci_dev *pdev,
        if (mci == NULL)
                return -ENOMEM;
 
-       debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+       edac_dbg(0, "MC: mci = %p\n", mci);
 
-       mci->dev = &pdev->dev;  /* record ptr  to the generic device */
+       mci->pdev = &pdev->dev; /* record ptr  to the generic device */
 
        pvt = mci->pvt_info;
        pvt->pci_dev_16_0_fsb_ctlr = pdev;      /* Record this device in our private */
@@ -1088,19 +1076,16 @@ static int __devinit i7300_init_one(struct pci_dev *pdev,
        /* initialize the MC control structure 'csrows' table
         * with the mapping and control information */
        if (i7300_get_mc_regs(mci)) {
-               debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
-                       "    because i7300_init_csrows() returned nonzero "
-                       "value\n");
+               edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i7300_init_csrows() returned nonzero value\n");
                mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */
        } else {
-               debugf1("MC: Enable error reporting now\n");
+               edac_dbg(1, "MC: Enable error reporting now\n");
                i7300_enable_error_reporting(mci);
        }
 
        /* add this new MC control structure to EDAC's list of MCs */
        if (edac_mc_add_mc(mci)) {
-               debugf0("MC: " __FILE__
-                       ": %s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
                /* FIXME: perhaps some code should go here that disables error
                 * reporting if we just enabled it
                 */
@@ -1142,7 +1127,7 @@ static void __devexit i7300_remove_one(struct pci_dev *pdev)
        struct mem_ctl_info *mci;
        char *tmp;
 
-       debugf0(__FILE__ ": %s()\n", __func__);
+       edac_dbg(0, "\n");
 
        if (i7300_pci)
                edac_pci_release_generic_ctl(i7300_pci);
@@ -1189,7 +1174,7 @@ static int __init i7300_init(void)
 {
        int pci_rc;
 
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       edac_dbg(2, "\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -1204,7 +1189,7 @@ static int __init i7300_init(void)
  */
 static void __exit i7300_exit(void)
 {
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       edac_dbg(2, "\n");
        pci_unregister_driver(&i7300_driver);
 }
 
index a499c7ed820ae62d8fc489478ef8522e756d833b..3672101023bd8d44c7fb136601a72a0290a9e936 100644 (file)
@@ -248,6 +248,8 @@ struct i7core_dev {
 };
 
 struct i7core_pvt {
+       struct device *addrmatch_dev, *chancounts_dev;
+
        struct pci_dev  *pci_noncore;
        struct pci_dev  *pci_mcr[MAX_MCR_FUNC + 1];
        struct pci_dev  *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1];
@@ -514,29 +516,28 @@ static int get_dimm_config(struct mem_ctl_info *mci)
        pci_read_config_dword(pdev, MC_MAX_DOD, &pvt->info.max_dod);
        pci_read_config_dword(pdev, MC_CHANNEL_MAPPER, &pvt->info.ch_map);
 
-       debugf0("QPI %d control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n",
-               pvt->i7core_dev->socket, pvt->info.mc_control, pvt->info.mc_status,
-               pvt->info.max_dod, pvt->info.ch_map);
+       edac_dbg(0, "QPI %d control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n",
+                pvt->i7core_dev->socket, pvt->info.mc_control,
+                pvt->info.mc_status, pvt->info.max_dod, pvt->info.ch_map);
 
        if (ECC_ENABLED(pvt)) {
-               debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt) ? 8 : 4);
+               edac_dbg(0, "ECC enabled with x%d SDCC\n", ECCx8(pvt) ? 8 : 4);
                if (ECCx8(pvt))
                        mode = EDAC_S8ECD8ED;
                else
                        mode = EDAC_S4ECD4ED;
        } else {
-               debugf0("ECC disabled\n");
+               edac_dbg(0, "ECC disabled\n");
                mode = EDAC_NONE;
        }
 
        /* FIXME: need to handle the error codes */
-       debugf0("DOD Max limits: DIMMS: %d, %d-ranked, %d-banked "
-               "x%x x 0x%x\n",
-               numdimms(pvt->info.max_dod),
-               numrank(pvt->info.max_dod >> 2),
-               numbank(pvt->info.max_dod >> 4),
-               numrow(pvt->info.max_dod >> 6),
-               numcol(pvt->info.max_dod >> 9));
+       edac_dbg(0, "DOD Max limits: DIMMS: %d, %d-ranked, %d-banked x%x x 0x%x\n",
+                numdimms(pvt->info.max_dod),
+                numrank(pvt->info.max_dod >> 2),
+                numbank(pvt->info.max_dod >> 4),
+                numrow(pvt->info.max_dod >> 6),
+                numcol(pvt->info.max_dod >> 9));
 
        for (i = 0; i < NUM_CHANS; i++) {
                u32 data, dimm_dod[3], value[8];
@@ -545,11 +546,11 @@ static int get_dimm_config(struct mem_ctl_info *mci)
                        continue;
 
                if (!CH_ACTIVE(pvt, i)) {
-                       debugf0("Channel %i is not active\n", i);
+                       edac_dbg(0, "Channel %i is not active\n", i);
                        continue;
                }
                if (CH_DISABLED(pvt, i)) {
-                       debugf0("Channel %i is disabled\n", i);
+                       edac_dbg(0, "Channel %i is disabled\n", i);
                        continue;
                }
 
@@ -580,15 +581,14 @@ static int get_dimm_config(struct mem_ctl_info *mci)
                pci_read_config_dword(pvt->pci_ch[i][1],
                                MC_DOD_CH_DIMM2, &dimm_dod[2]);
 
-               debugf0("Ch%d phy rd%d, wr%d (0x%08x): "
-                       "%s%s%s%cDIMMs\n",
-                       i,
-                       RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i),
-                       data,
-                       pvt->channel[i].is_3dimms_present ? "3DIMMS " : "",
-                       pvt->channel[i].is_3dimms_present ? "SINGLE_4R " : "",
-                       pvt->channel[i].has_4rank ? "HAS_4R " : "",
-                       (data & REGISTERED_DIMM) ? 'R' : 'U');
+               edac_dbg(0, "Ch%d phy rd%d, wr%d (0x%08x): %s%s%s%cDIMMs\n",
+                        i,
+                        RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i),
+                        data,
+                        pvt->channel[i].is_3dimms_present ? "3DIMMS " : "",
+                        pvt->channel[i].is_3dimms_present ? "SINGLE_4R " : "",
+                        pvt->channel[i].has_4rank ? "HAS_4R " : "",
+                        (data & REGISTERED_DIMM) ? 'R' : 'U');
 
                for (j = 0; j < 3; j++) {
                        u32 banks, ranks, rows, cols;
@@ -607,11 +607,10 @@ static int get_dimm_config(struct mem_ctl_info *mci)
                        /* DDR3 has 8 I/O banks */
                        size = (rows * cols * banks * ranks) >> (20 - 3);
 
-                       debugf0("\tdimm %d %d Mb offset: %x, "
-                               "bank: %d, rank: %d, row: %#x, col: %#x\n",
-                               j, size,
-                               RANKOFFSET(dimm_dod[j]),
-                               banks, ranks, rows, cols);
+                       edac_dbg(0, "\tdimm %d %d Mb offset: %x, bank: %d, rank: %d, row: %#x, col: %#x\n",
+                                j, size,
+                                RANKOFFSET(dimm_dod[j]),
+                                banks, ranks, rows, cols);
 
                        npages = MiB_TO_PAGES(size);
 
@@ -647,12 +646,12 @@ static int get_dimm_config(struct mem_ctl_info *mci)
                pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]);
                pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]);
                pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]);
-               debugf1("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i);
+               edac_dbg(1, "\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i);
                for (j = 0; j < 8; j++)
-                       debugf1("\t\t%#x\t%#x\t%#x\n",
-                               (value[j] >> 27) & 0x1,
-                               (value[j] >> 24) & 0x7,
-                               (value[j] & ((1 << 24) - 1)));
+                       edac_dbg(1, "\t\t%#x\t%#x\t%#x\n",
+                                (value[j] >> 27) & 0x1,
+                                (value[j] >> 24) & 0x7,
+                                (value[j] & ((1 << 24) - 1)));
        }
 
        return 0;
@@ -662,6 +661,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)
                        Error insertion routines
  ****************************************************************************/
 
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
+
 /* The i7core has independent error injection features per channel.
    However, to have a simpler code, we don't allow enabling error injection
    on more than one channel.
@@ -691,9 +692,11 @@ static int disable_inject(const struct mem_ctl_info *mci)
  *     bit 0 - refers to the lower 32-byte half cacheline
  *     bit 1 - refers to the upper 32-byte half cacheline
  */
-static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
+static ssize_t i7core_inject_section_store(struct device *dev,
+                                          struct device_attribute *mattr,
                                           const char *data, size_t count)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct i7core_pvt *pvt = mci->pvt_info;
        unsigned long value;
        int rc;
@@ -709,9 +712,11 @@ static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
        return count;
 }
 
-static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
-                                             char *data)
+static ssize_t i7core_inject_section_show(struct device *dev,
+                                         struct device_attribute *mattr,
+                                         char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct i7core_pvt *pvt = mci->pvt_info;
        return sprintf(data, "0x%08x\n", pvt->inject.section);
 }
@@ -724,10 +729,12 @@ static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
  *     bit 1 - inject ECC error
  *     bit 2 - inject parity error
  */
-static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
+static ssize_t i7core_inject_type_store(struct device *dev,
+                                       struct device_attribute *mattr,
                                        const char *data, size_t count)
 {
-       struct i7core_pvt *pvt = mci->pvt_info;
+       struct mem_ctl_info *mci = to_mci(dev);
+struct i7core_pvt *pvt = mci->pvt_info;
        unsigned long value;
        int rc;
 
@@ -742,10 +749,13 @@ static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
        return count;
 }
 
-static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
-                                             char *data)
+static ssize_t i7core_inject_type_show(struct device *dev,
+                                      struct device_attribute *mattr,
+                                      char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct i7core_pvt *pvt = mci->pvt_info;
+
        return sprintf(data, "0x%08x\n", pvt->inject.type);
 }
 
@@ -759,9 +769,11 @@ static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
  *   23:16 and 31:24). Flipping bits in two symbol pairs will cause an
  *   uncorrectable error to be injected.
  */
-static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
-                                       const char *data, size_t count)
+static ssize_t i7core_inject_eccmask_store(struct device *dev,
+                                          struct device_attribute *mattr,
+                                          const char *data, size_t count)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct i7core_pvt *pvt = mci->pvt_info;
        unsigned long value;
        int rc;
@@ -777,10 +789,13 @@ static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
        return count;
 }
 
-static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
-                                             char *data)
+static ssize_t i7core_inject_eccmask_show(struct device *dev,
+                                         struct device_attribute *mattr,
+                                         char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct i7core_pvt *pvt = mci->pvt_info;
+
        return sprintf(data, "0x%08x\n", pvt->inject.eccmask);
 }
 
@@ -797,14 +812,16 @@ static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
 
 #define DECLARE_ADDR_MATCH(param, limit)                       \
 static ssize_t i7core_inject_store_##param(                    \
-               struct mem_ctl_info *mci,                       \
-               const char *data, size_t count)                 \
+       struct device *dev,                                     \
+       struct device_attribute *mattr,                         \
+       const char *data, size_t count)                         \
 {                                                              \
+       struct mem_ctl_info *mci = to_mci(dev);                 \
        struct i7core_pvt *pvt;                                 \
        long value;                                             \
        int rc;                                                 \
                                                                \
-       debugf1("%s()\n", __func__);                            \
+       edac_dbg(1, "\n");                                      \
        pvt = mci->pvt_info;                                    \
                                                                \
        if (pvt->inject.enable)                                 \
@@ -824,13 +841,15 @@ static ssize_t i7core_inject_store_##param(                       \
 }                                                              \
                                                                \
 static ssize_t i7core_inject_show_##param(                     \
-               struct mem_ctl_info *mci,                       \
-               char *data)                                     \
+       struct device *dev,                                     \
+       struct device_attribute *mattr,                         \
+       char *data)                                             \
 {                                                              \
+       struct mem_ctl_info *mci = to_mci(dev);                 \
        struct i7core_pvt *pvt;                                 \
                                                                \
        pvt = mci->pvt_info;                                    \
-       debugf1("%s() pvt=%p\n", __func__, pvt);                \
+       edac_dbg(1, "pvt=%p\n", pvt);                           \
        if (pvt->inject.param < 0)                              \
                return sprintf(data, "any\n");                  \
        else                                                    \
@@ -838,14 +857,9 @@ static ssize_t i7core_inject_show_##param(                 \
 }
 
 #define ATTR_ADDR_MATCH(param)                                 \
-       {                                                       \
-               .attr = {                                       \
-                       .name = #param,                         \
-                       .mode = (S_IRUGO | S_IWUSR)             \
-               },                                              \
-               .show  = i7core_inject_show_##param,            \
-               .store = i7core_inject_store_##param,           \
-       }
+       static DEVICE_ATTR(param, S_IRUGO | S_IWUSR,            \
+                   i7core_inject_show_##param,                 \
+                   i7core_inject_store_##param)
 
 DECLARE_ADDR_MATCH(channel, 3);
 DECLARE_ADDR_MATCH(dimm, 3);
@@ -854,14 +868,21 @@ DECLARE_ADDR_MATCH(bank, 32);
 DECLARE_ADDR_MATCH(page, 0x10000);
 DECLARE_ADDR_MATCH(col, 0x4000);
 
+ATTR_ADDR_MATCH(channel);
+ATTR_ADDR_MATCH(dimm);
+ATTR_ADDR_MATCH(rank);
+ATTR_ADDR_MATCH(bank);
+ATTR_ADDR_MATCH(page);
+ATTR_ADDR_MATCH(col);
+
 static int write_and_test(struct pci_dev *dev, const int where, const u32 val)
 {
        u32 read;
        int count;
 
-       debugf0("setting pci %02x:%02x.%x reg=%02x value=%08x\n",
-               dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
-               where, val);
+       edac_dbg(0, "setting pci %02x:%02x.%x reg=%02x value=%08x\n",
+                dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+                where, val);
 
        for (count = 0; count < 10; count++) {
                if (count)
@@ -899,9 +920,11 @@ static int write_and_test(struct pci_dev *dev, const int where, const u32 val)
  *    is reliable enough to check if the MC is using the
  *    three channels. However, this is not clear at the datasheet.
  */
-static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
-                                      const char *data, size_t count)
+static ssize_t i7core_inject_enable_store(struct device *dev,
+                                         struct device_attribute *mattr,
+                                         const char *data, size_t count)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct i7core_pvt *pvt = mci->pvt_info;
        u32 injectmask;
        u64 mask = 0;
@@ -994,17 +1017,18 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
        pci_write_config_dword(pvt->pci_noncore,
                               MC_CFG_CONTROL, 8);
 
-       debugf0("Error inject addr match 0x%016llx, ecc 0x%08x,"
-               " inject 0x%08x\n",
-               mask, pvt->inject.eccmask, injectmask);
+       edac_dbg(0, "Error inject addr match 0x%016llx, ecc 0x%08x, inject 0x%08x\n",
+                mask, pvt->inject.eccmask, injectmask);
 
 
        return count;
 }
 
-static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
-                                       char *data)
+static ssize_t i7core_inject_enable_show(struct device *dev,
+                                        struct device_attribute *mattr,
+                                        char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct i7core_pvt *pvt = mci->pvt_info;
        u32 injectmask;
 
@@ -1014,7 +1038,7 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
        pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0],
                               MC_CHANNEL_ERROR_INJECT, &injectmask);
 
-       debugf0("Inject error read: 0x%018x\n", injectmask);
+       edac_dbg(0, "Inject error read: 0x%018x\n", injectmask);
 
        if (injectmask & 0x0c)
                pvt->inject.enable = 1;
@@ -1024,12 +1048,14 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
 
 #define DECLARE_COUNTER(param)                                 \
 static ssize_t i7core_show_counter_##param(                    \
-               struct mem_ctl_info *mci,                       \
-               char *data)                                     \
+       struct device *dev,                                     \
+       struct device_attribute *mattr,                         \
+       char *data)                                             \
 {                                                              \
+       struct mem_ctl_info *mci = to_mci(dev);                 \
        struct i7core_pvt *pvt = mci->pvt_info;                 \
                                                                \
-       debugf1("%s() \n", __func__);                           \
+       edac_dbg(1, "\n");                                      \
        if (!pvt->ce_count_available || (pvt->is_registered))   \
                return sprintf(data, "data unavailable\n");     \
        return sprintf(data, "%lu\n",                           \
@@ -1037,121 +1063,179 @@ static ssize_t i7core_show_counter_##param(                   \
 }
 
 #define ATTR_COUNTER(param)                                    \
-       {                                                       \
-               .attr = {                                       \
-                       .name = __stringify(udimm##param),      \
-                       .mode = (S_IRUGO | S_IWUSR)             \
-               },                                              \
-               .show  = i7core_show_counter_##param            \
-       }
+       static DEVICE_ATTR(udimm##param, S_IRUGO | S_IWUSR,     \
+                   i7core_show_counter_##param,                \
+                   NULL)
 
 DECLARE_COUNTER(0);
 DECLARE_COUNTER(1);
 DECLARE_COUNTER(2);
 
+ATTR_COUNTER(0);
+ATTR_COUNTER(1);
+ATTR_COUNTER(2);
+
 /*
- * Sysfs struct
+ * inject_addrmatch device sysfs struct
  */
 
-static const struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = {
-       ATTR_ADDR_MATCH(channel),
-       ATTR_ADDR_MATCH(dimm),
-       ATTR_ADDR_MATCH(rank),
-       ATTR_ADDR_MATCH(bank),
-       ATTR_ADDR_MATCH(page),
-       ATTR_ADDR_MATCH(col),
-       { } /* End of list */
+static struct attribute *i7core_addrmatch_attrs[] = {
+       &dev_attr_channel.attr,
+       &dev_attr_dimm.attr,
+       &dev_attr_rank.attr,
+       &dev_attr_bank.attr,
+       &dev_attr_page.attr,
+       &dev_attr_col.attr,
+       NULL
 };
 
-static const struct mcidev_sysfs_group i7core_inject_addrmatch = {
-       .name  = "inject_addrmatch",
-       .mcidev_attr = i7core_addrmatch_attrs,
+static struct attribute_group addrmatch_grp = {
+       .attrs  = i7core_addrmatch_attrs,
 };
 
-static const struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
-       ATTR_COUNTER(0),
-       ATTR_COUNTER(1),
-       ATTR_COUNTER(2),
-       { .attr = { .name = NULL } }
+static const struct attribute_group *addrmatch_groups[] = {
+       &addrmatch_grp,
+       NULL
 };
 
-static const struct mcidev_sysfs_group i7core_udimm_counters = {
-       .name  = "all_channel_counts",
-       .mcidev_attr = i7core_udimm_counters_attrs,
+static void addrmatch_release(struct device *device)
+{
+       edac_dbg(1, "Releasing device %s\n", dev_name(device));
+       kfree(device);
+}
+
+static struct device_type addrmatch_type = {
+       .groups         = addrmatch_groups,
+       .release        = addrmatch_release,
 };
 
-static const struct mcidev_sysfs_attribute i7core_sysfs_rdimm_attrs[] = {
-       {
-               .attr = {
-                       .name = "inject_section",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show  = i7core_inject_section_show,
-               .store = i7core_inject_section_store,
-       }, {
-               .attr = {
-                       .name = "inject_type",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show  = i7core_inject_type_show,
-               .store = i7core_inject_type_store,
-       }, {
-               .attr = {
-                       .name = "inject_eccmask",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show  = i7core_inject_eccmask_show,
-               .store = i7core_inject_eccmask_store,
-       }, {
-               .grp = &i7core_inject_addrmatch,
-       }, {
-               .attr = {
-                       .name = "inject_enable",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show  = i7core_inject_enable_show,
-               .store = i7core_inject_enable_store,
-       },
-       { }     /* End of list */
+/*
+ * all_channel_counts sysfs struct
+ */
+
+static struct attribute *i7core_udimm_counters_attrs[] = {
+       &dev_attr_udimm0.attr,
+       &dev_attr_udimm1.attr,
+       &dev_attr_udimm2.attr,
+       NULL
 };
 
-static const struct mcidev_sysfs_attribute i7core_sysfs_udimm_attrs[] = {
-       {
-               .attr = {
-                       .name = "inject_section",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show  = i7core_inject_section_show,
-               .store = i7core_inject_section_store,
-       }, {
-               .attr = {
-                       .name = "inject_type",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show  = i7core_inject_type_show,
-               .store = i7core_inject_type_store,
-       }, {
-               .attr = {
-                       .name = "inject_eccmask",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show  = i7core_inject_eccmask_show,
-               .store = i7core_inject_eccmask_store,
-       }, {
-               .grp = &i7core_inject_addrmatch,
-       }, {
-               .attr = {
-                       .name = "inject_enable",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show  = i7core_inject_enable_show,
-               .store = i7core_inject_enable_store,
-       }, {
-               .grp = &i7core_udimm_counters,
-       },
-       { }     /* End of list */
+static struct attribute_group all_channel_counts_grp = {
+       .attrs  = i7core_udimm_counters_attrs,
 };
 
+static const struct attribute_group *all_channel_counts_groups[] = {
+       &all_channel_counts_grp,
+       NULL
+};
+
+static void all_channel_counts_release(struct device *device)
+{
+       edac_dbg(1, "Releasing device %s\n", dev_name(device));
+       kfree(device);
+}
+
+static struct device_type all_channel_counts_type = {
+       .groups         = all_channel_counts_groups,
+       .release        = all_channel_counts_release,
+};
+
+/*
+ * inject sysfs attributes
+ */
+
+static DEVICE_ATTR(inject_section, S_IRUGO | S_IWUSR,
+                  i7core_inject_section_show, i7core_inject_section_store);
+
+static DEVICE_ATTR(inject_type, S_IRUGO | S_IWUSR,
+                  i7core_inject_type_show, i7core_inject_type_store);
+
+
+static DEVICE_ATTR(inject_eccmask, S_IRUGO | S_IWUSR,
+                  i7core_inject_eccmask_show, i7core_inject_eccmask_store);
+
+static DEVICE_ATTR(inject_enable, S_IRUGO | S_IWUSR,
+                  i7core_inject_enable_show, i7core_inject_enable_store);
+
+static int i7core_create_sysfs_devices(struct mem_ctl_info *mci)
+{
+       struct i7core_pvt *pvt = mci->pvt_info;
+       int rc;
+
+       rc = device_create_file(&mci->dev, &dev_attr_inject_section);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_inject_type);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_inject_eccmask);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_inject_enable);
+       if (rc < 0)
+               return rc;
+
+       pvt->addrmatch_dev = kzalloc(sizeof(*pvt->addrmatch_dev), GFP_KERNEL);
+       if (!pvt->addrmatch_dev)
+               return rc;
+
+       pvt->addrmatch_dev->type = &addrmatch_type;
+       pvt->addrmatch_dev->bus = mci->dev.bus;
+       device_initialize(pvt->addrmatch_dev);
+       pvt->addrmatch_dev->parent = &mci->dev;
+       dev_set_name(pvt->addrmatch_dev, "inject_addrmatch");
+       dev_set_drvdata(pvt->addrmatch_dev, mci);
+
+       edac_dbg(1, "creating %s\n", dev_name(pvt->addrmatch_dev));
+
+       rc = device_add(pvt->addrmatch_dev);
+       if (rc < 0)
+               return rc;
+
+       if (!pvt->is_registered) {
+               pvt->chancounts_dev = kzalloc(sizeof(*pvt->chancounts_dev),
+                                             GFP_KERNEL);
+               if (!pvt->chancounts_dev) {
+                       put_device(pvt->addrmatch_dev);
+                       device_del(pvt->addrmatch_dev);
+                       return rc;
+               }
+
+               pvt->chancounts_dev->type = &all_channel_counts_type;
+               pvt->chancounts_dev->bus = mci->dev.bus;
+               device_initialize(pvt->chancounts_dev);
+               pvt->chancounts_dev->parent = &mci->dev;
+               dev_set_name(pvt->chancounts_dev, "all_channel_counts");
+               dev_set_drvdata(pvt->chancounts_dev, mci);
+
+               edac_dbg(1, "creating %s\n", dev_name(pvt->chancounts_dev));
+
+               rc = device_add(pvt->chancounts_dev);
+               if (rc < 0)
+                       return rc;
+       }
+       return 0;
+}
+
+static void i7core_delete_sysfs_devices(struct mem_ctl_info *mci)
+{
+       struct i7core_pvt *pvt = mci->pvt_info;
+
+       edac_dbg(1, "\n");
+
+       device_remove_file(&mci->dev, &dev_attr_inject_section);
+       device_remove_file(&mci->dev, &dev_attr_inject_type);
+       device_remove_file(&mci->dev, &dev_attr_inject_eccmask);
+       device_remove_file(&mci->dev, &dev_attr_inject_enable);
+
+       if (!pvt->is_registered) {
+               put_device(pvt->chancounts_dev);
+               device_del(pvt->chancounts_dev);
+       }
+       put_device(pvt->addrmatch_dev);
+       device_del(pvt->addrmatch_dev);
+}
+
 /****************************************************************************
        Device initialization routines: put/get, init/exit
  ****************************************************************************/
@@ -1164,14 +1248,14 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev)
 {
        int i;
 
-       debugf0(__FILE__ ": %s()\n", __func__);
+       edac_dbg(0, "\n");
        for (i = 0; i < i7core_dev->n_devs; i++) {
                struct pci_dev *pdev = i7core_dev->pdev[i];
                if (!pdev)
                        continue;
-               debugf0("Removing dev %02x:%02x.%d\n",
-                       pdev->bus->number,
-                       PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+               edac_dbg(0, "Removing dev %02x:%02x.%d\n",
+                        pdev->bus->number,
+                        PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
                pci_dev_put(pdev);
        }
 }
@@ -1214,12 +1298,12 @@ static unsigned i7core_pci_lastbus(void)
 
        while ((b = pci_find_next_bus(b)) != NULL) {
                bus = b->number;
-               debugf0("Found bus %d\n", bus);
+               edac_dbg(0, "Found bus %d\n", bus);
                if (bus > last_bus)
                        last_bus = bus;
        }
 
-       debugf0("Last bus %d\n", last_bus);
+       edac_dbg(0, "Last bus %d\n", last_bus);
 
        return last_bus;
 }
@@ -1326,10 +1410,10 @@ static int i7core_get_onedevice(struct pci_dev **prev,
                return -ENODEV;
        }
 
-       debugf0("Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x\n",
-               socket, bus, dev_descr->dev,
-               dev_descr->func,
-               PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+       edac_dbg(0, "Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x\n",
+                socket, bus, dev_descr->dev,
+                dev_descr->func,
+                PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
 
        /*
         * As stated on drivers/pci/search.c, the reference count for
@@ -1427,13 +1511,13 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
                                family = "unknown";
                                pvt->enable_scrub = false;
                        }
-                       debugf0("Detected a processor type %s\n", family);
+                       edac_dbg(0, "Detected a processor type %s\n", family);
                } else
                        goto error;
 
-               debugf0("Associated fn %d.%d, dev = %p, socket %d\n",
-                       PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
-                       pdev, i7core_dev->socket);
+               edac_dbg(0, "Associated fn %d.%d, dev = %p, socket %d\n",
+                        PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+                        pdev, i7core_dev->socket);
 
                if (PCI_SLOT(pdev->devfn) == 3 &&
                        PCI_FUNC(pdev->devfn) == 2)
@@ -1452,18 +1536,6 @@ error:
 /****************************************************************************
                        Error check routines
  ****************************************************************************/
-static void i7core_rdimm_update_errcount(struct mem_ctl_info *mci,
-                                     const int chan,
-                                     const int dimm,
-                                     const int add)
-{
-       int i;
-
-       for (i = 0; i < add; i++) {
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
-                                    chan, dimm, -1, "error", "", NULL);
-       }
-}
 
 static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci,
                                         const int chan,
@@ -1502,12 +1574,17 @@ static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci,
 
        /*updated the edac core */
        if (add0 != 0)
-               i7core_rdimm_update_errcount(mci, chan, 0, add0);
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, add0,
+                                    0, 0, 0,
+                                    chan, 0, -1, "error", "");
        if (add1 != 0)
-               i7core_rdimm_update_errcount(mci, chan, 1, add1);
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, add1,
+                                    0, 0, 0,
+                                    chan, 1, -1, "error", "");
        if (add2 != 0)
-               i7core_rdimm_update_errcount(mci, chan, 2, add2);
-
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, add2,
+                                    0, 0, 0,
+                                    chan, 2, -1, "error", "");
 }
 
 static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci)
@@ -1530,8 +1607,8 @@ static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci)
        pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_5,
                                                                &rcv[2][1]);
        for (i = 0 ; i < 3; i++) {
-               debugf3("MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n",
-                       (i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]);
+               edac_dbg(3, "MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n",
+                        (i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]);
                /*if the channel has 3 dimms*/
                if (pvt->channel[i].dimms > 2) {
                        new0 = DIMM_BOT_COR_ERR(rcv[i][0]);
@@ -1562,7 +1639,7 @@ static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci)
        int new0, new1, new2;
 
        if (!pvt->pci_mcr[4]) {
-               debugf0("%s MCR registers not found\n", __func__);
+               edac_dbg(0, "MCR registers not found\n");
                return;
        }
 
@@ -1626,7 +1703,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
                                    const struct mce *m)
 {
        struct i7core_pvt *pvt = mci->pvt_info;
-       char *type, *optype, *err, msg[80];
+       char *type, *optype, *err;
        enum hw_event_mc_err_type tp_event;
        unsigned long error = m->status & 0x1ff0000l;
        bool uncorrected_error = m->mcgstatus & 1ll << 61;
@@ -1704,20 +1781,18 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
                err = "unknown";
        }
 
-       snprintf(msg, sizeof(msg), "count=%d %s", core_err_cnt, optype);
-
        /*
         * Call the helper to output message
         * FIXME: what to do if core_err_cnt > 1? Currently, it generates
         * only one event
         */
        if (uncorrected_error || !pvt->is_registered)
-               edac_mc_handle_error(tp_event, mci,
+               edac_mc_handle_error(tp_event, mci, core_err_cnt,
                                     m->addr >> PAGE_SHIFT,
                                     m->addr & ~PAGE_MASK,
                                     syndrome,
                                     channel, dimm, -1,
-                                    err, msg, m);
+                                    err, optype);
 }
 
 /*
@@ -2094,8 +2169,7 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
        struct i7core_pvt *pvt;
 
        if (unlikely(!mci || !mci->pvt_info)) {
-               debugf0("MC: " __FILE__ ": %s(): dev = %p\n",
-                       __func__, &i7core_dev->pdev[0]->dev);
+               edac_dbg(0, "MC: dev = %p\n", &i7core_dev->pdev[0]->dev);
 
                i7core_printk(KERN_ERR, "Couldn't find mci handler\n");
                return;
@@ -2103,8 +2177,7 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
 
        pvt = mci->pvt_info;
 
-       debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
-               __func__, mci, &i7core_dev->pdev[0]->dev);
+       edac_dbg(0, "MC: mci = %p, dev = %p\n", mci, &i7core_dev->pdev[0]->dev);
 
        /* Disable scrubrate setting */
        if (pvt->enable_scrub)
@@ -2114,9 +2187,10 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
        i7core_pci_ctl_release(pvt);
 
        /* Remove MC sysfs nodes */
-       edac_mc_del_mc(mci->dev);
+       i7core_delete_sysfs_devices(mci);
+       edac_mc_del_mc(mci->pdev);
 
-       debugf1("%s: free mci struct\n", mci->ctl_name);
+       edac_dbg(1, "%s: free mci struct\n", mci->ctl_name);
        kfree(mci->ctl_name);
        edac_mc_free(mci);
        i7core_dev->mci = NULL;
@@ -2142,8 +2216,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
        if (unlikely(!mci))
                return -ENOMEM;
 
-       debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
-               __func__, mci, &i7core_dev->pdev[0]->dev);
+       edac_dbg(0, "MC: mci = %p, dev = %p\n", mci, &i7core_dev->pdev[0]->dev);
 
        pvt = mci->pvt_info;
        memset(pvt, 0, sizeof(*pvt));
@@ -2172,15 +2245,11 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
        if (unlikely(rc < 0))
                goto fail0;
 
-       if (pvt->is_registered)
-               mci->mc_driver_sysfs_attributes = i7core_sysfs_rdimm_attrs;
-       else
-               mci->mc_driver_sysfs_attributes = i7core_sysfs_udimm_attrs;
 
        /* Get dimm basic config */
        get_dimm_config(mci);
        /* record ptr to the generic device */
-       mci->dev = &i7core_dev->pdev[0]->dev;
+       mci->pdev = &i7core_dev->pdev[0]->dev;
        /* Set the function pointer to an actual operation function */
        mci->edac_check = i7core_check_error;
 
@@ -2190,8 +2259,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
 
        /* add this new MC control structure to EDAC's list of MCs */
        if (unlikely(edac_mc_add_mc(mci))) {
-               debugf0("MC: " __FILE__
-                       ": %s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
                /* FIXME: perhaps some code should go here that disables error
                 * reporting if we just enabled it
                 */
@@ -2199,6 +2267,12 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
                rc = -EINVAL;
                goto fail0;
        }
+       if (i7core_create_sysfs_devices(mci)) {
+               edac_dbg(0, "MC: failed to create sysfs nodes\n");
+               edac_mc_del_mc(mci->pdev);
+               rc = -EINVAL;
+               goto fail0;
+       }
 
        /* Default error mask is any memory */
        pvt->inject.channel = 0;
@@ -2298,7 +2372,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev)
 {
        struct i7core_dev *i7core_dev;
 
-       debugf0(__FILE__ ": %s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /*
         * we have a trouble here: pdev value for removal will be wrong, since
@@ -2347,7 +2421,7 @@ static int __init i7core_init(void)
 {
        int pci_rc;
 
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       edac_dbg(2, "\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -2374,7 +2448,7 @@ static int __init i7core_init(void)
  */
 static void __exit i7core_exit(void)
 {
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       edac_dbg(2, "\n");
        pci_unregister_driver(&i7core_driver);
        mce_unregister_decode_chain(&i7_mce_dec);
 }
index 52072c28a8a652466f31ed8be165b591098143ca..90f303db5d1dfd0d6ee0b4d77a0e1b899834fa68 100644 (file)
@@ -124,7 +124,7 @@ static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
                                *info)
 {
        struct pci_dev *pdev;
-       pdev = to_pci_dev(mci->dev);
+       pdev = to_pci_dev(mci->pdev);
        pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap);
        if (info->eap & I82443BXGX_EAP_OFFSET_SBE)
                /* Clear error to allow next error to be reported [p.61] */
@@ -156,19 +156,19 @@ static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci,
        if (info->eap & I82443BXGX_EAP_OFFSET_SBE) {
                error_found = 1;
                if (handle_errors)
-                       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+                       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                             page, pageoffset, 0,
                                             edac_mc_find_csrow_by_page(mci, page),
-                                            0, -1, mci->ctl_name, "", NULL);
+                                            0, -1, mci->ctl_name, "");
        }
 
        if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
                error_found = 1;
                if (handle_errors)
-                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                             page, pageoffset, 0,
                                             edac_mc_find_csrow_by_page(mci, page),
-                                            0, -1, mci->ctl_name, "", NULL);
+                                            0, -1, mci->ctl_name, "");
        }
 
        return error_found;
@@ -178,7 +178,7 @@ static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
 {
        struct i82443bxgx_edacmc_error_info info;
 
-       debugf1("MC%d: %s: %s()\n", mci->mc_idx, __FILE__, __func__);
+       edac_dbg(1, "MC%d\n", mci->mc_idx);
        i82443bxgx_edacmc_get_error_info(mci, &info);
        i82443bxgx_edacmc_process_error_info(mci, &info, 1);
 }
@@ -197,18 +197,17 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
        pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
        row_high_limit_last = 0;
        for (index = 0; index < mci->nr_csrows; index++) {
-               csrow = &mci->csrows[index];
-               dimm = csrow->channels[0].dimm;
+               csrow = mci->csrows[index];
+               dimm = csrow->channels[0]->dimm;
 
                pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
-               debugf1("MC%d: %s: %s() Row=%d DRB = %#0x\n",
-                       mci->mc_idx, __FILE__, __func__, index, drbar);
+               edac_dbg(1, "MC%d: Row=%d DRB = %#0x\n",
+                        mci->mc_idx, index, drbar);
                row_high_limit = ((u32) drbar << 23);
                /* find the DRAM Chip Select Base address and mask */
-               debugf1("MC%d: %s: %s() Row=%d, "
-                       "Boundary Address=%#0x, Last = %#0x\n",
-                       mci->mc_idx, __FILE__, __func__, index, row_high_limit,
-                       row_high_limit_last);
+               edac_dbg(1, "MC%d: Row=%d, Boundary Address=%#0x, Last = %#0x\n",
+                        mci->mc_idx, index, row_high_limit,
+                        row_high_limit_last);
 
                /* 440GX goes to 2GB, represented with a DRB of 0. */
                if (row_high_limit_last && !row_high_limit)
@@ -241,7 +240,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
        enum mem_type mtype;
        enum edac_type edac_mode;
 
-       debugf0("MC: %s: %s()\n", __FILE__, __func__);
+       edac_dbg(0, "MC:\n");
 
        /* Something is really hosed if PCI config space reads from
         * the MC aren't working.
@@ -259,8 +258,8 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
        if (mci == NULL)
                return -ENOMEM;
 
-       debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
-       mci->dev = &pdev->dev;
+       edac_dbg(0, "MC: mci = %p\n", mci);
+       mci->pdev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
        pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
@@ -275,8 +274,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
                mtype = MEM_RDR;
                break;
        default:
-               debugf0("Unknown/reserved DRAM type value "
-                       "in DRAMC register!\n");
+               edac_dbg(0, "Unknown/reserved DRAM type value in DRAMC register!\n");
                mtype = -MEM_UNKNOWN;
        }
 
@@ -305,8 +303,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
                edac_mode = EDAC_SECDED;
                break;
        default:
-               debugf0("%s(): Unknown/reserved ECC state "
-                       "in NBXCFG register!\n", __func__);
+               edac_dbg(0, "Unknown/reserved ECC state in NBXCFG register!\n");
                edac_mode = EDAC_UNKNOWN;
                break;
        }
@@ -330,7 +327,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
        mci->ctl_page_to_phys = NULL;
 
        if (edac_mc_add_mc(mci)) {
-               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "failed edac_mc_add_mc()\n");
                goto fail;
        }
 
@@ -345,7 +342,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
                        __func__);
        }
 
-       debugf3("MC: %s: %s(): success\n", __FILE__, __func__);
+       edac_dbg(3, "MC: success\n");
        return 0;
 
 fail:
@@ -361,7 +358,7 @@ static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("MC: %s: %s()\n", __FILE__, __func__);
+       edac_dbg(0, "MC:\n");
 
        /* don't need to call pci_enable_device() */
        rc = i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
@@ -376,7 +373,7 @@ static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0("%s: %s()\n", __FILE__, __func__);
+       edac_dbg(0, "\n");
 
        if (i82443bxgx_pci)
                edac_pci_release_generic_ctl(i82443bxgx_pci);
@@ -428,7 +425,7 @@ static int __init i82443bxgx_edacmc_init(void)
                        id = &i82443bxgx_pci_tbl[i];
                }
                if (!mci_pdev) {
-                       debugf0("i82443bxgx pci_get_device fail\n");
+                       edac_dbg(0, "i82443bxgx pci_get_device fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
@@ -436,7 +433,7 @@ static int __init i82443bxgx_edacmc_init(void)
                pci_rc = i82443bxgx_edacmc_init_one(mci_pdev, i82443bxgx_pci_tbl);
 
                if (pci_rc < 0) {
-                       debugf0("i82443bxgx init fail\n");
+                       edac_dbg(0, "i82443bxgx init fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
index 08045059d10bcc64a06318c9fcdd7826e7ea83fc..1faa749715131c1e19b34134d6c01626fb34dd7a 100644 (file)
@@ -67,7 +67,7 @@ static void i82860_get_error_info(struct mem_ctl_info *mci,
 {
        struct pci_dev *pdev;
 
-       pdev = to_pci_dev(mci->dev);
+       pdev = to_pci_dev(mci->pdev);
 
        /*
         * This is a mess because there is no atomic way to read all the
@@ -109,25 +109,25 @@ static int i82860_process_error_info(struct mem_ctl_info *mci,
                return 1;
 
        if ((info->errsts ^ info->errsts2) & 0x0003) {
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
-                                    -1, -1, -1, "UE overwrote CE", "", NULL);
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
+                                    -1, -1, -1, "UE overwrote CE", "");
                info->errsts = info->errsts2;
        }
 
        info->eap >>= PAGE_SHIFT;
        row = edac_mc_find_csrow_by_page(mci, info->eap);
-       dimm = mci->csrows[row].channels[0].dimm;
+       dimm = mci->csrows[row]->channels[0]->dimm;
 
        if (info->errsts & 0x0002)
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                     info->eap, 0, 0,
                                     dimm->location[0], dimm->location[1], -1,
-                                    "i82860 UE", "", NULL);
+                                    "i82860 UE", "");
        else
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                     info->eap, 0, info->derrsyn,
                                     dimm->location[0], dimm->location[1], -1,
-                                    "i82860 CE", "", NULL);
+                                    "i82860 CE", "");
 
        return 1;
 }
@@ -136,7 +136,7 @@ static void i82860_check(struct mem_ctl_info *mci)
 {
        struct i82860_error_info info;
 
-       debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+       edac_dbg(1, "MC%d\n", mci->mc_idx);
        i82860_get_error_info(mci, &info);
        i82860_process_error_info(mci, &info, 1);
 }
@@ -161,14 +161,13 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
         * in all eight rows.
         */
        for (index = 0; index < mci->nr_csrows; index++) {
-               csrow = &mci->csrows[index];
-               dimm = csrow->channels[0].dimm;
+               csrow = mci->csrows[index];
+               dimm = csrow->channels[0]->dimm;
 
                pci_read_config_word(pdev, I82860_GBA + index * 2, &value);
                cumul_size = (value & I82860_GBA_MASK) <<
                        (I82860_GBA_SHIFT - PAGE_SHIFT);
-               debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
-                       cumul_size);
+               edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size);
 
                if (cumul_size == last_cumul_size)
                        continue;       /* not populated */
@@ -210,8 +209,8 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
        if (!mci)
                return -ENOMEM;
 
-       debugf3("%s(): init mci\n", __func__);
-       mci->dev = &pdev->dev;
+       edac_dbg(3, "init mci\n");
+       mci->pdev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_DDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
        /* I"m not sure about this but I think that all RDRAM is SECDED */
@@ -229,7 +228,7 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
         * type of memory controller.  The ID is therefore hardcoded to 0.
         */
        if (edac_mc_add_mc(mci)) {
-               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "failed edac_mc_add_mc()\n");
                goto fail;
        }
 
@@ -245,7 +244,7 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
        }
 
        /* get this far and it's successful */
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
 
        return 0;
 
@@ -260,7 +259,7 @@ static int __devinit i82860_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
        i82860_printk(KERN_INFO, "i82860 init one\n");
 
        if (pci_enable_device(pdev) < 0)
@@ -278,7 +277,7 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        if (i82860_pci)
                edac_pci_release_generic_ctl(i82860_pci);
@@ -311,7 +310,7 @@ static int __init i82860_init(void)
 {
        int pci_rc;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -324,7 +323,7 @@ static int __init i82860_init(void)
                                        PCI_DEVICE_ID_INTEL_82860_0, NULL);
 
                if (mci_pdev == NULL) {
-                       debugf0("860 pci_get_device fail\n");
+                       edac_dbg(0, "860 pci_get_device fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
@@ -332,7 +331,7 @@ static int __init i82860_init(void)
                pci_rc = i82860_init_one(mci_pdev, i82860_pci_tbl);
 
                if (pci_rc < 0) {
-                       debugf0("860 init fail\n");
+                       edac_dbg(0, "860 init fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
@@ -352,7 +351,7 @@ fail0:
 
 static void __exit i82860_exit(void)
 {
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        pci_unregister_driver(&i82860_driver);
 
index b613e31c16e5de18f47a8a335690cfc4c487a752..3e416b1a6b53680b3f5d78f3a579fb04439caa62 100644 (file)
@@ -189,7 +189,7 @@ static void i82875p_get_error_info(struct mem_ctl_info *mci,
 {
        struct pci_dev *pdev;
 
-       pdev = to_pci_dev(mci->dev);
+       pdev = to_pci_dev(mci->pdev);
 
        /*
         * This is a mess because there is no atomic way to read all the
@@ -227,7 +227,7 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci,
 {
        int row, multi_chan;
 
-       multi_chan = mci->csrows[0].nr_channels - 1;
+       multi_chan = mci->csrows[0]->nr_channels - 1;
 
        if (!(info->errsts & 0x0081))
                return 0;
@@ -236,9 +236,9 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci,
                return 1;
 
        if ((info->errsts ^ info->errsts2) & 0x0081) {
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
                                     -1, -1, -1,
-                                    "UE overwrote CE", "", NULL);
+                                    "UE overwrote CE", "");
                info->errsts = info->errsts2;
        }
 
@@ -246,15 +246,15 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci,
        row = edac_mc_find_csrow_by_page(mci, info->eap);
 
        if (info->errsts & 0x0080)
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                     info->eap, 0, 0,
                                     row, -1, -1,
-                                    "i82875p UE", "", NULL);
+                                    "i82875p UE", "");
        else
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                     info->eap, 0, info->derrsyn,
                                     row, multi_chan ? (info->des & 0x1) : 0,
-                                    -1, "i82875p CE", "", NULL);
+                                    -1, "i82875p CE", "");
 
        return 1;
 }
@@ -263,7 +263,7 @@ static void i82875p_check(struct mem_ctl_info *mci)
 {
        struct i82875p_error_info info;
 
-       debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+       edac_dbg(1, "MC%d\n", mci->mc_idx);
        i82875p_get_error_info(mci, &info);
        i82875p_process_error_info(mci, &info, 1);
 }
@@ -367,12 +367,11 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci,
         */
 
        for (index = 0; index < mci->nr_csrows; index++) {
-               csrow = &mci->csrows[index];
+               csrow = mci->csrows[index];
 
                value = readb(ovrfl_window + I82875P_DRB + index);
                cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT);
-               debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
-                       cumul_size);
+               edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size);
                if (cumul_size == last_cumul_size)
                        continue;       /* not populated */
 
@@ -382,7 +381,7 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci,
                last_cumul_size = cumul_size;
 
                for (j = 0; j < nr_chans; j++) {
-                       dimm = csrow->channels[j].dimm;
+                       dimm = csrow->channels[j]->dimm;
 
                        dimm->nr_pages = nr_pages / nr_chans;
                        dimm->grain = 1 << 12;  /* I82875P_EAP has 4KiB reolution */
@@ -405,7 +404,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
        u32 nr_chans;
        struct i82875p_error_info discard;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
 
@@ -426,11 +425,8 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
                goto fail0;
        }
 
-       /* Keeps mci available after edac_mc_del_mc() till edac_mc_free() */
-       kobject_get(&mci->edac_mci_kobj);
-
-       debugf3("%s(): init mci\n", __func__);
-       mci->dev = &pdev->dev;
+       edac_dbg(3, "init mci\n");
+       mci->pdev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_DDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
        mci->edac_cap = EDAC_FLAG_UNKNOWN;
@@ -440,7 +436,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
        mci->dev_name = pci_name(pdev);
        mci->edac_check = i82875p_check;
        mci->ctl_page_to_phys = NULL;
-       debugf3("%s(): init pvt\n", __func__);
+       edac_dbg(3, "init pvt\n");
        pvt = (struct i82875p_pvt *)mci->pvt_info;
        pvt->ovrfl_pdev = ovrfl_pdev;
        pvt->ovrfl_window = ovrfl_window;
@@ -451,7 +447,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
         * type of memory controller.  The ID is therefore hardcoded to 0.
         */
        if (edac_mc_add_mc(mci)) {
-               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "failed edac_mc_add_mc()\n");
                goto fail1;
        }
 
@@ -467,11 +463,10 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
        }
 
        /* get this far and it's successful */
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
        return 0;
 
 fail1:
-       kobject_put(&mci->edac_mci_kobj);
        edac_mc_free(mci);
 
 fail0:
@@ -489,7 +484,7 @@ static int __devinit i82875p_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
        i82875p_printk(KERN_INFO, "i82875p init one\n");
 
        if (pci_enable_device(pdev) < 0)
@@ -508,7 +503,7 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev)
        struct mem_ctl_info *mci;
        struct i82875p_pvt *pvt = NULL;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        if (i82875p_pci)
                edac_pci_release_generic_ctl(i82875p_pci);
@@ -554,7 +549,7 @@ static int __init i82875p_init(void)
 {
        int pci_rc;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -569,7 +564,7 @@ static int __init i82875p_init(void)
                                        PCI_DEVICE_ID_INTEL_82875_0, NULL);
 
                if (!mci_pdev) {
-                       debugf0("875p pci_get_device fail\n");
+                       edac_dbg(0, "875p pci_get_device fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
@@ -577,7 +572,7 @@ static int __init i82875p_init(void)
                pci_rc = i82875p_init_one(mci_pdev, i82875p_pci_tbl);
 
                if (pci_rc < 0) {
-                       debugf0("875p init fail\n");
+                       edac_dbg(0, "875p init fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
@@ -597,7 +592,7 @@ fail0:
 
 static void __exit i82875p_exit(void)
 {
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        i82875p_remove_one(mci_pdev);
        pci_dev_put(mci_pdev);
index 433332c7cdbabe3bf54fbce0e9622403af29869c..069e26c11c4f761997bbf2afb6b9bf1bf2d6b039 100644 (file)
@@ -241,7 +241,7 @@ static void i82975x_get_error_info(struct mem_ctl_info *mci,
 {
        struct pci_dev *pdev;
 
-       pdev = to_pci_dev(mci->dev);
+       pdev = to_pci_dev(mci->pdev);
 
        /*
         * This is a mess because there is no atomic way to read all the
@@ -288,8 +288,8 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci,
                return 1;
 
        if ((info->errsts ^ info->errsts2) & 0x0003) {
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
-                                    -1, -1, -1, "UE overwrote CE", "", NULL);
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
+                                    -1, -1, -1, "UE overwrote CE", "");
                info->errsts = info->errsts2;
        }
 
@@ -308,21 +308,21 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci,
                        (info->xeap & 1) ? 1 : 0, info->eap, (unsigned int) page);
                return 0;
        }
-       chan = (mci->csrows[row].nr_channels == 1) ? 0 : info->eap & 1;
+       chan = (mci->csrows[row]->nr_channels == 1) ? 0 : info->eap & 1;
        offst = info->eap
                        & ((1 << PAGE_SHIFT) -
-                          (1 << mci->csrows[row].channels[chan].dimm->grain));
+                          (1 << mci->csrows[row]->channels[chan]->dimm->grain));
 
        if (info->errsts & 0x0002)
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                     page, offst, 0,
                                     row, -1, -1,
-                                    "i82975x UE", "", NULL);
+                                    "i82975x UE", "");
        else
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                     page, offst, info->derrsyn,
                                     row, chan ? chan : 0, -1,
-                                    "i82975x CE", "", NULL);
+                                    "i82975x CE", "");
 
        return 1;
 }
@@ -331,7 +331,7 @@ static void i82975x_check(struct mem_ctl_info *mci)
 {
        struct i82975x_error_info info;
 
-       debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+       edac_dbg(1, "MC%d\n", mci->mc_idx);
        i82975x_get_error_info(mci, &info);
        i82975x_process_error_info(mci, &info, 1);
 }
@@ -394,7 +394,7 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
         */
 
        for (index = 0; index < mci->nr_csrows; index++) {
-               csrow = &mci->csrows[index];
+               csrow = mci->csrows[index];
 
                value = readb(mch_window + I82975X_DRB + index +
                                        ((index >= 4) ? 0x80 : 0));
@@ -406,8 +406,7 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
                 */
                if (csrow->nr_channels > 1)
                        cumul_size <<= 1;
-               debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
-                       cumul_size);
+               edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size);
 
                nr_pages = cumul_size - last_cumul_size;
                if (!nr_pages)
@@ -421,10 +420,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
                 */
                dtype = i82975x_dram_type(mch_window, index);
                for (chan = 0; chan < csrow->nr_channels; chan++) {
-                       dimm = mci->csrows[index].channels[chan].dimm;
+                       dimm = mci->csrows[index]->channels[chan]->dimm;
 
                        dimm->nr_pages = nr_pages / csrow->nr_channels;
-                       strncpy(csrow->channels[chan].dimm->label,
+                       strncpy(csrow->channels[chan]->dimm->label,
                                        labels[(index >> 1) + (chan * 2)],
                                        EDAC_MC_LABEL_LEN);
                        dimm->grain = 1 << 7;   /* 128Byte cache-line resolution */
@@ -489,11 +488,11 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
        u8 c1drb[4];
 #endif
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        pci_read_config_dword(pdev, I82975X_MCHBAR, &mchbar);
        if (!(mchbar & 1)) {
-               debugf3("%s(): failed, MCHBAR disabled!\n", __func__);
+               edac_dbg(3, "failed, MCHBAR disabled!\n");
                goto fail0;
        }
        mchbar &= 0xffffc000;   /* bits 31:14 used for 16K window */
@@ -558,8 +557,8 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
                goto fail1;
        }
 
-       debugf3("%s(): init mci\n", __func__);
-       mci->dev = &pdev->dev;
+       edac_dbg(3, "init mci\n");
+       mci->pdev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_DDR2;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
        mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
@@ -569,7 +568,7 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
        mci->dev_name = pci_name(pdev);
        mci->edac_check = i82975x_check;
        mci->ctl_page_to_phys = NULL;
-       debugf3("%s(): init pvt\n", __func__);
+       edac_dbg(3, "init pvt\n");
        pvt = (struct i82975x_pvt *) mci->pvt_info;
        pvt->mch_window = mch_window;
        i82975x_init_csrows(mci, pdev, mch_window);
@@ -578,12 +577,12 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
 
        /* finalize this instance of memory controller with edac core */
        if (edac_mc_add_mc(mci)) {
-               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "failed edac_mc_add_mc()\n");
                goto fail2;
        }
 
        /* get this far and it's successful */
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
        return 0;
 
 fail2:
@@ -601,7 +600,7 @@ static int __devinit i82975x_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        if (pci_enable_device(pdev) < 0)
                return -EIO;
@@ -619,7 +618,7 @@ static void __devexit i82975x_remove_one(struct pci_dev *pdev)
        struct mem_ctl_info *mci;
        struct i82975x_pvt *pvt;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        mci = edac_mc_del_mc(&pdev->dev);
        if (mci  == NULL)
@@ -655,7 +654,7 @@ static int __init i82975x_init(void)
 {
        int pci_rc;
 
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -669,7 +668,7 @@ static int __init i82975x_init(void)
                                PCI_DEVICE_ID_INTEL_82975_0, NULL);
 
                if (!mci_pdev) {
-                       debugf0("i82975x pci_get_device fail\n");
+                       edac_dbg(0, "i82975x pci_get_device fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
@@ -677,7 +676,7 @@ static int __init i82975x_init(void)
                pci_rc = i82975x_init_one(mci_pdev, i82975x_pci_tbl);
 
                if (pci_rc < 0) {
-                       debugf0("i82975x init fail\n");
+                       edac_dbg(0, "i82975x init fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
@@ -697,7 +696,7 @@ fail0:
 
 static void __exit i82975x_exit(void)
 {
-       debugf3("%s()\n", __func__);
+       edac_dbg(3, "\n");
 
        pci_unregister_driver(&i82975x_driver);
 
index 0e374625f6f894a20272df947ffe2f3b7620422f..a1e791ec25d38514b7c47ae27bd2cab0198ded68 100644 (file)
@@ -49,34 +49,45 @@ static u32 orig_hid1[2];
 
 /************************ MC SYSFS parts ***********************************/
 
-static ssize_t mpc85xx_mc_inject_data_hi_show(struct mem_ctl_info *mci,
+#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
+
+static ssize_t mpc85xx_mc_inject_data_hi_show(struct device *dev,
+                                             struct device_attribute *mattr,
                                              char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
        return sprintf(data, "0x%08x",
                       in_be32(pdata->mc_vbase +
                               MPC85XX_MC_DATA_ERR_INJECT_HI));
 }
 
-static ssize_t mpc85xx_mc_inject_data_lo_show(struct mem_ctl_info *mci,
+static ssize_t mpc85xx_mc_inject_data_lo_show(struct device *dev,
+                                             struct device_attribute *mattr,
                                              char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
        return sprintf(data, "0x%08x",
                       in_be32(pdata->mc_vbase +
                               MPC85XX_MC_DATA_ERR_INJECT_LO));
 }
 
-static ssize_t mpc85xx_mc_inject_ctrl_show(struct mem_ctl_info *mci, char *data)
+static ssize_t mpc85xx_mc_inject_ctrl_show(struct device *dev,
+                                          struct device_attribute *mattr,
+                                          char *data)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
        return sprintf(data, "0x%08x",
                       in_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT));
 }
 
-static ssize_t mpc85xx_mc_inject_data_hi_store(struct mem_ctl_info *mci,
+static ssize_t mpc85xx_mc_inject_data_hi_store(struct device *dev,
+                                              struct device_attribute *mattr,
                                               const char *data, size_t count)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
        if (isdigit(*data)) {
                out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_HI,
@@ -86,9 +97,11 @@ static ssize_t mpc85xx_mc_inject_data_hi_store(struct mem_ctl_info *mci,
        return 0;
 }
 
-static ssize_t mpc85xx_mc_inject_data_lo_store(struct mem_ctl_info *mci,
+static ssize_t mpc85xx_mc_inject_data_lo_store(struct device *dev,
+                                              struct device_attribute *mattr,
                                               const char *data, size_t count)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
        if (isdigit(*data)) {
                out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_LO,
@@ -98,9 +111,11 @@ static ssize_t mpc85xx_mc_inject_data_lo_store(struct mem_ctl_info *mci,
        return 0;
 }
 
-static ssize_t mpc85xx_mc_inject_ctrl_store(struct mem_ctl_info *mci,
-                                           const char *data, size_t count)
+static ssize_t mpc85xx_mc_inject_ctrl_store(struct device *dev,
+                                              struct device_attribute *mattr,
+                                              const char *data, size_t count)
 {
+       struct mem_ctl_info *mci = to_mci(dev);
        struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
        if (isdigit(*data)) {
                out_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT,
@@ -110,38 +125,35 @@ static ssize_t mpc85xx_mc_inject_ctrl_store(struct mem_ctl_info *mci,
        return 0;
 }
 
-static struct mcidev_sysfs_attribute mpc85xx_mc_sysfs_attributes[] = {
-       {
-        .attr = {
-                 .name = "inject_data_hi",
-                 .mode = (S_IRUGO | S_IWUSR)
-                 },
-        .show = mpc85xx_mc_inject_data_hi_show,
-        .store = mpc85xx_mc_inject_data_hi_store},
-       {
-        .attr = {
-                 .name = "inject_data_lo",
-                 .mode = (S_IRUGO | S_IWUSR)
-                 },
-        .show = mpc85xx_mc_inject_data_lo_show,
-        .store = mpc85xx_mc_inject_data_lo_store},
-       {
-        .attr = {
-                 .name = "inject_ctrl",
-                 .mode = (S_IRUGO | S_IWUSR)
-                 },
-        .show = mpc85xx_mc_inject_ctrl_show,
-        .store = mpc85xx_mc_inject_ctrl_store},
+DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR,
+           mpc85xx_mc_inject_data_hi_show, mpc85xx_mc_inject_data_hi_store);
+DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR,
+           mpc85xx_mc_inject_data_lo_show, mpc85xx_mc_inject_data_lo_store);
+DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR,
+           mpc85xx_mc_inject_ctrl_show, mpc85xx_mc_inject_ctrl_store);
 
-       /* End of list */
-       {
-        .attr = {.name = NULL}
-        }
-};
+static int mpc85xx_create_sysfs_attributes(struct mem_ctl_info *mci)
+{
+       int rc;
+
+       rc = device_create_file(&mci->dev, &dev_attr_inject_data_hi);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_inject_data_lo);
+       if (rc < 0)
+               return rc;
+       rc = device_create_file(&mci->dev, &dev_attr_inject_ctrl);
+       if (rc < 0)
+               return rc;
 
-static void mpc85xx_set_mc_sysfs_attributes(struct mem_ctl_info *mci)
+       return 0;
+}
+
+static void mpc85xx_remove_sysfs_attributes(struct mem_ctl_info *mci)
 {
-       mci->mc_driver_sysfs_attributes = mpc85xx_mc_sysfs_attributes;
+       device_remove_file(&mci->dev, &dev_attr_inject_data_hi);
+       device_remove_file(&mci->dev, &dev_attr_inject_data_lo);
+       device_remove_file(&mci->dev, &dev_attr_inject_ctrl);
 }
 
 /**************************** PCI Err device ***************************/
@@ -268,7 +280,7 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op)
        out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0);
 
        if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
-               debugf3("%s(): failed edac_pci_add_device()\n", __func__);
+               edac_dbg(3, "failed edac_pci_add_device()\n");
                goto err;
        }
 
@@ -291,7 +303,7 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op)
        }
 
        devres_remove_group(&op->dev, mpc85xx_pci_err_probe);
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
        printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n");
 
        return 0;
@@ -309,7 +321,7 @@ static int mpc85xx_pci_err_remove(struct platform_device *op)
        struct edac_pci_ctl_info *pci = dev_get_drvdata(&op->dev);
        struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_CAP_DR,
                 orig_pci_err_cap_dr);
@@ -570,7 +582,7 @@ static int __devinit mpc85xx_l2_err_probe(struct platform_device *op)
        pdata->edac_idx = edac_dev_idx++;
 
        if (edac_device_add_device(edac_dev) > 0) {
-               debugf3("%s(): failed edac_device_add_device()\n", __func__);
+               edac_dbg(3, "failed edac_device_add_device()\n");
                goto err;
        }
 
@@ -598,7 +610,7 @@ static int __devinit mpc85xx_l2_err_probe(struct platform_device *op)
 
        devres_remove_group(&op->dev, mpc85xx_l2_err_probe);
 
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
        printk(KERN_INFO EDAC_MOD_STR " L2 err registered\n");
 
        return 0;
@@ -616,7 +628,7 @@ static int mpc85xx_l2_err_remove(struct platform_device *op)
        struct edac_device_ctl_info *edac_dev = dev_get_drvdata(&op->dev);
        struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        if (edac_op_state == EDAC_OPSTATE_INT) {
                out_be32(pdata->l2_vbase + MPC85XX_L2_ERRINTEN, 0);
@@ -813,7 +825,7 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
        pfn = err_addr >> PAGE_SHIFT;
 
        for (row_index = 0; row_index < mci->nr_csrows; row_index++) {
-               csrow = &mci->csrows[row_index];
+               csrow = mci->csrows[row_index];
                if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page))
                        break;
        }
@@ -854,16 +866,16 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
                mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n");
 
        if (err_detect & DDR_EDE_SBE)
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                     pfn, err_addr & ~PAGE_MASK, syndrome,
                                     row_index, 0, -1,
-                                    mci->ctl_name, "", NULL);
+                                    mci->ctl_name, "");
 
        if (err_detect & DDR_EDE_MBE)
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                     pfn, err_addr & ~PAGE_MASK, syndrome,
                                     row_index, 0, -1,
-                                    mci->ctl_name, "", NULL);
+                                    mci->ctl_name, "");
 
        out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect);
 }
@@ -933,8 +945,8 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
                u32 start;
                u32 end;
 
-               csrow = &mci->csrows[index];
-               dimm = csrow->channels[0].dimm;
+               csrow = mci->csrows[index];
+               dimm = csrow->channels[0]->dimm;
 
                cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 +
                                  (index * MPC85XX_MC_CS_BNDS_OFS));
@@ -990,9 +1002,9 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
        pdata = mci->pvt_info;
        pdata->name = "mpc85xx_mc_err";
        pdata->irq = NO_IRQ;
-       mci->dev = &op->dev;
+       mci->pdev = &op->dev;
        pdata->edac_idx = edac_mc_idx++;
-       dev_set_drvdata(mci->dev, mci);
+       dev_set_drvdata(mci->pdev, mci);
        mci->ctl_name = pdata->name;
        mci->dev_name = pdata->name;
 
@@ -1026,7 +1038,7 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
                goto err;
        }
 
-       debugf3("%s(): init mci\n", __func__);
+       edac_dbg(3, "init mci\n");
        mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 |
            MEM_FLAG_DDR | MEM_FLAG_DDR2;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
@@ -1041,8 +1053,6 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
 
        mci->scrub_mode = SCRUB_SW_SRC;
 
-       mpc85xx_set_mc_sysfs_attributes(mci);
-
        mpc85xx_init_csrows(mci);
 
        /* store the original error disable bits */
@@ -1054,7 +1064,13 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
        out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, ~0);
 
        if (edac_mc_add_mc(mci)) {
-               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "failed edac_mc_add_mc()\n");
+               goto err;
+       }
+
+       if (mpc85xx_create_sysfs_attributes(mci)) {
+               edac_mc_del_mc(mci->pdev);
+               edac_dbg(3, "failed edac_mc_add_mc()\n");
                goto err;
        }
 
@@ -1088,7 +1104,7 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
        }
 
        devres_remove_group(&op->dev, mpc85xx_mc_err_probe);
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
        printk(KERN_INFO EDAC_MOD_STR " MC err registered\n");
 
        return 0;
@@ -1106,7 +1122,7 @@ static int mpc85xx_mc_err_remove(struct platform_device *op)
        struct mem_ctl_info *mci = dev_get_drvdata(&op->dev);
        struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        if (edac_op_state == EDAC_OPSTATE_INT) {
                out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, 0);
@@ -1117,6 +1133,7 @@ static int mpc85xx_mc_err_remove(struct platform_device *op)
                 orig_ddr_err_disable);
        out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, orig_ddr_err_sbe);
 
+       mpc85xx_remove_sysfs_attributes(mci);
        edac_mc_del_mc(&op->dev);
        edac_mc_free(mci);
        return 0;
index b0bb5a3d2527698c1f4659997fc6950526e5e215..2b315c2edc3cac14c5247e33a398283fd098b26d 100644 (file)
@@ -169,7 +169,7 @@ static int __devinit mv64x60_pci_err_probe(struct platform_device *pdev)
                 MV64X60_PCIx_ERR_MASK_VAL);
 
        if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
-               debugf3("%s(): failed edac_pci_add_device()\n", __func__);
+               edac_dbg(3, "failed edac_pci_add_device()\n");
                goto err;
        }
 
@@ -194,7 +194,7 @@ static int __devinit mv64x60_pci_err_probe(struct platform_device *pdev)
        devres_remove_group(&pdev->dev, mv64x60_pci_err_probe);
 
        /* get this far and it's successful */
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
 
        return 0;
 
@@ -210,7 +210,7 @@ static int mv64x60_pci_err_remove(struct platform_device *pdev)
 {
        struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev);
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        edac_pci_del_device(&pdev->dev);
 
@@ -336,7 +336,7 @@ static int __devinit mv64x60_sram_err_probe(struct platform_device *pdev)
        pdata->edac_idx = edac_dev_idx++;
 
        if (edac_device_add_device(edac_dev) > 0) {
-               debugf3("%s(): failed edac_device_add_device()\n", __func__);
+               edac_dbg(3, "failed edac_device_add_device()\n");
                goto err;
        }
 
@@ -363,7 +363,7 @@ static int __devinit mv64x60_sram_err_probe(struct platform_device *pdev)
        devres_remove_group(&pdev->dev, mv64x60_sram_err_probe);
 
        /* get this far and it's successful */
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
 
        return 0;
 
@@ -379,7 +379,7 @@ static int mv64x60_sram_err_remove(struct platform_device *pdev)
 {
        struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev);
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        edac_device_del_device(&pdev->dev);
        edac_device_free_ctl_info(edac_dev);
@@ -531,7 +531,7 @@ static int __devinit mv64x60_cpu_err_probe(struct platform_device *pdev)
        pdata->edac_idx = edac_dev_idx++;
 
        if (edac_device_add_device(edac_dev) > 0) {
-               debugf3("%s(): failed edac_device_add_device()\n", __func__);
+               edac_dbg(3, "failed edac_device_add_device()\n");
                goto err;
        }
 
@@ -558,7 +558,7 @@ static int __devinit mv64x60_cpu_err_probe(struct platform_device *pdev)
        devres_remove_group(&pdev->dev, mv64x60_cpu_err_probe);
 
        /* get this far and it's successful */
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
 
        return 0;
 
@@ -574,7 +574,7 @@ static int mv64x60_cpu_err_remove(struct platform_device *pdev)
 {
        struct edac_device_ctl_info *edac_dev = platform_get_drvdata(pdev);
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        edac_device_del_device(&pdev->dev);
        edac_device_free_ctl_info(edac_dev);
@@ -611,17 +611,17 @@ static void mv64x60_mc_check(struct mem_ctl_info *mci)
 
        /* first bit clear in ECC Err Reg, 1 bit error, correctable by HW */
        if (!(reg & 0x1))
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                     err_addr >> PAGE_SHIFT,
                                     err_addr & PAGE_MASK, syndrome,
                                     0, 0, -1,
-                                    mci->ctl_name, "", NULL);
+                                    mci->ctl_name, "");
        else    /* 2 bit error, UE */
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                     err_addr >> PAGE_SHIFT,
                                     err_addr & PAGE_MASK, 0,
                                     0, 0, -1,
-                                    mci->ctl_name, "", NULL);
+                                    mci->ctl_name, "");
 
        /* clear the error */
        out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0);
@@ -670,8 +670,8 @@ static void mv64x60_init_csrows(struct mem_ctl_info *mci,
 
        ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
 
-       csrow = &mci->csrows[0];
-       dimm = csrow->channels[0].dimm;
+       csrow = mci->csrows[0];
+       dimm = csrow->channels[0]->dimm;
 
        dimm->nr_pages = pdata->total_mem >> PAGE_SHIFT;
        dimm->grain = 8;
@@ -724,7 +724,7 @@ static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
        }
 
        pdata = mci->pvt_info;
-       mci->dev = &pdev->dev;
+       mci->pdev = &pdev->dev;
        platform_set_drvdata(pdev, mci);
        pdata->name = "mv64x60_mc_err";
        pdata->irq = NO_IRQ;
@@ -766,7 +766,7 @@ static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
                goto err2;
        }
 
-       debugf3("%s(): init mci\n", __func__);
+       edac_dbg(3, "init mci\n");
        mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
        mci->edac_cap = EDAC_FLAG_SECDED;
@@ -790,7 +790,7 @@ static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
        out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL, ctl);
 
        if (edac_mc_add_mc(mci)) {
-               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "failed edac_mc_add_mc()\n");
                goto err;
        }
 
@@ -815,7 +815,7 @@ static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
        }
 
        /* get this far and it's successful */
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
 
        return 0;
 
@@ -831,7 +831,7 @@ static int mv64x60_mc_err_remove(struct platform_device *pdev)
 {
        struct mem_ctl_info *mci = platform_get_drvdata(pdev);
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        edac_mc_del_mc(&pdev->dev);
        edac_mc_free(mci);
index b095a906a994bc7b092362f21ed9f31eecf8d288..2d35b78ada3c819a5879d9357eadbb5ec2da00e7 100644 (file)
@@ -74,7 +74,7 @@ static int system_mmc_id;
 
 static u32 pasemi_edac_get_error_info(struct mem_ctl_info *mci)
 {
-       struct pci_dev *pdev = to_pci_dev(mci->dev);
+       struct pci_dev *pdev = to_pci_dev(mci->pdev);
        u32 tmp;
 
        pci_read_config_dword(pdev, MCDEBUG_ERRSTA,
@@ -95,7 +95,7 @@ static u32 pasemi_edac_get_error_info(struct mem_ctl_info *mci)
 
 static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
 {
-       struct pci_dev *pdev = to_pci_dev(mci->dev);
+       struct pci_dev *pdev = to_pci_dev(mci->pdev);
        u32 errlog1a;
        u32 cs;
 
@@ -110,16 +110,16 @@ static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
        /* uncorrectable/multi-bit errors */
        if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS |
                      MCDEBUG_ERRSTA_RFL_STATUS)) {
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
-                                    mci->csrows[cs].first_page, 0, 0,
-                                    cs, 0, -1, mci->ctl_name, "", NULL);
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
+                                    mci->csrows[cs]->first_page, 0, 0,
+                                    cs, 0, -1, mci->ctl_name, "");
        }
 
        /* correctable/single-bit errors */
        if (errsta & MCDEBUG_ERRSTA_SBE_STATUS)
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
-                                    mci->csrows[cs].first_page, 0, 0,
-                                    cs, 0, -1, mci->ctl_name, "", NULL);
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
+                                    mci->csrows[cs]->first_page, 0, 0,
+                                    cs, 0, -1, mci->ctl_name, "");
 }
 
 static void pasemi_edac_check(struct mem_ctl_info *mci)
@@ -141,8 +141,8 @@ static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
        int index;
 
        for (index = 0; index < mci->nr_csrows; index++) {
-               csrow = &mci->csrows[index];
-               dimm = csrow->channels[0].dimm;
+               csrow = mci->csrows[index];
+               dimm = csrow->channels[0]->dimm;
 
                pci_read_config_dword(pdev,
                                      MCDRAM_RANKCFG + (index * 12),
@@ -225,7 +225,7 @@ static int __devinit pasemi_edac_probe(struct pci_dev *pdev,
                MCCFG_ERRCOR_ECC_GEN_EN |
                MCCFG_ERRCOR_ECC_CRR_EN;
 
-       mci->dev = &pdev->dev;
+       mci->pdev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
        mci->edac_cap = (errcor & MCCFG_ERRCOR_ECC_GEN_EN) ?
index f3f9fed06ad7d34ec8e3607f8141da6256e88e49..bf09576359911c51f8d548b04605387c77466a1e 100644 (file)
@@ -727,10 +727,10 @@ ppc4xx_edac_handle_ce(struct mem_ctl_info *mci,
 
        for (row = 0; row < mci->nr_csrows; row++)
                if (ppc4xx_edac_check_bank_error(status, row))
-                       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+                       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                             0, 0, 0,
                                             row, 0, -1,
-                                            message, "", NULL);
+                                            message, "");
 }
 
 /**
@@ -758,10 +758,10 @@ ppc4xx_edac_handle_ue(struct mem_ctl_info *mci,
 
        for (row = 0; row < mci->nr_csrows; row++)
                if (ppc4xx_edac_check_bank_error(status, row))
-                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                             page, offset, 0,
                                             row, 0, -1,
-                                            message, "", NULL);
+                                            message, "");
 }
 
 /**
@@ -1027,9 +1027,9 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
 
        /* Initial driver pointers and private data */
 
-       mci->dev                = &op->dev;
+       mci->pdev               = &op->dev;
 
-       dev_set_drvdata(mci->dev, mci);
+       dev_set_drvdata(mci->pdev, mci);
 
        pdata                   = mci->pvt_info;
 
@@ -1334,7 +1334,7 @@ static int __devinit ppc4xx_edac_probe(struct platform_device *op)
        return 0;
 
  fail1:
-       edac_mc_del_mc(mci->dev);
+       edac_mc_del_mc(mci->pdev);
 
  fail:
        edac_mc_free(mci);
@@ -1368,7 +1368,7 @@ ppc4xx_edac_remove(struct platform_device *op)
 
        dcr_unmap(pdata->dcr_host, SDRAM_DCR_RESOURCE_LEN);
 
-       edac_mc_del_mc(mci->dev);
+       edac_mc_del_mc(mci->pdev);
        edac_mc_free(mci);
 
        return 0;
index e1cacd164f316d3821e750f106a82540e536d794..f854debd553306a6eeae079067c2a35bc6a5988d 100644 (file)
@@ -140,7 +140,7 @@ static void r82600_get_error_info(struct mem_ctl_info *mci,
 {
        struct pci_dev *pdev;
 
-       pdev = to_pci_dev(mci->dev);
+       pdev = to_pci_dev(mci->pdev);
        pci_read_config_dword(pdev, R82600_EAP, &info->eapr);
 
        if (info->eapr & BIT(0))
@@ -179,11 +179,11 @@ static int r82600_process_error_info(struct mem_ctl_info *mci,
                error_found = 1;
 
                if (handle_errors)
-                       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+                       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                             page, 0, syndrome,
                                             edac_mc_find_csrow_by_page(mci, page),
                                             0, -1,
-                                            mci->ctl_name, "", NULL);
+                                            mci->ctl_name, "");
        }
 
        if (info->eapr & BIT(1)) {      /* UE? */
@@ -191,11 +191,11 @@ static int r82600_process_error_info(struct mem_ctl_info *mci,
 
                if (handle_errors)
                        /* 82600 doesn't give enough info */
-                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                             page, 0, 0,
                                             edac_mc_find_csrow_by_page(mci, page),
                                             0, -1,
-                                            mci->ctl_name, "", NULL);
+                                            mci->ctl_name, "");
        }
 
        return error_found;
@@ -205,7 +205,7 @@ static void r82600_check(struct mem_ctl_info *mci)
 {
        struct r82600_error_info info;
 
-       debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+       edac_dbg(1, "MC%d\n", mci->mc_idx);
        r82600_get_error_info(mci, &info);
        r82600_process_error_info(mci, &info, 1);
 }
@@ -230,19 +230,19 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
        row_high_limit_last = 0;
 
        for (index = 0; index < mci->nr_csrows; index++) {
-               csrow = &mci->csrows[index];
-               dimm = csrow->channels[0].dimm;
+               csrow = mci->csrows[index];
+               dimm = csrow->channels[0]->dimm;
 
                /* find the DRAM Chip Select Base address and mask */
                pci_read_config_byte(pdev, R82600_DRBA + index, &drbar);
 
-               debugf1("%s() Row=%d DRBA = %#0x\n", __func__, index, drbar);
+               edac_dbg(1, "Row=%d DRBA = %#0x\n", index, drbar);
 
                row_high_limit = ((u32) drbar << 24);
 /*             row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */
 
-               debugf1("%s() Row=%d, Boundary Address=%#0x, Last = %#0x\n",
-                       __func__, index, row_high_limit, row_high_limit_last);
+               edac_dbg(1, "Row=%d, Boundary Address=%#0x, Last = %#0x\n",
+                        index, row_high_limit, row_high_limit_last);
 
                /* Empty row [p.57] */
                if (row_high_limit == row_high_limit_last)
@@ -277,14 +277,13 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
        u32 sdram_refresh_rate;
        struct r82600_error_info discard;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
        pci_read_config_byte(pdev, R82600_DRAMC, &dramcr);
        pci_read_config_dword(pdev, R82600_EAP, &eapr);
        scrub_disabled = eapr & BIT(31);
        sdram_refresh_rate = dramcr & (BIT(0) | BIT(1));
-       debugf2("%s(): sdram refresh rate = %#0x\n", __func__,
-               sdram_refresh_rate);
-       debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr);
+       edac_dbg(2, "sdram refresh rate = %#0x\n", sdram_refresh_rate);
+       edac_dbg(2, "DRAMC register = %#0x\n", dramcr);
        layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
        layers[0].size = R82600_NR_CSROWS;
        layers[0].is_virt_csrow = true;
@@ -295,8 +294,8 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
        if (mci == NULL)
                return -ENOMEM;
 
-       debugf0("%s(): mci = %p\n", __func__, mci);
-       mci->dev = &pdev->dev;
+       edac_dbg(0, "mci = %p\n", mci);
+       mci->pdev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
        /* FIXME try to work out if the chip leads have been used for COM2
@@ -311,8 +310,8 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
 
        if (ecc_enabled(dramcr)) {
                if (scrub_disabled)
-                       debugf3("%s(): mci = %p - Scrubbing disabled! EAP: "
-                               "%#0x\n", __func__, mci, eapr);
+                       edac_dbg(3, "mci = %p - Scrubbing disabled! EAP: %#0x\n",
+                                mci, eapr);
        } else
                mci->edac_cap = EDAC_FLAG_NONE;
 
@@ -329,15 +328,14 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
         * type of memory controller.  The ID is therefore hardcoded to 0.
         */
        if (edac_mc_add_mc(mci)) {
-               debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "failed edac_mc_add_mc()\n");
                goto fail;
        }
 
        /* get this far and it's successful */
 
        if (disable_hardware_scrub) {
-               debugf3("%s(): Disabling Hardware Scrub (scrub on error)\n",
-                       __func__);
+               edac_dbg(3, "Disabling Hardware Scrub (scrub on error)\n");
                pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31));
        }
 
@@ -352,7 +350,7 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
                        __func__);
        }
 
-       debugf3("%s(): success\n", __func__);
+       edac_dbg(3, "success\n");
        return 0;
 
 fail:
@@ -364,7 +362,7 @@ fail:
 static int __devinit r82600_init_one(struct pci_dev *pdev,
                                const struct pci_device_id *ent)
 {
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /* don't need to call pci_enable_device() */
        return r82600_probe1(pdev, ent->driver_data);
@@ -374,7 +372,7 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        if (r82600_pci)
                edac_pci_release_generic_ctl(r82600_pci);
index 36ad17e79d6183e3f21bf63f3266dc169f3941a0..f3b1f9fafa4b20b4f40917bcbab827ad760515df 100644 (file)
@@ -381,8 +381,8 @@ static inline int numrank(u32 mtr)
        int ranks = (1 << RANK_CNT_BITS(mtr));
 
        if (ranks > 4) {
-               debugf0("Invalid number of ranks: %d (max = 4) raw value = %x (%04x)",
-                       ranks, (unsigned int)RANK_CNT_BITS(mtr), mtr);
+               edac_dbg(0, "Invalid number of ranks: %d (max = 4) raw value = %x (%04x)\n",
+                        ranks, (unsigned int)RANK_CNT_BITS(mtr), mtr);
                return -EINVAL;
        }
 
@@ -394,8 +394,8 @@ static inline int numrow(u32 mtr)
        int rows = (RANK_WIDTH_BITS(mtr) + 12);
 
        if (rows < 13 || rows > 18) {
-               debugf0("Invalid number of rows: %d (should be between 14 and 17) raw value = %x (%04x)",
-                       rows, (unsigned int)RANK_WIDTH_BITS(mtr), mtr);
+               edac_dbg(0, "Invalid number of rows: %d (should be between 14 and 17) raw value = %x (%04x)\n",
+                        rows, (unsigned int)RANK_WIDTH_BITS(mtr), mtr);
                return -EINVAL;
        }
 
@@ -407,8 +407,8 @@ static inline int numcol(u32 mtr)
        int cols = (COL_WIDTH_BITS(mtr) + 10);
 
        if (cols > 12) {
-               debugf0("Invalid number of cols: %d (max = 4) raw value = %x (%04x)",
-                       cols, (unsigned int)COL_WIDTH_BITS(mtr), mtr);
+               edac_dbg(0, "Invalid number of cols: %d (max = 4) raw value = %x (%04x)\n",
+                        cols, (unsigned int)COL_WIDTH_BITS(mtr), mtr);
                return -EINVAL;
        }
 
@@ -475,8 +475,8 @@ static struct pci_dev *get_pdev_slot_func(u8 bus, unsigned slot,
 
                if (PCI_SLOT(sbridge_dev->pdev[i]->devfn) == slot &&
                    PCI_FUNC(sbridge_dev->pdev[i]->devfn) == func) {
-                       debugf1("Associated %02x.%02x.%d with %p\n",
-                               bus, slot, func, sbridge_dev->pdev[i]);
+                       edac_dbg(1, "Associated %02x.%02x.%d with %p\n",
+                                bus, slot, func, sbridge_dev->pdev[i]);
                        return sbridge_dev->pdev[i];
                }
        }
@@ -523,45 +523,45 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 
        pci_read_config_dword(pvt->pci_br, SAD_CONTROL, &reg);
        pvt->sbridge_dev->node_id = NODE_ID(reg);
-       debugf0("mc#%d: Node ID: %d, source ID: %d\n",
-               pvt->sbridge_dev->mc,
-               pvt->sbridge_dev->node_id,
-               pvt->sbridge_dev->source_id);
+       edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n",
+                pvt->sbridge_dev->mc,
+                pvt->sbridge_dev->node_id,
+                pvt->sbridge_dev->source_id);
 
        pci_read_config_dword(pvt->pci_ras, RASENABLES, &reg);
        if (IS_MIRROR_ENABLED(reg)) {
-               debugf0("Memory mirror is enabled\n");
+               edac_dbg(0, "Memory mirror is enabled\n");
                pvt->is_mirrored = true;
        } else {
-               debugf0("Memory mirror is disabled\n");
+               edac_dbg(0, "Memory mirror is disabled\n");
                pvt->is_mirrored = false;
        }
 
        pci_read_config_dword(pvt->pci_ta, MCMTR, &pvt->info.mcmtr);
        if (IS_LOCKSTEP_ENABLED(pvt->info.mcmtr)) {
-               debugf0("Lockstep is enabled\n");
+               edac_dbg(0, "Lockstep is enabled\n");
                mode = EDAC_S8ECD8ED;
                pvt->is_lockstep = true;
        } else {
-               debugf0("Lockstep is disabled\n");
+               edac_dbg(0, "Lockstep is disabled\n");
                mode = EDAC_S4ECD4ED;
                pvt->is_lockstep = false;
        }
        if (IS_CLOSE_PG(pvt->info.mcmtr)) {
-               debugf0("address map is on closed page mode\n");
+               edac_dbg(0, "address map is on closed page mode\n");
                pvt->is_close_pg = true;
        } else {
-               debugf0("address map is on open page mode\n");
+               edac_dbg(0, "address map is on open page mode\n");
                pvt->is_close_pg = false;
        }
 
        pci_read_config_dword(pvt->pci_ddrio, RANK_CFG_A, &reg);
        if (IS_RDIMM_ENABLED(reg)) {
                /* FIXME: Can also be LRDIMM */
-               debugf0("Memory is registered\n");
+               edac_dbg(0, "Memory is registered\n");
                mtype = MEM_RDDR3;
        } else {
-               debugf0("Memory is unregistered\n");
+               edac_dbg(0, "Memory is unregistered\n");
                mtype = MEM_DDR3;
        }
 
@@ -576,7 +576,7 @@ static int get_dimm_config(struct mem_ctl_info *mci)
                                       i, j, 0);
                        pci_read_config_dword(pvt->pci_tad[i],
                                              mtr_regs[j], &mtr);
-                       debugf4("Channel #%d  MTR%d = %x\n", i, j, mtr);
+                       edac_dbg(4, "Channel #%d  MTR%d = %x\n", i, j, mtr);
                        if (IS_DIMM_PRESENT(mtr)) {
                                pvt->channel[i].dimms++;
 
@@ -588,10 +588,10 @@ static int get_dimm_config(struct mem_ctl_info *mci)
                                size = (rows * cols * banks * ranks) >> (20 - 3);
                                npages = MiB_TO_PAGES(size);
 
-                               debugf0("mc#%d: channel %d, dimm %d, %d Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
-                                       pvt->sbridge_dev->mc, i, j,
-                                       size, npages,
-                                       banks, ranks, rows, cols);
+                               edac_dbg(0, "mc#%d: channel %d, dimm %d, %d Mb (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
+                                        pvt->sbridge_dev->mc, i, j,
+                                        size, npages,
+                                        banks, ranks, rows, cols);
 
                                dimm->nr_pages = npages;
                                dimm->grain = 32;
@@ -629,8 +629,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
        tmp_mb = (1 + pvt->tolm) >> 20;
 
        mb = div_u64_rem(tmp_mb, 1000, &kb);
-       debugf0("TOLM: %u.%03u GB (0x%016Lx)\n",
-               mb, kb, (u64)pvt->tolm);
+       edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tolm);
 
        /* Address range is already 45:25 */
        pci_read_config_dword(pvt->pci_sad1, TOHM,
@@ -639,8 +638,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
        tmp_mb = (1 + pvt->tohm) >> 20;
 
        mb = div_u64_rem(tmp_mb, 1000, &kb);
-       debugf0("TOHM: %u.%03u GB (0x%016Lx)",
-               mb, kb, (u64)pvt->tohm);
+       edac_dbg(0, "TOHM: %u.%03u GB (0x%016Lx)", mb, kb, (u64)pvt->tohm);
 
        /*
         * Step 2) Get SAD range and SAD Interleave list
@@ -663,13 +661,13 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 
                tmp_mb = (limit + 1) >> 20;
                mb = div_u64_rem(tmp_mb, 1000, &kb);
-               debugf0("SAD#%d %s up to %u.%03u GB (0x%016Lx) %s reg=0x%08x\n",
-                       n_sads,
-                       get_dram_attr(reg),
-                       mb, kb,
-                       ((u64)tmp_mb) << 20L,
-                       INTERLEAVE_MODE(reg) ? "Interleave: 8:6" : "Interleave: [8:6]XOR[18:16]",
-                       reg);
+               edac_dbg(0, "SAD#%d %s up to %u.%03u GB (0x%016Lx) Interleave: %s reg=0x%08x\n",
+                        n_sads,
+                        get_dram_attr(reg),
+                        mb, kb,
+                        ((u64)tmp_mb) << 20L,
+                        INTERLEAVE_MODE(reg) ? "8:6" : "[8:6]XOR[18:16]",
+                        reg);
                prv = limit;
 
                pci_read_config_dword(pvt->pci_sad0, interleave_list[n_sads],
@@ -679,8 +677,8 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                        if (j > 0 && sad_interl == sad_pkg(reg, j))
                                break;
 
-                       debugf0("SAD#%d, interleave #%d: %d\n",
-                       n_sads, j, sad_pkg(reg, j));
+                       edac_dbg(0, "SAD#%d, interleave #%d: %d\n",
+                                n_sads, j, sad_pkg(reg, j));
                }
        }
 
@@ -697,16 +695,16 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                tmp_mb = (limit + 1) >> 20;
 
                mb = div_u64_rem(tmp_mb, 1000, &kb);
-               debugf0("TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
-                       n_tads, mb, kb,
-                       ((u64)tmp_mb) << 20L,
-                       (u32)TAD_SOCK(reg),
-                       (u32)TAD_CH(reg),
-                       (u32)TAD_TGT0(reg),
-                       (u32)TAD_TGT1(reg),
-                       (u32)TAD_TGT2(reg),
-                       (u32)TAD_TGT3(reg),
-                       reg);
+               edac_dbg(0, "TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
+                        n_tads, mb, kb,
+                        ((u64)tmp_mb) << 20L,
+                        (u32)TAD_SOCK(reg),
+                        (u32)TAD_CH(reg),
+                        (u32)TAD_TGT0(reg),
+                        (u32)TAD_TGT1(reg),
+                        (u32)TAD_TGT2(reg),
+                        (u32)TAD_TGT3(reg),
+                        reg);
                prv = limit;
        }
 
@@ -722,11 +720,11 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                                              &reg);
                        tmp_mb = TAD_OFFSET(reg) >> 20;
                        mb = div_u64_rem(tmp_mb, 1000, &kb);
-                       debugf0("TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n",
-                               i, j,
-                               mb, kb,
-                               ((u64)tmp_mb) << 20L,
-                               reg);
+                       edac_dbg(0, "TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n",
+                                i, j,
+                                mb, kb,
+                                ((u64)tmp_mb) << 20L,
+                                reg);
                }
        }
 
@@ -747,12 +745,12 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                        tmp_mb = RIR_LIMIT(reg) >> 20;
                        rir_way = 1 << RIR_WAY(reg);
                        mb = div_u64_rem(tmp_mb, 1000, &kb);
-                       debugf0("CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n",
-                               i, j,
-                               mb, kb,
-                               ((u64)tmp_mb) << 20L,
-                               rir_way,
-                               reg);
+                       edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n",
+                                i, j,
+                                mb, kb,
+                                ((u64)tmp_mb) << 20L,
+                                rir_way,
+                                reg);
 
                        for (k = 0; k < rir_way; k++) {
                                pci_read_config_dword(pvt->pci_tad[i],
@@ -761,12 +759,12 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                                tmp_mb = RIR_OFFSET(reg) << 6;
 
                                mb = div_u64_rem(tmp_mb, 1000, &kb);
-                               debugf0("CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
-                                       i, j, k,
-                                       mb, kb,
-                                       ((u64)tmp_mb) << 20L,
-                                       (u32)RIR_RNK_TGT(reg),
-                                       reg);
+                               edac_dbg(0, "CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
+                                        i, j, k,
+                                        mb, kb,
+                                        ((u64)tmp_mb) << 20L,
+                                        (u32)RIR_RNK_TGT(reg),
+                                        reg);
                        }
                }
        }
@@ -853,16 +851,16 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                if (sad_way > 0 && sad_interl == sad_pkg(reg, sad_way))
                        break;
                sad_interleave[sad_way] = sad_pkg(reg, sad_way);
-               debugf0("SAD interleave #%d: %d\n",
-                       sad_way, sad_interleave[sad_way]);
+               edac_dbg(0, "SAD interleave #%d: %d\n",
+                        sad_way, sad_interleave[sad_way]);
        }
-       debugf0("mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n",
-               pvt->sbridge_dev->mc,
-               n_sads,
-               addr,
-               limit,
-               sad_way + 7,
-               interleave_mode ? "" : "XOR[18:16]");
+       edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n",
+                pvt->sbridge_dev->mc,
+                n_sads,
+                addr,
+                limit,
+                sad_way + 7,
+                interleave_mode ? "" : "XOR[18:16]");
        if (interleave_mode)
                idx = ((addr >> 6) ^ (addr >> 16)) & 7;
        else
@@ -884,8 +882,8 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                return -EINVAL;
        }
        *socket = sad_interleave[idx];
-       debugf0("SAD interleave index: %d (wayness %d) = CPU socket %d\n",
-               idx, sad_way, *socket);
+       edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n",
+                idx, sad_way, *socket);
 
        /*
         * Move to the proper node structure, in order to access the
@@ -972,16 +970,16 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 
        offset = TAD_OFFSET(tad_offset);
 
-       debugf0("TAD#%d: address 0x%016Lx < 0x%016Lx, socket interleave %d, channel interleave %d (offset 0x%08Lx), index %d, base ch: %d, ch mask: 0x%02lx\n",
-               n_tads,
-               addr,
-               limit,
-               (u32)TAD_SOCK(reg),
-               ch_way,
-               offset,
-               idx,
-               base_ch,
-               *channel_mask);
+       edac_dbg(0, "TAD#%d: address 0x%016Lx < 0x%016Lx, socket interleave %d, channel interleave %d (offset 0x%08Lx), index %d, base ch: %d, ch mask: 0x%02lx\n",
+                n_tads,
+                addr,
+                limit,
+                (u32)TAD_SOCK(reg),
+                ch_way,
+                offset,
+                idx,
+                base_ch,
+                *channel_mask);
 
        /* Calculate channel address */
        /* Remove the TAD offset */
@@ -1017,11 +1015,11 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
 
                limit = RIR_LIMIT(reg);
                mb = div_u64_rem(limit >> 20, 1000, &kb);
-               debugf0("RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
-                       n_rir,
-                       mb, kb,
-                       limit,
-                       1 << RIR_WAY(reg));
+               edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
+                        n_rir,
+                        mb, kb,
+                        limit,
+                        1 << RIR_WAY(reg));
                if  (ch_addr <= limit)
                        break;
        }
@@ -1042,12 +1040,12 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                              &reg);
        *rank = RIR_RNK_TGT(reg);
 
-       debugf0("RIR#%d: channel address 0x%08Lx < 0x%08Lx, RIR interleave %d, index %d\n",
-               n_rir,
-               ch_addr,
-               limit,
-               rir_way,
-               idx);
+       edac_dbg(0, "RIR#%d: channel address 0x%08Lx < 0x%08Lx, RIR interleave %d, index %d\n",
+                n_rir,
+                ch_addr,
+                limit,
+                rir_way,
+                idx);
 
        return 0;
 }
@@ -1064,14 +1062,14 @@ static void sbridge_put_devices(struct sbridge_dev *sbridge_dev)
 {
        int i;
 
-       debugf0(__FILE__ ": %s()\n", __func__);
+       edac_dbg(0, "\n");
        for (i = 0; i < sbridge_dev->n_devs; i++) {
                struct pci_dev *pdev = sbridge_dev->pdev[i];
                if (!pdev)
                        continue;
-               debugf0("Removing dev %02x:%02x.%d\n",
-                       pdev->bus->number,
-                       PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+               edac_dbg(0, "Removing dev %02x:%02x.%d\n",
+                        pdev->bus->number,
+                        PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
                pci_dev_put(pdev);
        }
 }
@@ -1177,10 +1175,9 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
                return -ENODEV;
        }
 
-       debugf0("Detected dev %02x:%d.%d PCI ID %04x:%04x\n",
-               bus, dev_descr->dev,
-               dev_descr->func,
-               PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+       edac_dbg(0, "Detected dev %02x:%d.%d PCI ID %04x:%04x\n",
+                bus, dev_descr->dev, dev_descr->func,
+                PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
 
        /*
         * As stated on drivers/pci/search.c, the reference count for
@@ -1297,10 +1294,10 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
                        goto error;
                }
 
-               debugf0("Associated PCI %02x.%02d.%d with dev = %p\n",
-                       sbridge_dev->bus,
-                       PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
-                       pdev);
+               edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
+                        sbridge_dev->bus,
+                        PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+                        pdev);
        }
 
        /* Check if everything were registered */
@@ -1435,8 +1432,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
         * to the group of dimm's where the error may be happening.
         */
        snprintf(msg, sizeof(msg),
-                "count:%d%s%s area:%s err_code:%04x:%04x socket:%d channel_mask:%ld rank:%d",
-                core_err_cnt,
+                "%s%s area:%s err_code:%04x:%04x socket:%d channel_mask:%ld rank:%d",
                 overflow ? " OVERFLOW" : "",
                 (uncorrected_error && recoverable) ? " recoverable" : "",
                 area_type,
@@ -1445,20 +1441,20 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
                 channel_mask,
                 rank);
 
-       debugf0("%s", msg);
+       edac_dbg(0, "%s\n", msg);
 
        /* FIXME: need support for channel mask */
 
        /* Call the helper to output message */
-       edac_mc_handle_error(tp_event, mci,
+       edac_mc_handle_error(tp_event, mci, core_err_cnt,
                             m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
                             channel, dimm, -1,
-                            optype, msg, m);
+                            optype, msg);
        return;
 err_parsing:
-       edac_mc_handle_error(tp_event, mci, 0, 0, 0,
+       edac_mc_handle_error(tp_event, mci, core_err_cnt, 0, 0, 0,
                             -1, -1, -1,
-                            msg, "", m);
+                            msg, "");
 
 }
 
@@ -1592,8 +1588,7 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)
        struct sbridge_pvt *pvt;
 
        if (unlikely(!mci || !mci->pvt_info)) {
-               debugf0("MC: " __FILE__ ": %s(): dev = %p\n",
-                       __func__, &sbridge_dev->pdev[0]->dev);
+               edac_dbg(0, "MC: dev = %p\n", &sbridge_dev->pdev[0]->dev);
 
                sbridge_printk(KERN_ERR, "Couldn't find mci handler\n");
                return;
@@ -1601,13 +1596,13 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)
 
        pvt = mci->pvt_info;
 
-       debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
-               __func__, mci, &sbridge_dev->pdev[0]->dev);
+       edac_dbg(0, "MC: mci = %p, dev = %p\n",
+                mci, &sbridge_dev->pdev[0]->dev);
 
        /* Remove MC sysfs nodes */
-       edac_mc_del_mc(mci->dev);
+       edac_mc_del_mc(mci->pdev);
 
-       debugf1("%s: free mci struct\n", mci->ctl_name);
+       edac_dbg(1, "%s: free mci struct\n", mci->ctl_name);
        kfree(mci->ctl_name);
        edac_mc_free(mci);
        sbridge_dev->mci = NULL;
@@ -1638,8 +1633,8 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
        if (unlikely(!mci))
                return -ENOMEM;
 
-       debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
-               __func__, mci, &sbridge_dev->pdev[0]->dev);
+       edac_dbg(0, "MC: mci = %p, dev = %p\n",
+                mci, &sbridge_dev->pdev[0]->dev);
 
        pvt = mci->pvt_info;
        memset(pvt, 0, sizeof(*pvt));
@@ -1670,12 +1665,11 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
        get_memory_layout(mci);
 
        /* record ptr to the generic device */
-       mci->dev = &sbridge_dev->pdev[0]->dev;
+       mci->pdev = &sbridge_dev->pdev[0]->dev;
 
        /* add this new MC control structure to EDAC's list of MCs */
        if (unlikely(edac_mc_add_mc(mci))) {
-               debugf0("MC: " __FILE__
-                       ": %s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
                rc = -EINVAL;
                goto fail0;
        }
@@ -1722,7 +1716,8 @@ static int __devinit sbridge_probe(struct pci_dev *pdev,
        mc = 0;
 
        list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {
-               debugf0("Registering MC#%d (%d of %d)\n", mc, mc + 1, num_mc);
+               edac_dbg(0, "Registering MC#%d (%d of %d)\n",
+                        mc, mc + 1, num_mc);
                sbridge_dev->mc = mc++;
                rc = sbridge_register_mci(sbridge_dev);
                if (unlikely(rc < 0))
@@ -1752,7 +1747,7 @@ static void __devexit sbridge_remove(struct pci_dev *pdev)
 {
        struct sbridge_dev *sbridge_dev;
 
-       debugf0(__FILE__ ": %s()\n", __func__);
+       edac_dbg(0, "\n");
 
        /*
         * we have a trouble here: pdev value for removal will be wrong, since
@@ -1801,7 +1796,7 @@ static int __init sbridge_init(void)
 {
        int pci_rc;
 
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       edac_dbg(2, "\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -1825,7 +1820,7 @@ static int __init sbridge_init(void)
  */
 static void __exit sbridge_exit(void)
 {
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       edac_dbg(2, "\n");
        pci_unregister_driver(&sbridge_driver);
        mce_unregister_decode_chain(&sbridge_mce_dec);
 }
index 7bb4614730db846445909d460a5b5a0953d8ab50..1e904b7b79a042671c83bb10e07547bfcf3eee12 100644 (file)
@@ -69,12 +69,12 @@ static void tile_edac_check(struct mem_ctl_info *mci)
 
        /* Check if the current error count is different from the saved one. */
        if (mem_error.sbe_count != priv->ce_count) {
-               dev_dbg(mci->dev, "ECC CE err on node %d\n", priv->node);
+               dev_dbg(mci->pdev, "ECC CE err on node %d\n", priv->node);
                priv->ce_count = mem_error.sbe_count;
-               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                     0, 0, 0,
                                     0, 0, -1,
-                                    mci->ctl_name, "", NULL);
+                                    mci->ctl_name, "");
        }
 }
 
@@ -84,10 +84,10 @@ static void tile_edac_check(struct mem_ctl_info *mci)
  */
 static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci)
 {
-       struct csrow_info       *csrow = &mci->csrows[0];
+       struct csrow_info       *csrow = mci->csrows[0];
        struct tile_edac_priv   *priv = mci->pvt_info;
        struct mshim_mem_info   mem_info;
-       struct dimm_info *dimm = csrow->channels[0].dimm;
+       struct dimm_info *dimm = csrow->channels[0]->dimm;
 
        if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_info,
                sizeof(struct mshim_mem_info), MSHIM_MEM_INFO_OFF) !=
@@ -149,7 +149,7 @@ static int __devinit tile_edac_mc_probe(struct platform_device *pdev)
        priv->node = pdev->id;
        priv->hv_devhdl = hv_devhdl;
 
-       mci->dev = &pdev->dev;
+       mci->pdev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_DDR2;
        mci->edac_ctl_cap = EDAC_FLAG_SECDED;
 
index 1ac7962d63eadcd5ba8ddd17ae58b96b9a062e2e..08a992693e62ed8b7e994782ce824945001f220a 100644 (file)
@@ -103,10 +103,10 @@ static int how_many_channel(struct pci_dev *pdev)
 
        pci_read_config_byte(pdev, X38_CAPID0 + 8, &capid0_8b);
        if (capid0_8b & 0x20) { /* check DCD: Dual Channel Disable */
-               debugf0("In single channel mode.\n");
+               edac_dbg(0, "In single channel mode\n");
                x38_channel_num = 1;
        } else {
-               debugf0("In dual channel mode.\n");
+               edac_dbg(0, "In dual channel mode\n");
                x38_channel_num = 2;
        }
 
@@ -151,7 +151,7 @@ static void x38_clear_error_info(struct mem_ctl_info *mci)
 {
        struct pci_dev *pdev;
 
-       pdev = to_pci_dev(mci->dev);
+       pdev = to_pci_dev(mci->pdev);
 
        /*
         * Clear any error bits.
@@ -172,7 +172,7 @@ static void x38_get_and_clear_error_info(struct mem_ctl_info *mci,
        struct pci_dev *pdev;
        void __iomem *window = mci->pvt_info;
 
-       pdev = to_pci_dev(mci->dev);
+       pdev = to_pci_dev(mci->pdev);
 
        /*
         * This is a mess because there is no atomic way to read all the
@@ -215,26 +215,26 @@ static void x38_process_error_info(struct mem_ctl_info *mci,
                return;
 
        if ((info->errsts ^ info->errsts2) & X38_ERRSTS_BITS) {
-               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
+               edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
                                     -1, -1, -1,
-                                    "UE overwrote CE", "", NULL);
+                                    "UE overwrote CE", "");
                info->errsts = info->errsts2;
        }
 
        for (channel = 0; channel < x38_channel_num; channel++) {
                log = info->eccerrlog[channel];
                if (log & X38_ECCERRLOG_UE) {
-                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+                       edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
                                             0, 0, 0,
                                             eccerrlog_row(channel, log),
                                             -1, -1,
-                                            "x38 UE", "", NULL);
+                                            "x38 UE", "");
                } else if (log & X38_ECCERRLOG_CE) {
-                       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+                       edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
                                             0, 0, eccerrlog_syndrome(log),
                                             eccerrlog_row(channel, log),
                                             -1, -1,
-                                            "x38 CE", "", NULL);
+                                            "x38 CE", "");
                }
        }
 }
@@ -243,7 +243,7 @@ static void x38_check(struct mem_ctl_info *mci)
 {
        struct x38_error_info info;
 
-       debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+       edac_dbg(1, "MC%d\n", mci->mc_idx);
        x38_get_and_clear_error_info(mci, &info);
        x38_process_error_info(mci, &info);
 }
@@ -331,7 +331,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
        bool stacked;
        void __iomem *window;
 
-       debugf0("MC: %s()\n", __func__);
+       edac_dbg(0, "MC:\n");
 
        window = x38_map_mchbar(pdev);
        if (!window)
@@ -352,9 +352,9 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
        if (!mci)
                return -ENOMEM;
 
-       debugf3("MC: %s(): init mci\n", __func__);
+       edac_dbg(3, "MC: init mci\n");
 
-       mci->dev = &pdev->dev;
+       mci->pdev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_DDR2;
 
        mci->edac_ctl_cap = EDAC_FLAG_SECDED;
@@ -378,7 +378,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
         */
        for (i = 0; i < mci->nr_csrows; i++) {
                unsigned long nr_pages;
-               struct csrow_info *csrow = &mci->csrows[i];
+               struct csrow_info *csrow = mci->csrows[i];
 
                nr_pages = drb_to_nr_pages(drbs, stacked,
                        i / X38_RANKS_PER_CHANNEL,
@@ -388,7 +388,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
                        continue;
 
                for (j = 0; j < x38_channel_num; j++) {
-                       struct dimm_info *dimm = csrow->channels[j].dimm;
+                       struct dimm_info *dimm = csrow->channels[j]->dimm;
 
                        dimm->nr_pages = nr_pages / x38_channel_num;
                        dimm->grain = nr_pages << PAGE_SHIFT;
@@ -402,12 +402,12 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 
        rc = -ENODEV;
        if (edac_mc_add_mc(mci)) {
-               debugf3("MC: %s(): failed edac_mc_add_mc()\n", __func__);
+               edac_dbg(3, "MC: failed edac_mc_add_mc()\n");
                goto fail;
        }
 
        /* get this far and it's successful */
-       debugf3("MC: %s(): success\n", __func__);
+       edac_dbg(3, "MC: success\n");
        return 0;
 
 fail:
@@ -423,7 +423,7 @@ static int __devinit x38_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("MC: %s()\n", __func__);
+       edac_dbg(0, "MC:\n");
 
        if (pci_enable_device(pdev) < 0)
                return -EIO;
@@ -439,7 +439,7 @@ static void __devexit x38_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0("%s()\n", __func__);
+       edac_dbg(0, "\n");
 
        mci = edac_mc_del_mc(&pdev->dev);
        if (!mci)
@@ -472,7 +472,7 @@ static int __init x38_init(void)
 {
        int pci_rc;
 
-       debugf3("MC: %s()\n", __func__);
+       edac_dbg(3, "MC:\n");
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -486,14 +486,14 @@ static int __init x38_init(void)
                mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                        PCI_DEVICE_ID_INTEL_X38_HB, NULL);
                if (!mci_pdev) {
-                       debugf0("x38 pci_get_device fail\n");
+                       edac_dbg(0, "x38 pci_get_device fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
 
                pci_rc = x38_init_one(mci_pdev, x38_pci_tbl);
                if (pci_rc < 0) {
-                       debugf0("x38 init fail\n");
+                       edac_dbg(0, "x38 init fail\n");
                        pci_rc = -ENODEV;
                        goto fail1;
                }
@@ -513,7 +513,7 @@ fail0:
 
 static void __exit x38_exit(void)
 {
-       debugf3("MC: %s()\n", __func__);
+       edac_dbg(3, "MC:\n");
 
        pci_unregister_driver(&x38_driver);
        if (!x38_registered) {
index 16716356d1fee89dc4344c08bd0d11b57b87bf85..e175c8ed4ec47667fd9f09514ed2801b51e2c21d 100644 (file)
@@ -33,7 +33,7 @@ config EXTCON_MAX77693
 
 config EXTCON_MAX8997
        tristate "MAX8997 EXTCON Support"
-       depends on MFD_MAX8997
+       depends on MFD_MAX8997 && IRQ_DOMAIN
        help
          If you say yes here you get support for the MUIC device of
          Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory
index a4ed30bd9a4182c26168bd3bbc81b206641739a2..ef9090a4271ddc00ee6d735c2c4b48051e5c09f3 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/mfd/max8997.h>
 #include <linux/mfd/max8997-private.h>
 #include <linux/extcon.h>
+#include <linux/irqdomain.h>
 
 #define        DEV_NAME                        "max8997-muic"
 
@@ -77,6 +78,7 @@
 struct max8997_muic_irq {
        unsigned int irq;
        const char *name;
+       unsigned int virq;
 };
 
 static struct max8997_muic_irq muic_irqs[] = {
@@ -343,12 +345,10 @@ static void max8997_muic_irq_work(struct work_struct *work)
 {
        struct max8997_muic_info *info = container_of(work,
                        struct max8997_muic_info, irq_work);
-       struct max8997_dev *max8997 = i2c_get_clientdata(info->muic);
        u8 status[2];
        u8 adc, chg_type;
-
-       int irq_type = info->irq - max8997->irq_base;
-       int ret;
+       int irq_type = 0;
+       int i, ret;
 
        mutex_lock(&info->mutex);
 
@@ -363,6 +363,10 @@ static void max8997_muic_irq_work(struct work_struct *work)
        dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__,
                        status[0], status[1]);
 
+       for (i = 0 ; i < ARRAY_SIZE(muic_irqs) ; i++)
+               if (info->irq == muic_irqs[i].virq)
+                       irq_type = muic_irqs[i].irq;
+
        switch (irq_type) {
        case MAX8997_MUICIRQ_ADC:
                adc = status[0] & STATUS1_ADC_MASK;
@@ -448,11 +452,15 @@ static int __devinit max8997_muic_probe(struct platform_device *pdev)
 
        for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
                struct max8997_muic_irq *muic_irq = &muic_irqs[i];
+               int virq = 0;
+
+               virq = irq_create_mapping(max8997->irq_domain, muic_irq->irq);
+               if (!virq)
+                       goto err_irq;
+               muic_irq->virq = virq;
 
-               ret = request_threaded_irq(pdata->irq_base + muic_irq->irq,
-                               NULL, max8997_muic_irq_handler,
-                               0, muic_irq->name,
-                               info);
+               ret = request_threaded_irq(virq, NULL,max8997_muic_irq_handler,
+                               0, muic_irq->name, info);
                if (ret) {
                        dev_err(&pdev->dev,
                                "failed: irq request (IRQ: %d,"
@@ -496,7 +504,7 @@ err_extcon:
        kfree(info->edev);
 err_irq:
        while (--i >= 0)
-               free_irq(pdata->irq_base + muic_irqs[i].irq, info);
+               free_irq(muic_irqs[i].virq, info);
        kfree(info);
 err_kfree:
        return ret;
@@ -505,11 +513,10 @@ err_kfree:
 static int __devexit max8997_muic_remove(struct platform_device *pdev)
 {
        struct max8997_muic_info *info = platform_get_drvdata(pdev);
-       struct max8997_dev *max8997 = i2c_get_clientdata(info->muic);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
-               free_irq(max8997->irq_base + muic_irqs[i].irq, info);
+               free_irq(muic_irqs[i].virq, info);
        cancel_work_sync(&info->irq_work);
 
        extcon_dev_unregister(info->edev);
index 4d460ef871610d6309a47561bf0c531344e2b7cd..7a05fd24d68b9c126719ac320620dee9343f49a4 100644 (file)
@@ -398,6 +398,14 @@ static ssize_t guid_show(struct device *dev,
        return ret;
 }
 
+static ssize_t is_local_show(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       struct fw_device *device = fw_device(dev);
+
+       return sprintf(buf, "%u\n", device->is_local);
+}
+
 static int units_sprintf(char *buf, const u32 *directory)
 {
        struct fw_csr_iterator ci;
@@ -447,6 +455,7 @@ static ssize_t units_show(struct device *dev,
 static struct device_attribute fw_device_attributes[] = {
        __ATTR_RO(config_rom),
        __ATTR_RO(guid),
+       __ATTR_RO(is_local),
        __ATTR_RO(units),
        __ATTR_NULL,
 };
index 8382e27e9a271877c98d24ff6268f9d578738b47..38c0aa60b2cb1a53da46547e5bc188a87db1f18b 100644 (file)
@@ -146,7 +146,7 @@ EXPORT_SYMBOL(fw_iso_buffer_destroy);
 /* Convert DMA address to offset into virtually contiguous buffer. */
 size_t fw_iso_buffer_lookup(struct fw_iso_buffer *buffer, dma_addr_t completed)
 {
-       int i;
+       size_t i;
        dma_addr_t address;
        ssize_t offset;
 
index 780708dc6e25f39a9cd181e3a1c0f075ad8f96ee..87d6f2d2f02d015a030cad4001fd59bebeeea9a4 100644 (file)
@@ -525,9 +525,10 @@ const struct fw_address_region fw_high_memory_region =
        { .start = 0x000100000000ULL, .end = 0xffffe0000000ULL,  };
 EXPORT_SYMBOL(fw_high_memory_region);
 
-#if 0
-const struct fw_address_region fw_low_memory_region =
+static const struct fw_address_region low_memory_region =
        { .start = 0x000000000000ULL, .end = 0x000100000000ULL,  };
+
+#if 0
 const struct fw_address_region fw_private_region =
        { .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL,  };
 const struct fw_address_region fw_csr_region =
@@ -1198,6 +1199,23 @@ static struct fw_address_handler registers = {
        .address_callback       = handle_registers,
 };
 
+static void handle_low_memory(struct fw_card *card, struct fw_request *request,
+               int tcode, int destination, int source, int generation,
+               unsigned long long offset, void *payload, size_t length,
+               void *callback_data)
+{
+       /*
+        * This catches requests not handled by the physical DMA unit,
+        * i.e., wrong transaction types or unauthorized source nodes.
+        */
+       fw_send_response(card, request, RCODE_TYPE_ERROR);
+}
+
+static struct fw_address_handler low_memory = {
+       .length                 = 0x000100000000ULL,
+       .address_callback       = handle_low_memory,
+};
+
 MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
 MODULE_DESCRIPTION("Core IEEE1394 transaction logic");
 MODULE_LICENSE("GPL");
@@ -1259,6 +1277,7 @@ static int __init fw_core_init(void)
 
        fw_core_add_address_handler(&topology_map, &topology_map_region);
        fw_core_add_address_handler(&registers, &registers_region);
+       fw_core_add_address_handler(&low_memory, &low_memory_region);
        fw_core_add_descriptor(&vendor_id_descriptor);
        fw_core_add_descriptor(&model_id_descriptor);
 
index c1af05e834b610e98acba423c6e811239c9d908e..c788dbdaf3bc6b51f779079909e339d26b063e25 100644 (file)
@@ -191,6 +191,7 @@ struct fw_ohci {
        unsigned quirks;
        unsigned int pri_req_max;
        u32 bus_time;
+       bool bus_time_running;
        bool is_root;
        bool csr_state_setclear_abdicate;
        int n_ir;
@@ -1726,6 +1727,13 @@ static u32 update_bus_time(struct fw_ohci *ohci)
 {
        u32 cycle_time_seconds = get_cycle_time(ohci) >> 25;
 
+       if (unlikely(!ohci->bus_time_running)) {
+               reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_cycle64Seconds);
+               ohci->bus_time = (lower_32_bits(get_seconds()) & ~0x7f) |
+                                (cycle_time_seconds & 0x40);
+               ohci->bus_time_running = true;
+       }
+
        if ((ohci->bus_time & 0x40) != (cycle_time_seconds & 0x40))
                ohci->bus_time += 0x40;
 
@@ -2213,7 +2221,7 @@ static int ohci_enable(struct fw_card *card,
 {
        struct fw_ohci *ohci = fw_ohci(card);
        struct pci_dev *dev = to_pci_dev(card->device);
-       u32 lps, seconds, version, irqs;
+       u32 lps, version, irqs;
        int i, ret;
 
        if (software_reset(ohci)) {
@@ -2269,9 +2277,12 @@ static int ohci_enable(struct fw_card *card,
                  (OHCI1394_MAX_PHYS_RESP_RETRIES << 8) |
                  (200 << 16));
 
-       seconds = lower_32_bits(get_seconds());
-       reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25);
-       ohci->bus_time = seconds & ~0x3f;
+       ohci->bus_time_running = false;
+
+       for (i = 0; i < 32; i++)
+               if (ohci->ir_context_support & (1 << i))
+                       reg_write(ohci, OHCI1394_IsoRcvContextControlClear(i),
+                                 IR_CONTEXT_MULTI_CHANNEL_MODE);
 
        version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
        if (version >= OHCI_VERSION_1_1) {
@@ -2369,7 +2380,6 @@ static int ohci_enable(struct fw_card *card,
                OHCI1394_postedWriteErr |
                OHCI1394_selfIDComplete |
                OHCI1394_regAccessFail |
-               OHCI1394_cycle64Seconds |
                OHCI1394_cycleInconsistent |
                OHCI1394_unrecoverableError |
                OHCI1394_cycleTooLong |
@@ -2658,7 +2668,8 @@ static void ohci_write_csr(struct fw_card *card, int csr_offset, u32 value)
 
        case CSR_BUS_TIME:
                spin_lock_irqsave(&ohci->lock, flags);
-               ohci->bus_time = (ohci->bus_time & 0x7f) | (value & ~0x7f);
+               ohci->bus_time = (update_bus_time(ohci) & 0x40) |
+                                (value & ~0x7f);
                spin_unlock_irqrestore(&ohci->lock, flags);
                break;
 
@@ -3539,6 +3550,13 @@ static int __devinit pci_probe(struct pci_dev *dev,
 
        INIT_WORK(&ohci->bus_reset_work, bus_reset_work);
 
+       if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM) ||
+           pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE) {
+               dev_err(&dev->dev, "invalid MMIO resource\n");
+               err = -ENXIO;
+               goto fail_disable;
+       }
+
        err = pci_request_region(dev, 0, ohci_driver_name);
        if (err) {
                dev_err(&dev->dev, "MMIO resource unavailable\n");
index adc07102a20d0caef9fc98290f25be6c5b2b6a3d..c1cdc9236666f60ee6891206f5a1f90bba2c4a0f 100644 (file)
@@ -98,7 +98,7 @@ static LIST_HEAD(map_entries);
 /**
  * firmware_map_add_entry() - Does the real work to add a firmware memmap entry.
  * @start: Start of the memory range.
- * @end:   End of the memory range (inclusive).
+ * @end:   End of the memory range (exclusive).
  * @type:  Type of the memory range.
  * @entry: Pre-allocated (either kmalloc() or bootmem allocator), uninitialised
  *         entry.
@@ -113,7 +113,7 @@ static int firmware_map_add_entry(u64 start, u64 end,
        BUG_ON(start > end);
 
        entry->start = start;
-       entry->end = end;
+       entry->end = end - 1;
        entry->type = type;
        INIT_LIST_HEAD(&entry->list);
        kobject_init(&entry->kobj, &memmap_ktype);
@@ -148,7 +148,7 @@ static int add_sysfs_fw_map_entry(struct firmware_map_entry *entry)
  * firmware_map_add_hotplug() - Adds a firmware mapping entry when we do
  * memory hotplug.
  * @start: Start of the memory range.
- * @end:   End of the memory range (inclusive).
+ * @end:   End of the memory range (exclusive)
  * @type:  Type of the memory range.
  *
  * Adds a firmware mapping entry. This function is for memory hotplug, it is
@@ -175,7 +175,7 @@ int __meminit firmware_map_add_hotplug(u64 start, u64 end, const char *type)
 /**
  * firmware_map_add_early() - Adds a firmware mapping entry.
  * @start: Start of the memory range.
- * @end:   End of the memory range (inclusive).
+ * @end:   End of the memory range.
  * @type:  Type of the memory range.
  *
  * Adds a firmware mapping entry. This function uses the bootmem allocator
index 51e0e2d8fac6345859e1c7083c7a3c86a9b5add3..a330492e06f9597e9d8abcf82561b248bee1753c 100644 (file)
@@ -95,7 +95,7 @@ efi_setup_pcdp_console(char *cmdline)
        if (efi.hcdp == EFI_INVALID_TABLE_ADDR)
                return -ENODEV;
 
-       pcdp = ioremap(efi.hcdp, 4096);
+       pcdp = early_ioremap(efi.hcdp, 4096);
        printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, efi.hcdp);
 
        if (strstr(cmdline, "console=hcdp")) {
@@ -131,6 +131,6 @@ efi_setup_pcdp_console(char *cmdline)
        }
 
 out:
-       iounmap(pcdp);
+       early_iounmap(pcdp, 4096);
        return rc;
 }
index 502b5ea43f4fae28db5a9eb65f3c37d0daf52e69..b16c8a72a2e241a8a47c524564a02c48a5389b35 100644 (file)
@@ -597,6 +597,13 @@ config GPIO_AB8500
        help
          Select this to enable the AB8500 IC GPIO driver
 
+config GPIO_TPS6586X
+       bool "TPS6586X GPIO"
+       depends on MFD_TPS6586X
+       help
+         Select this option to enable GPIO driver for the TPS6586X
+         chip family.
+
 config GPIO_TPS65910
        bool "TPS65910 GPIO"
        depends on MFD_TPS65910
index d37048105a87328c96f5b56a4bb5f1abf1812011..153caceeb0530df7a7e5932421b7f2d48fee3780 100644 (file)
@@ -63,6 +63,7 @@ obj-$(CONFIG_GPIO_TC3589X)    += gpio-tc3589x.o
 obj-$(CONFIG_ARCH_TEGRA)       += gpio-tegra.o
 obj-$(CONFIG_GPIO_TIMBERDALE)  += gpio-timberdale.o
 obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o
+obj-$(CONFIG_GPIO_TPS6586X)    += gpio-tps6586x.o
 obj-$(CONFIG_GPIO_TPS65910)    += gpio-tps65910.o
 obj-$(CONFIG_GPIO_TPS65912)    += gpio-tps65912.o
 obj-$(CONFIG_GPIO_TWL4030)     += gpio-twl4030.o
diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c
new file mode 100644 (file)
index 0000000..2526b3b
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * TI TPS6586x GPIO driver
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * Based on tps6586x.c
+ * Copyright (c) 2010 CompuLab Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/tps6586x.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+/* GPIO control registers */
+#define TPS6586X_GPIOSET1      0x5d
+#define TPS6586X_GPIOSET2      0x5e
+
+struct tps6586x_gpio {
+       struct gpio_chip gpio_chip;
+       struct device *parent;
+};
+
+static inline struct tps6586x_gpio *to_tps6586x_gpio(struct gpio_chip *chip)
+{
+       return container_of(chip, struct tps6586x_gpio, gpio_chip);
+}
+
+static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+       struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc);
+       uint8_t val;
+       int ret;
+
+       ret = tps6586x_read(tps6586x_gpio->parent, TPS6586X_GPIOSET2, &val);
+       if (ret)
+               return ret;
+
+       return !!(val & (1 << offset));
+}
+
+static void tps6586x_gpio_set(struct gpio_chip *gc, unsigned offset,
+                             int value)
+{
+       struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc);
+
+       tps6586x_update(tps6586x_gpio->parent, TPS6586X_GPIOSET2,
+                       value << offset, 1 << offset);
+}
+
+static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
+                               int value)
+{
+       struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc);
+       uint8_t val, mask;
+
+       tps6586x_gpio_set(gc, offset, value);
+
+       val = 0x1 << (offset * 2);
+       mask = 0x3 << (offset * 2);
+
+       return tps6586x_update(tps6586x_gpio->parent, TPS6586X_GPIOSET1,
+                               val, mask);
+}
+
+static int __devinit tps6586x_gpio_probe(struct platform_device *pdev)
+{
+       struct tps6586x_platform_data *pdata;
+       struct tps6586x_gpio *tps6586x_gpio;
+       int ret;
+
+       pdata = dev_get_platdata(pdev->dev.parent);
+       tps6586x_gpio = devm_kzalloc(&pdev->dev,
+                               sizeof(*tps6586x_gpio), GFP_KERNEL);
+       if (!tps6586x_gpio) {
+               dev_err(&pdev->dev, "Could not allocate tps6586x_gpio\n");
+               return -ENOMEM;
+       }
+
+       tps6586x_gpio->parent = pdev->dev.parent;
+
+       tps6586x_gpio->gpio_chip.owner = THIS_MODULE;
+       tps6586x_gpio->gpio_chip.label = pdev->name;
+       tps6586x_gpio->gpio_chip.dev = &pdev->dev;
+       tps6586x_gpio->gpio_chip.ngpio = 4;
+       tps6586x_gpio->gpio_chip.can_sleep = 1;
+
+       /* FIXME: add handling of GPIOs as dedicated inputs */
+       tps6586x_gpio->gpio_chip.direction_output = tps6586x_gpio_output;
+       tps6586x_gpio->gpio_chip.set    = tps6586x_gpio_set;
+       tps6586x_gpio->gpio_chip.get    = tps6586x_gpio_get;
+
+#ifdef CONFIG_OF_GPIO
+       tps6586x_gpio->gpio_chip.of_node = pdev->dev.parent->of_node;
+#endif
+       if (pdata && pdata->gpio_base)
+               tps6586x_gpio->gpio_chip.base = pdata->gpio_base;
+       else
+               tps6586x_gpio->gpio_chip.base = -1;
+
+       ret = gpiochip_add(&tps6586x_gpio->gpio_chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, tps6586x_gpio);
+
+       return ret;
+}
+
+static int __devexit tps6586x_gpio_remove(struct platform_device *pdev)
+{
+       struct tps6586x_gpio *tps6586x_gpio = platform_get_drvdata(pdev);
+
+       return gpiochip_remove(&tps6586x_gpio->gpio_chip);
+}
+
+static struct platform_driver tps6586x_gpio_driver = {
+       .driver.name    = "tps6586x-gpio",
+       .driver.owner   = THIS_MODULE,
+       .probe          = tps6586x_gpio_probe,
+       .remove         = __devexit_p(tps6586x_gpio_remove),
+};
+
+static int __init tps6586x_gpio_init(void)
+{
+       return platform_driver_register(&tps6586x_gpio_driver);
+}
+subsys_initcall(tps6586x_gpio_init);
+
+static void __exit tps6586x_gpio_exit(void)
+{
+       platform_driver_unregister(&tps6586x_gpio_driver);
+}
+module_exit(tps6586x_gpio_exit);
+
+MODULE_ALIAS("platform:tps6586x-gpio");
+MODULE_DESCRIPTION("GPIO interface for TPS6586X PMIC");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_LICENSE("GPL");
index bf791fa0e50d06311b98379aa550a2444051b191..d9568198c3008b1518096c92ee5ac54f77a70676 100644 (file)
@@ -196,7 +196,8 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
        return ret;
 }
 
-struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
+static struct drm_encoder *exynos_drm_best_encoder(
+                                               struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct exynos_drm_connector *exynos_connector =
index eaf630dc5dba951e78f8a68c2d0bcc1b25ae40b3..84dd099eae3b93cfa49e733d42353e1a0d0e12e4 100644 (file)
@@ -33,7 +33,6 @@
 #include "exynos_drm_fbdev.h"
 
 static LIST_HEAD(exynos_drm_subdrv_list);
-static struct drm_device *drm_dev;
 
 static int exynos_drm_subdrv_probe(struct drm_device *dev,
                                        struct exynos_drm_subdrv *subdrv)
@@ -120,8 +119,6 @@ int exynos_drm_device_register(struct drm_device *dev)
        if (!dev)
                return -EINVAL;
 
-       drm_dev = dev;
-
        list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
                subdrv->drm_dev = dev;
                err = exynos_drm_subdrv_probe(dev, subdrv);
@@ -149,8 +146,6 @@ int exynos_drm_device_unregister(struct drm_device *dev)
        list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list)
                exynos_drm_subdrv_remove(dev, subdrv);
 
-       drm_dev = NULL;
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
index 32a34c85899bb08aa0cf95d492830af66af6041c..abb1e2f8227f3304a88b475bcc3190dec81be8c8 100644 (file)
 #include "drmP.h"
 #include "drm_crtc_helper.h"
 
-#include "exynos_drm_crtc.h"
 #include "exynos_drm_drv.h"
-#include "exynos_drm_fb.h"
 #include "exynos_drm_encoder.h"
-#include "exynos_drm_gem.h"
+#include "exynos_drm_plane.h"
 
 #define to_exynos_crtc(x)      container_of(x, struct exynos_drm_crtc,\
                                drm_crtc)
 
+enum exynos_crtc_mode {
+       CRTC_MODE_NORMAL,       /* normal mode */
+       CRTC_MODE_BLANK,        /* The private plane of crtc is blank */
+};
+
 /*
  * Exynos specific crtc structure.
  *
  * @drm_crtc: crtc object.
- * @overlay: contain information common to display controller and hdmi and
- *     contents of this overlay object would be copied to sub driver size.
+ * @drm_plane: pointer of private plane object for this crtc
  * @pipe: a crtc index created at load() with a new crtc object creation
  *     and the crtc object would be set to private->crtc array
  *     to get a crtc object corresponding to this pipe from private->crtc
  *     we can refer to the crtc to current hardware interrupt occured through
  *     this pipe value.
  * @dpms: store the crtc dpms value
+ * @mode: store the crtc mode value
  */
 struct exynos_drm_crtc {
        struct drm_crtc                 drm_crtc;
-       struct exynos_drm_overlay       overlay;
+       struct drm_plane                *plane;
        unsigned int                    pipe;
        unsigned int                    dpms;
+       enum exynos_crtc_mode           mode;
 };
 
-static void exynos_drm_crtc_apply(struct drm_crtc *crtc)
-{
-       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-       struct exynos_drm_overlay *overlay = &exynos_crtc->overlay;
-
-       exynos_drm_fn_encoder(crtc, overlay,
-                       exynos_drm_encoder_crtc_mode_set);
-       exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
-                       exynos_drm_encoder_crtc_commit);
-}
-
-int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
-                             struct drm_framebuffer *fb,
-                             struct drm_display_mode *mode,
-                             struct exynos_drm_crtc_pos *pos)
-{
-       struct exynos_drm_gem_buf *buffer;
-       unsigned int actual_w;
-       unsigned int actual_h;
-       int nr = exynos_drm_format_num_buffers(fb->pixel_format);
-       int i;
-
-       for (i = 0; i < nr; i++) {
-               buffer = exynos_drm_fb_buffer(fb, i);
-               if (!buffer) {
-                       DRM_LOG_KMS("buffer is null\n");
-                       return -EFAULT;
-               }
-
-               overlay->dma_addr[i] = buffer->dma_addr;
-               overlay->vaddr[i] = buffer->kvaddr;
-
-               DRM_DEBUG_KMS("buffer: %d, vaddr = 0x%lx, dma_addr = 0x%lx\n",
-                               i, (unsigned long)overlay->vaddr[i],
-                               (unsigned long)overlay->dma_addr[i]);
-       }
-
-       actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w);
-       actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h);
-
-       /* set drm framebuffer data. */
-       overlay->fb_x = pos->fb_x;
-       overlay->fb_y = pos->fb_y;
-       overlay->fb_width = fb->width;
-       overlay->fb_height = fb->height;
-       overlay->src_width = pos->src_w;
-       overlay->src_height = pos->src_h;
-       overlay->bpp = fb->bits_per_pixel;
-       overlay->pitch = fb->pitches[0];
-       overlay->pixel_format = fb->pixel_format;
-
-       /* set overlay range to be displayed. */
-       overlay->crtc_x = pos->crtc_x;
-       overlay->crtc_y = pos->crtc_y;
-       overlay->crtc_width = actual_w;
-       overlay->crtc_height = actual_h;
-
-       /* set drm mode data. */
-       overlay->mode_width = mode->hdisplay;
-       overlay->mode_height = mode->vdisplay;
-       overlay->refresh = mode->vrefresh;
-       overlay->scan_flag = mode->flags;
-
-       DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
-                       overlay->crtc_x, overlay->crtc_y,
-                       overlay->crtc_width, overlay->crtc_height);
-
-       return 0;
-}
-
-static int exynos_drm_crtc_update(struct drm_crtc *crtc)
-{
-       struct exynos_drm_crtc *exynos_crtc;
-       struct exynos_drm_overlay *overlay;
-       struct exynos_drm_crtc_pos pos;
-       struct drm_display_mode *mode = &crtc->mode;
-       struct drm_framebuffer *fb = crtc->fb;
-
-       if (!mode || !fb)
-               return -EINVAL;
-
-       exynos_crtc = to_exynos_crtc(crtc);
-       overlay = &exynos_crtc->overlay;
-
-       memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
-
-       /* it means the offset of framebuffer to be displayed. */
-       pos.fb_x = crtc->x;
-       pos.fb_y = crtc->y;
-
-       /* OSD position to be displayed. */
-       pos.crtc_x = 0;
-       pos.crtc_y = 0;
-       pos.crtc_w = fb->width - crtc->x;
-       pos.crtc_h = fb->height - crtc->y;
-       pos.src_w = pos.crtc_w;
-       pos.src_h = pos.crtc_h;
-
-       return exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos);
-}
-
 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
        struct drm_device *dev = crtc->dev;
@@ -175,23 +78,8 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
 
        mutex_lock(&dev->struct_mutex);
 
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               exynos_drm_fn_encoder(crtc, &mode,
-                               exynos_drm_encoder_crtc_dpms);
-               exynos_crtc->dpms = mode;
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               exynos_drm_fn_encoder(crtc, &mode,
-                               exynos_drm_encoder_crtc_dpms);
-               exynos_crtc->dpms = mode;
-               break;
-       default:
-               DRM_ERROR("unspecified mode %d\n", mode);
-               break;
-       }
+       exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms);
+       exynos_crtc->dpms = mode;
 
        mutex_unlock(&dev->struct_mutex);
 }
@@ -209,30 +97,8 @@ static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       /*
-        * when set_crtc is requested from user or at booting time,
-        * crtc->commit would be called without dpms call so if dpms is
-        * no power on then crtc->dpms should be called
-        * with DRM_MODE_DPMS_ON for the hardware power to be on.
-        */
-       if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) {
-               int mode = DRM_MODE_DPMS_ON;
-
-               /*
-                * enable hardware(power on) to all encoders hdmi connected
-                * to current crtc.
-                */
-               exynos_drm_crtc_dpms(crtc, mode);
-               /*
-                * enable dma to all encoders connected to current crtc and
-                * lcd panel.
-                */
-               exynos_drm_fn_encoder(crtc, &mode,
-                                       exynos_drm_encoder_dpms_from_crtc);
-       }
-
-       exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
-                       exynos_drm_encoder_crtc_commit);
+       exynos_plane_commit(exynos_crtc->plane);
+       exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON);
 }
 
 static bool
@@ -251,31 +117,61 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
                          struct drm_display_mode *adjusted_mode, int x, int y,
                          struct drm_framebuffer *old_fb)
 {
+       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+       struct drm_plane *plane = exynos_crtc->plane;
+       unsigned int crtc_w;
+       unsigned int crtc_h;
+       int pipe = exynos_crtc->pipe;
+       int ret;
+
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
+       exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+
        /*
         * copy the mode data adjusted by mode_fixup() into crtc->mode
         * so that hardware can be seet to proper mode.
         */
        memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
 
-       return exynos_drm_crtc_update(crtc);
+       crtc_w = crtc->fb->width - x;
+       crtc_h = crtc->fb->height - y;
+
+       ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
+                                   x, y, crtc_w, crtc_h);
+       if (ret)
+               return ret;
+
+       plane->crtc = crtc;
+       plane->fb = crtc->fb;
+
+       exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
+
+       return 0;
 }
 
 static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
                                          struct drm_framebuffer *old_fb)
 {
+       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+       struct drm_plane *plane = exynos_crtc->plane;
+       unsigned int crtc_w;
+       unsigned int crtc_h;
        int ret;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       ret = exynos_drm_crtc_update(crtc);
+       crtc_w = crtc->fb->width - x;
+       crtc_h = crtc->fb->height - y;
+
+       ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
+                                   x, y, crtc_w, crtc_h);
        if (ret)
                return ret;
 
-       exynos_drm_crtc_apply(crtc);
+       exynos_drm_crtc_commit(crtc);
 
-       return ret;
+       return 0;
 }
 
 static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
@@ -284,6 +180,16 @@ static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
        /* drm framework doesn't check NULL */
 }
 
+static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
+{
+       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF);
+       exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
        .dpms           = exynos_drm_crtc_dpms,
        .prepare        = exynos_drm_crtc_prepare,
@@ -292,6 +198,7 @@ static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
        .mode_set       = exynos_drm_crtc_mode_set,
        .mode_set_base  = exynos_drm_crtc_mode_set_base,
        .load_lut       = exynos_drm_crtc_load_lut,
+       .disable        = exynos_drm_crtc_disable,
 };
 
 static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
@@ -327,7 +234,8 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
                                &dev_priv->pageflip_event_list);
 
                crtc->fb = fb;
-               ret = exynos_drm_crtc_update(crtc);
+               ret = exynos_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y,
+                                                   NULL);
                if (ret) {
                        crtc->fb = old_fb;
                        drm_vblank_put(dev, exynos_crtc->pipe);
@@ -335,14 +243,6 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
 
                        goto out;
                }
-
-               /*
-                * the values related to a buffer of the drm framebuffer
-                * to be applied should be set at here. because these values
-                * first, are set to shadow registers and then to
-                * real registers at vsync front porch period.
-                */
-               exynos_drm_crtc_apply(crtc);
        }
 out:
        mutex_unlock(&dev->struct_mutex);
@@ -362,18 +262,73 @@ static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
        kfree(exynos_crtc);
 }
 
+static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
+                                       struct drm_property *property,
+                                       uint64_t val)
+{
+       struct drm_device *dev = crtc->dev;
+       struct exynos_drm_private *dev_priv = dev->dev_private;
+       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+
+       DRM_DEBUG_KMS("%s\n", __func__);
+
+       if (property == dev_priv->crtc_mode_property) {
+               enum exynos_crtc_mode mode = val;
+
+               if (mode == exynos_crtc->mode)
+                       return 0;
+
+               exynos_crtc->mode = mode;
+
+               switch (mode) {
+               case CRTC_MODE_NORMAL:
+                       exynos_drm_crtc_commit(crtc);
+                       break;
+               case CRTC_MODE_BLANK:
+                       exynos_plane_dpms(exynos_crtc->plane,
+                                         DRM_MODE_DPMS_OFF);
+                       break;
+               default:
+                       break;
+               }
+
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
 static struct drm_crtc_funcs exynos_crtc_funcs = {
        .set_config     = drm_crtc_helper_set_config,
        .page_flip      = exynos_drm_crtc_page_flip,
        .destroy        = exynos_drm_crtc_destroy,
+       .set_property   = exynos_drm_crtc_set_property,
+};
+
+static const struct drm_prop_enum_list mode_names[] = {
+       { CRTC_MODE_NORMAL, "normal" },
+       { CRTC_MODE_BLANK, "blank" },
 };
 
-struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev,
-               struct drm_crtc *crtc)
+static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
 {
-       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct exynos_drm_private *dev_priv = dev->dev_private;
+       struct drm_property *prop;
 
-       return &exynos_crtc->overlay;
+       DRM_DEBUG_KMS("%s\n", __func__);
+
+       prop = dev_priv->crtc_mode_property;
+       if (!prop) {
+               prop = drm_property_create_enum(dev, 0, "mode", mode_names,
+                                               ARRAY_SIZE(mode_names));
+               if (!prop)
+                       return;
+
+               dev_priv->crtc_mode_property = prop;
+       }
+
+       drm_object_attach_property(&crtc->base, prop, 0);
 }
 
 int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
@@ -392,7 +347,12 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
 
        exynos_crtc->pipe = nr;
        exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
-       exynos_crtc->overlay.zpos = DEFAULT_ZPOS;
+       exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true);
+       if (!exynos_crtc->plane) {
+               kfree(exynos_crtc);
+               return -ENOMEM;
+       }
+
        crtc = &exynos_crtc->drm_crtc;
 
        private->crtc[nr] = crtc;
@@ -400,6 +360,8 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
        drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
        drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
 
+       exynos_drm_crtc_attach_mode_property(crtc);
+
        return 0;
 }
 
index 16b8e2195a0de2f1b8778b697e707f50f527843f..6bae8d8c250ec7d6cd84c85268d99cf5f40669b6 100644 (file)
 #ifndef _EXYNOS_DRM_CRTC_H_
 #define _EXYNOS_DRM_CRTC_H_
 
-struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev,
-               struct drm_crtc *crtc);
 int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr);
 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
 void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
 
-/*
- * Exynos specific crtc postion structure.
- *
- * @fb_x: offset x on a framebuffer to be displyed
- *     - the unit is screen coordinates.
- * @fb_y: offset y on a framebuffer to be displayed
- *     - the unit is screen coordinates.
- * @src_w: width of source area to be displayed from a framebuffer.
- * @src_h: height of source area to be displayed from a framebuffer.
- * @crtc_x: offset x on hardware screen.
- * @crtc_y: offset y on hardware screen.
- * @crtc_w: width of hardware screen.
- * @crtc_h: height of hardware screen.
- */
-struct exynos_drm_crtc_pos {
-       unsigned int fb_x;
-       unsigned int fb_y;
-       unsigned int src_w;
-       unsigned int src_h;
-       unsigned int crtc_x;
-       unsigned int crtc_y;
-       unsigned int crtc_w;
-       unsigned int crtc_h;
-};
-
-int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
-                             struct drm_framebuffer *fb,
-                             struct drm_display_mode *mode,
-                             struct exynos_drm_crtc_pos *pos);
 #endif
index 274909271c36de62e18d10b81fe01a58b598fc61..613bf8a5d9b268331779b0f60f43f52a047269de 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "drmP.h"
 #include "drm.h"
+#include "exynos_drm.h"
 #include "exynos_drm_drv.h"
 #include "exynos_drm_gem.h"
 
@@ -86,6 +87,10 @@ static struct sg_table *
        npages = buf->size / buf->page_size;
 
        sgt = exynos_pages_to_sg(buf->pages, npages, buf->page_size);
+       if (!sgt) {
+               DRM_DEBUG_PRIME("exynos_pages_to_sg returned NULL!\n");
+               goto err_unlock;
+       }
        nents = dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir);
 
        DRM_DEBUG_PRIME("npages = %d buffer size = 0x%lx page_size = 0x%lx\n",
@@ -186,7 +191,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
        struct exynos_drm_gem_obj *exynos_gem_obj;
        struct exynos_drm_gem_buf *buffer;
        struct page *page;
-       int ret, i = 0;
+       int ret;
 
        DRM_DEBUG_PRIME("%s\n", __FILE__);
 
@@ -210,7 +215,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
 
 
        sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
-       if (IS_ERR(sgt)) {
+       if (IS_ERR_OR_NULL(sgt)) {
                ret = PTR_ERR(sgt);
                goto err_buf_detach;
        }
@@ -236,13 +241,25 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
        }
 
        sgl = sgt->sgl;
-       buffer->dma_addr = sg_dma_address(sgl);
 
-       while (i < sgt->nents) {
-               buffer->pages[i] = sg_page(sgl);
-               buffer->size += sg_dma_len(sgl);
-               sgl = sg_next(sgl);
-               i++;
+       if (sgt->nents == 1) {
+               buffer->dma_addr = sg_dma_address(sgt->sgl);
+               buffer->size = sg_dma_len(sgt->sgl);
+
+               /* always physically continuous memory if sgt->nents is 1. */
+               exynos_gem_obj->flags |= EXYNOS_BO_CONTIG;
+       } else {
+               unsigned int i = 0;
+
+               buffer->dma_addr = sg_dma_address(sgl);
+               while (i < sgt->nents) {
+                       buffer->pages[i] = sg_page(sgl);
+                       buffer->size += sg_dma_len(sgl);
+                       sgl = sg_next(sgl);
+                       i++;
+               }
+
+               exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG;
        }
 
        exynos_gem_obj->buffer = buffer;
index d6de2e07fa034ea33d796cd6ad97c5902e369924..ebacec6f1e48efef646700c630f02813007eaac0 100644 (file)
@@ -85,8 +85,11 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
        }
 
        for (nr = 0; nr < MAX_PLANE; nr++) {
-               ret = exynos_plane_init(dev, nr);
-               if (ret)
+               struct drm_plane *plane;
+               unsigned int possible_crtcs = (1 << MAX_CRTC) - 1;
+
+               plane = exynos_plane_init(dev, possible_crtcs, false);
+               if (!plane)
                        goto err_crtc;
        }
 
@@ -221,8 +224,6 @@ static struct drm_ioctl_desc exynos_ioctls[] = {
                        exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
        DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
                        exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
-       DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl,
-                       DRM_UNLOCKED | DRM_AUTH),
        DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
                        vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
        DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
index 277653d5fda0704dcbad615b1ec1d64f7bedc5f7..e22704b249d75782def8345dca75b5e51d60715d 100644 (file)
@@ -59,12 +59,14 @@ enum exynos_drm_output_type {
  *
  * @mode_set: copy drm overlay info to hw specific overlay info.
  * @commit: apply hardware specific overlay data to registers.
+ * @enable: enable hardware specific overlay.
  * @disable: disable hardware specific overlay.
  */
 struct exynos_drm_overlay_ops {
        void (*mode_set)(struct device *subdrv_dev,
                         struct exynos_drm_overlay *overlay);
        void (*commit)(struct device *subdrv_dev, int zpos);
+       void (*enable)(struct device *subdrv_dev, int zpos);
        void (*disable)(struct device *subdrv_dev, int zpos);
 };
 
@@ -235,6 +237,8 @@ struct exynos_drm_private {
         * this array is used to be aware of which crtc did it request vblank.
         */
        struct drm_crtc *crtc[MAX_CRTC];
+       struct drm_property *plane_zpos_property;
+       struct drm_property *crtc_mode_property;
 };
 
 /*
index 4a13a747f5d4930d06d495503190ee80ea4d532d..2c037cd7d2d44aee526779636d5f8e999c4adf5d 100644 (file)
@@ -30,7 +30,6 @@
 #include "drm_crtc_helper.h"
 
 #include "exynos_drm_drv.h"
-#include "exynos_drm_crtc.h"
 #include "exynos_drm_encoder.h"
 
 #define to_exynos_encoder(x)   container_of(x, struct exynos_drm_encoder,\
@@ -136,21 +135,16 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
        struct drm_connector *connector;
        struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
        struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
-       struct exynos_drm_overlay *overlay = get_exynos_drm_overlay(dev,
-                                               encoder->crtc);
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
+       exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
+               if (connector->encoder == encoder)
                        if (manager_ops && manager_ops->mode_set)
                                manager_ops->mode_set(manager->dev,
                                                        adjusted_mode);
-
-                       if (overlay_ops && overlay_ops->mode_set)
-                               overlay_ops->mode_set(manager->dev, overlay);
-               }
        }
 }
 
@@ -310,8 +304,8 @@ void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
        struct exynos_drm_manager_ops *manager_ops = manager->ops;
        int crtc = *(int *)data;
 
-       if (manager->pipe == -1)
-               manager->pipe = crtc;
+       if (manager->pipe != crtc)
+               return;
 
        if (manager_ops->enable_vblank)
                manager_ops->enable_vblank(manager->dev);
@@ -324,34 +318,41 @@ void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
        struct exynos_drm_manager_ops *manager_ops = manager->ops;
        int crtc = *(int *)data;
 
-       if (manager->pipe == -1)
-               manager->pipe = crtc;
+       if (manager->pipe != crtc)
+               return;
 
        if (manager_ops->disable_vblank)
                manager_ops->disable_vblank(manager->dev);
 }
 
-void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder,
-                                         void *data)
+void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
 {
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
-       int zpos = DEFAULT_ZPOS;
+       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+       struct exynos_drm_manager *manager = exynos_encoder->manager;
+       struct exynos_drm_manager_ops *manager_ops = manager->ops;
+       int mode = *(int *)data;
 
-       if (data)
-               zpos = *(int *)data;
+       DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (overlay_ops && overlay_ops->commit)
-               overlay_ops->commit(manager->dev, zpos);
+       if (manager_ops && manager_ops->dpms)
+               manager_ops->dpms(manager->dev, mode);
+
+       /*
+        * if this condition is ok then it means that the crtc is already
+        * detached from encoder and last function for detaching is properly
+        * done, so clear pipe from manager to prevent repeated call.
+        */
+       if (mode > DRM_MODE_DPMS_ON) {
+               if (!encoder->crtc)
+                       manager->pipe = -1;
+       }
 }
 
-void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
+void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
 {
        struct exynos_drm_manager *manager =
                to_exynos_encoder(encoder)->manager;
-       int crtc = *(int *)data;
-       int zpos = DEFAULT_ZPOS;
+       int pipe = *(int *)data;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -359,76 +360,62 @@ void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
         * when crtc is detached from encoder, this pipe is used
         * to select manager operation
         */
-       manager->pipe = crtc;
-
-       exynos_drm_encoder_crtc_plane_commit(encoder, &zpos);
+       manager->pipe = pipe;
 }
 
-void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder, void *data)
+void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
 {
-       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       int mode = *(int *)data;
+       struct exynos_drm_manager *manager =
+               to_exynos_encoder(encoder)->manager;
+       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+       struct exynos_drm_overlay *overlay = data;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       exynos_drm_encoder_dpms(encoder, mode);
-
-       exynos_encoder->dpms = mode;
+       if (overlay_ops && overlay_ops->mode_set)
+               overlay_ops->mode_set(manager->dev, overlay);
 }
 
-void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
+void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
 {
-       struct drm_device *dev = encoder->dev;
-       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       struct exynos_drm_manager *manager = exynos_encoder->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       struct drm_connector *connector;
-       int mode = *(int *)data;
+       struct exynos_drm_manager *manager =
+               to_exynos_encoder(encoder)->manager;
+       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+       int zpos = DEFAULT_ZPOS;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (manager_ops && manager_ops->dpms)
-               manager_ops->dpms(manager->dev, mode);
-
-       /*
-        * set current dpms mode to the connector connected to
-        * current encoder. connector->dpms would be checked
-        * at drm_helper_connector_dpms()
-        */
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
-               if (connector->encoder == encoder)
-                       connector->dpms = mode;
+       if (data)
+               zpos = *(int *)data;
 
-       /*
-        * if this condition is ok then it means that the crtc is already
-        * detached from encoder and last function for detaching is properly
-        * done, so clear pipe from manager to prevent repeated call.
-        */
-       if (mode > DRM_MODE_DPMS_ON) {
-               if (!encoder->crtc)
-                       manager->pipe = -1;
-       }
+       if (overlay_ops && overlay_ops->commit)
+               overlay_ops->commit(manager->dev, zpos);
 }
 
-void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
+void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
 {
        struct exynos_drm_manager *manager =
                to_exynos_encoder(encoder)->manager;
        struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
-       struct exynos_drm_overlay *overlay = data;
+       int zpos = DEFAULT_ZPOS;
 
-       if (overlay_ops && overlay_ops->mode_set)
-               overlay_ops->mode_set(manager->dev, overlay);
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (data)
+               zpos = *(int *)data;
+
+       if (overlay_ops && overlay_ops->enable)
+               overlay_ops->enable(manager->dev, zpos);
 }
 
-void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
+void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
 {
        struct exynos_drm_manager *manager =
                to_exynos_encoder(encoder)->manager;
        struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
        int zpos = DEFAULT_ZPOS;
 
-       DRM_DEBUG_KMS("\n");
+       DRM_DEBUG_KMS("%s\n", __FILE__);
 
        if (data)
                zpos = *(int *)data;
index eb7d2316847edff9e4faa2940f241e9a19f8739c..6470d9ddf5a15affa3291673422b72e06b456063 100644 (file)
@@ -40,13 +40,11 @@ void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
                            void (*fn)(struct drm_encoder *, void *));
 void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
 void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder,
-                                         void *data);
-void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder,
-                                       void *data);
 void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data);
+void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data);
+void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data);
+void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data);
+void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data);
+void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data);
 
 #endif
index 29fdbfeb43cb79645d034da2d7f8a7aba27dbe5b..a68d2b313f03cab1d42fae0d362159f6a4f1ba26 100644 (file)
@@ -78,7 +78,6 @@ struct fimd_context {
        struct drm_crtc                 *crtc;
        struct clk                      *bus_clk;
        struct clk                      *lcd_clk;
-       struct resource                 *regs_res;
        void __iomem                    *regs;
        struct fimd_win_data            win_data[WINDOWS_NR];
        unsigned int                    clkdiv;
@@ -813,7 +812,7 @@ static int __devinit fimd_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
@@ -838,33 +837,26 @@ static int __devinit fimd_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
-       ctx->regs_res = request_mem_region(res->start, resource_size(res),
-                                          dev_name(dev));
-       if (!ctx->regs_res) {
-               dev_err(dev, "failed to claim register region\n");
-               ret = -ENOENT;
-               goto err_clk;
-       }
-
-       ctx->regs = ioremap(res->start, resource_size(res));
+       ctx->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (!ctx->regs) {
                dev_err(dev, "failed to map registers\n");
                ret = -ENXIO;
-               goto err_req_region_io;
+               goto err_clk;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
                dev_err(dev, "irq request failed.\n");
-               goto err_req_region_irq;
+               goto err_clk;
        }
 
        ctx->irq = res->start;
 
-       ret = request_irq(ctx->irq, fimd_irq_handler, 0, "drm_fimd", ctx);
-       if (ret < 0) {
+       ret = devm_request_irq(&pdev->dev, ctx->irq, fimd_irq_handler,
+                                                       0, "drm_fimd", ctx);
+       if (ret) {
                dev_err(dev, "irq request failed.\n");
-               goto err_req_irq;
+               goto err_clk;
        }
 
        ctx->vidcon0 = pdata->vidcon0;
@@ -899,14 +891,6 @@ static int __devinit fimd_probe(struct platform_device *pdev)
 
        return 0;
 
-err_req_irq:
-err_req_region_irq:
-       iounmap(ctx->regs);
-
-err_req_region_io:
-       release_resource(ctx->regs_res);
-       kfree(ctx->regs_res);
-
 err_clk:
        clk_disable(ctx->lcd_clk);
        clk_put(ctx->lcd_clk);
@@ -916,7 +900,6 @@ err_bus_clk:
        clk_put(ctx->bus_clk);
 
 err_clk_get:
-       kfree(ctx);
        return ret;
 }
 
@@ -944,13 +927,6 @@ out:
        clk_put(ctx->lcd_clk);
        clk_put(ctx->bus_clk);
 
-       iounmap(ctx->regs);
-       release_resource(ctx->regs_res);
-       kfree(ctx->regs_res);
-       free_irq(ctx->irq, ctx);
-
-       kfree(ctx);
-
        return 0;
 }
 
index 5c8b683029ea64c0938c1054aa1157c4eb94e694..f9efde40c097b819af24d41ff32162f3191ea632 100644 (file)
@@ -99,25 +99,17 @@ out:
 struct page **exynos_gem_get_pages(struct drm_gem_object *obj,
                                                gfp_t gfpmask)
 {
-       struct inode *inode;
-       struct address_space *mapping;
        struct page *p, **pages;
        int i, npages;
 
-       /* This is the shared memory object that backs the GEM resource */
-       inode = obj->filp->f_path.dentry->d_inode;
-       mapping = inode->i_mapping;
-
        npages = obj->size >> PAGE_SHIFT;
 
        pages = drm_malloc_ab(npages, sizeof(struct page *));
        if (pages == NULL)
                return ERR_PTR(-ENOMEM);
 
-       gfpmask |= mapping_gfp_mask(mapping);
-
        for (i = 0; i < npages; i++) {
-               p = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
+               p = alloc_page(gfpmask);
                if (IS_ERR(p))
                        goto fail;
                pages[i] = p;
@@ -126,31 +118,22 @@ struct page **exynos_gem_get_pages(struct drm_gem_object *obj,
        return pages;
 
 fail:
-       while (i--)
-               page_cache_release(pages[i]);
+       while (--i)
+               __free_page(pages[i]);
 
        drm_free_large(pages);
        return ERR_PTR(PTR_ERR(p));
 }
 
 static void exynos_gem_put_pages(struct drm_gem_object *obj,
-                                       struct page **pages,
-                                       bool dirty, bool accessed)
+                                       struct page **pages)
 {
-       int i, npages;
+       int npages;
 
        npages = obj->size >> PAGE_SHIFT;
 
-       for (i = 0; i < npages; i++) {
-               if (dirty)
-                       set_page_dirty(pages[i]);
-
-               if (accessed)
-                       mark_page_accessed(pages[i]);
-
-               /* Undo the reference we took when populating the table */
-               page_cache_release(pages[i]);
-       }
+       while (--npages >= 0)
+               __free_page(pages[npages]);
 
        drm_free_large(pages);
 }
@@ -189,7 +172,7 @@ static int exynos_drm_gem_get_pages(struct drm_gem_object *obj)
                return -EINVAL;
        }
 
-       pages = exynos_gem_get_pages(obj, GFP_KERNEL);
+       pages = exynos_gem_get_pages(obj, GFP_HIGHUSER_MOVABLE);
        if (IS_ERR(pages)) {
                DRM_ERROR("failed to get pages.\n");
                return PTR_ERR(pages);
@@ -230,7 +213,7 @@ err1:
        kfree(buf->sgt);
        buf->sgt = NULL;
 err:
-       exynos_gem_put_pages(obj, pages, true, false);
+       exynos_gem_put_pages(obj, pages);
        return ret;
 
 }
@@ -248,7 +231,7 @@ static void exynos_drm_gem_put_pages(struct drm_gem_object *obj)
        kfree(buf->sgt);
        buf->sgt = NULL;
 
-       exynos_gem_put_pages(obj, buf->pages, true, false);
+       exynos_gem_put_pages(obj, buf->pages);
        buf->pages = NULL;
 
        /* add some codes for UNCACHED type here. TODO */
@@ -291,11 +274,21 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
        if (!buf->pages)
                return;
 
+       /*
+        * do not release memory region from exporter.
+        *
+        * the region will be released by exporter
+        * once dmabuf's refcount becomes 0.
+        */
+       if (obj->import_attach)
+               goto out;
+
        if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG)
                exynos_drm_gem_put_pages(obj);
        else
                exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags, buf);
 
+out:
        exynos_drm_fini_buf(obj->dev, buf);
        exynos_gem_obj->buffer = NULL;
 
@@ -668,7 +661,7 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
         *      with DRM_IOCTL_MODE_CREATE_DUMB command.
         */
 
-       args->pitch = args->width * args->bpp >> 3;
+       args->pitch = args->width * ((args->bpp + 7) / 8);
        args->size = PAGE_ALIGN(args->pitch * args->height);
 
        exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
index 14d038b6cb02ffe6c35e3350d612018a3fe9f241..085b2a5d5f70fab9925aafbc8c561c05040521e7 100644 (file)
@@ -63,7 +63,8 @@ struct exynos_drm_gem_buf {
  *     by user request or at framebuffer creation.
  *     continuous memory region allocated by user request
  *     or at framebuffer creation.
- * @size: total memory size to physically non-continuous memory region.
+ * @size: size requested from user, in bytes and this size is aligned
+ *     in page unit.
  * @flags: indicate memory type to allocated buffer and cache attruibute.
  *
  * P.S. this object would be transfered to user as kms_bo.handle so
index c4c6525d46532392414902079ec5aa18efdedfbc..b89829e5043a59a67152c5cafc241265f0183f12 100644 (file)
 #include "drmP.h"
 
 #include "exynos_drm.h"
-#include "exynos_drm_crtc.h"
 #include "exynos_drm_drv.h"
 #include "exynos_drm_encoder.h"
+#include "exynos_drm_fb.h"
+#include "exynos_drm_gem.h"
+
+#define to_exynos_plane(x)     container_of(x, struct exynos_plane, base)
 
 struct exynos_plane {
        struct drm_plane                base;
@@ -30,6 +33,108 @@ static const uint32_t formats[] = {
        DRM_FORMAT_NV12MT,
 };
 
+int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
+                         struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+                         unsigned int crtc_w, unsigned int crtc_h,
+                         uint32_t src_x, uint32_t src_y,
+                         uint32_t src_w, uint32_t src_h)
+{
+       struct exynos_plane *exynos_plane = to_exynos_plane(plane);
+       struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
+       unsigned int actual_w;
+       unsigned int actual_h;
+       int nr;
+       int i;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       nr = exynos_drm_format_num_buffers(fb->pixel_format);
+       for (i = 0; i < nr; i++) {
+               struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i);
+
+               if (!buffer) {
+                       DRM_LOG_KMS("buffer is null\n");
+                       return -EFAULT;
+               }
+
+               overlay->dma_addr[i] = buffer->dma_addr;
+               overlay->vaddr[i] = buffer->kvaddr;
+
+               DRM_DEBUG_KMS("buffer: %d, vaddr = 0x%lx, dma_addr = 0x%lx\n",
+                               i, (unsigned long)overlay->vaddr[i],
+                               (unsigned long)overlay->dma_addr[i]);
+       }
+
+       actual_w = min((unsigned)(crtc->mode.hdisplay - crtc_x), crtc_w);
+       actual_h = min((unsigned)(crtc->mode.vdisplay - crtc_y), crtc_h);
+
+       /* set drm framebuffer data. */
+       overlay->fb_x = src_x;
+       overlay->fb_y = src_y;
+       overlay->fb_width = fb->width;
+       overlay->fb_height = fb->height;
+       overlay->src_width = src_w;
+       overlay->src_height = src_h;
+       overlay->bpp = fb->bits_per_pixel;
+       overlay->pitch = fb->pitches[0];
+       overlay->pixel_format = fb->pixel_format;
+
+       /* set overlay range to be displayed. */
+       overlay->crtc_x = crtc_x;
+       overlay->crtc_y = crtc_y;
+       overlay->crtc_width = actual_w;
+       overlay->crtc_height = actual_h;
+
+       /* set drm mode data. */
+       overlay->mode_width = crtc->mode.hdisplay;
+       overlay->mode_height = crtc->mode.vdisplay;
+       overlay->refresh = crtc->mode.vrefresh;
+       overlay->scan_flag = crtc->mode.flags;
+
+       DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
+                       overlay->crtc_x, overlay->crtc_y,
+                       overlay->crtc_width, overlay->crtc_height);
+
+       exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_plane_mode_set);
+
+       return 0;
+}
+
+void exynos_plane_commit(struct drm_plane *plane)
+{
+       struct exynos_plane *exynos_plane = to_exynos_plane(plane);
+       struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
+
+       exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+                       exynos_drm_encoder_plane_commit);
+}
+
+void exynos_plane_dpms(struct drm_plane *plane, int mode)
+{
+       struct exynos_plane *exynos_plane = to_exynos_plane(plane);
+       struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       if (mode == DRM_MODE_DPMS_ON) {
+               if (exynos_plane->enabled)
+                       return;
+
+               exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+                               exynos_drm_encoder_plane_enable);
+
+               exynos_plane->enabled = true;
+       } else {
+               if (!exynos_plane->enabled)
+                       return;
+
+               exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+                               exynos_drm_encoder_plane_disable);
+
+               exynos_plane->enabled = false;
+       }
+}
+
 static int
 exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                     struct drm_framebuffer *fb, int crtc_x, int crtc_y,
@@ -37,64 +142,37 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                     uint32_t src_x, uint32_t src_y,
                     uint32_t src_w, uint32_t src_h)
 {
-       struct exynos_plane *exynos_plane =
-               container_of(plane, struct exynos_plane, base);
-       struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
-       struct exynos_drm_crtc_pos pos;
        int ret;
 
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-       memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
-       pos.crtc_x = crtc_x;
-       pos.crtc_y = crtc_y;
-       pos.crtc_w = crtc_w;
-       pos.crtc_h = crtc_h;
-
-       /* considering 16.16 fixed point of source values */
-       pos.fb_x = src_x >> 16;
-       pos.fb_y = src_y >> 16;
-       pos.src_w = src_w >> 16;
-       pos.src_h = src_h >> 16;
-
-       ret = exynos_drm_overlay_update(overlay, fb, &crtc->mode, &pos);
+       ret = exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
+                       crtc_w, crtc_h, src_x >> 16, src_y >> 16,
+                       src_w >> 16, src_h >> 16);
        if (ret < 0)
                return ret;
 
-       exynos_drm_fn_encoder(crtc, overlay,
-                       exynos_drm_encoder_crtc_mode_set);
-       exynos_drm_fn_encoder(crtc, &overlay->zpos,
-                       exynos_drm_encoder_crtc_plane_commit);
+       plane->crtc = crtc;
+       plane->fb = crtc->fb;
 
-       exynos_plane->enabled = true;
+       exynos_plane_commit(plane);
+       exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
 
        return 0;
 }
 
 static int exynos_disable_plane(struct drm_plane *plane)
 {
-       struct exynos_plane *exynos_plane =
-               container_of(plane, struct exynos_plane, base);
-       struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
-
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-       if (!exynos_plane->enabled)
-               return 0;
-
-       exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
-                       exynos_drm_encoder_crtc_disable);
-
-       exynos_plane->enabled = false;
-       exynos_plane->overlay.zpos = DEFAULT_ZPOS;
+       exynos_plane_dpms(plane, DRM_MODE_DPMS_OFF);
 
        return 0;
 }
 
 static void exynos_plane_destroy(struct drm_plane *plane)
 {
-       struct exynos_plane *exynos_plane =
-               container_of(plane, struct exynos_plane, base);
+       struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
@@ -103,69 +181,79 @@ static void exynos_plane_destroy(struct drm_plane *plane)
        kfree(exynos_plane);
 }
 
+static int exynos_plane_set_property(struct drm_plane *plane,
+                                    struct drm_property *property,
+                                    uint64_t val)
+{
+       struct drm_device *dev = plane->dev;
+       struct exynos_plane *exynos_plane = to_exynos_plane(plane);
+       struct exynos_drm_private *dev_priv = dev->dev_private;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       if (property == dev_priv->plane_zpos_property) {
+               exynos_plane->overlay.zpos = val;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
 static struct drm_plane_funcs exynos_plane_funcs = {
        .update_plane   = exynos_update_plane,
        .disable_plane  = exynos_disable_plane,
        .destroy        = exynos_plane_destroy,
+       .set_property   = exynos_plane_set_property,
 };
 
-int exynos_plane_init(struct drm_device *dev, unsigned int nr)
+static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
 {
-       struct exynos_plane *exynos_plane;
-       uint32_t possible_crtcs;
+       struct drm_device *dev = plane->dev;
+       struct exynos_drm_private *dev_priv = dev->dev_private;
+       struct drm_property *prop;
 
-       exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
-       if (!exynos_plane)
-               return -ENOMEM;
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-       /* all CRTCs are available */
-       possible_crtcs = (1 << MAX_CRTC) - 1;
+       prop = dev_priv->plane_zpos_property;
+       if (!prop) {
+               prop = drm_property_create_range(dev, 0, "zpos", 0,
+                                                MAX_PLANE - 1);
+               if (!prop)
+                       return;
 
-       exynos_plane->overlay.zpos = DEFAULT_ZPOS;
+               dev_priv->plane_zpos_property = prop;
+       }
 
-       return drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
-                             &exynos_plane_funcs, formats, ARRAY_SIZE(formats),
-                             false);
+       drm_object_attach_property(&plane->base, prop, 0);
 }
 
-int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
-                               struct drm_file *file_priv)
+struct drm_plane *exynos_plane_init(struct drm_device *dev,
+                                   unsigned int possible_crtcs, bool priv)
 {
-       struct drm_exynos_plane_set_zpos *zpos_req = data;
-       struct drm_mode_object *obj;
-       struct drm_plane *plane;
        struct exynos_plane *exynos_plane;
-       int ret = 0;
+       int err;
 
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       if (zpos_req->zpos < 0 || zpos_req->zpos >= MAX_PLANE) {
-               if (zpos_req->zpos != DEFAULT_ZPOS) {
-                       DRM_ERROR("zpos not within limits\n");
-                       return -EINVAL;
-               }
+       exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
+       if (!exynos_plane) {
+               DRM_ERROR("failed to allocate plane\n");
+               return NULL;
        }
 
-       mutex_lock(&dev->mode_config.mutex);
-
-       obj = drm_mode_object_find(dev, zpos_req->plane_id,
-                       DRM_MODE_OBJECT_PLANE);
-       if (!obj) {
-               DRM_DEBUG_KMS("Unknown plane ID %d\n",
-                             zpos_req->plane_id);
-               ret = -EINVAL;
-               goto out;
+       err = drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
+                             &exynos_plane_funcs, formats, ARRAY_SIZE(formats),
+                             priv);
+       if (err) {
+               DRM_ERROR("failed to initialize plane\n");
+               kfree(exynos_plane);
+               return NULL;
        }
 
-       plane = obj_to_plane(obj);
-       exynos_plane = container_of(plane, struct exynos_plane, base);
-
-       exynos_plane->overlay.zpos = zpos_req->zpos;
+       if (priv)
+               exynos_plane->overlay.zpos = DEFAULT_ZPOS;
+       else
+               exynos_plane_attach_zpos_property(&exynos_plane->base);
 
-out:
-       mutex_unlock(&dev->mode_config.mutex);
-       return ret;
+       return &exynos_plane->base;
 }
index 16b71f8217e7c121a083adf673859c6447e115cb..88312458580d459946cd67a1f794a13929254374 100644 (file)
@@ -9,6 +9,12 @@
  *
  */
 
-int exynos_plane_init(struct drm_device *dev, unsigned int nr);
-int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
-                               struct drm_file *file_priv);
+int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
+                         struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+                         unsigned int crtc_w, unsigned int crtc_h,
+                         uint32_t src_x, uint32_t src_y,
+                         uint32_t src_w, uint32_t src_h);
+void exynos_plane_commit(struct drm_plane *plane);
+void exynos_plane_dpms(struct drm_plane *plane, int mode);
+struct drm_plane *exynos_plane_init(struct drm_device *dev,
+                                   unsigned int possible_crtcs, bool priv);
index 7b9c153dceb610776f59711d4c5c3c303ff21228..bb1550c4dd57db37554954537ef19c61d4e513ce 100644 (file)
@@ -85,8 +85,6 @@ static const char fake_edid_info[] = {
        0x00, 0x00, 0x00, 0x06
 };
 
-static void vidi_fake_vblank_handler(struct work_struct *work);
-
 static bool vidi_display_is_connected(struct device *dev)
 {
        struct vidi_context *ctx = get_vidi_context(dev);
@@ -531,6 +529,16 @@ static int vidi_store_connection(struct device *dev,
        if (ctx->connected > 1)
                return -EINVAL;
 
+       /* use fake edid data for test. */
+       if (!ctx->raw_edid)
+               ctx->raw_edid = (struct edid *)fake_edid_info;
+
+       /* if raw_edid isn't same as fake data then it can't be tested. */
+       if (ctx->raw_edid != (struct edid *)fake_edid_info) {
+               DRM_DEBUG_KMS("edid data is not fake data.\n");
+               return -EINVAL;
+       }
+
        DRM_DEBUG_KMS("requested connection.\n");
 
        drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
@@ -549,6 +557,8 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
        struct exynos_drm_manager *manager;
        struct exynos_drm_display_ops *display_ops;
        struct drm_exynos_vidi_connection *vidi = data;
+       struct edid *raw_edid;
+       int edid_len;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -557,11 +567,6 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
                return -EINVAL;
        }
 
-       if (!vidi->edid) {
-               DRM_DEBUG_KMS("edid data is null.\n");
-               return -EINVAL;
-       }
-
        if (vidi->connection > 1) {
                DRM_DEBUG_KMS("connection should be 0 or 1.\n");
                return -EINVAL;
@@ -588,8 +593,30 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
                return -EINVAL;
        }
 
-       if (vidi->connection)
-               ctx->raw_edid = (struct edid *)vidi->edid;
+       if (vidi->connection) {
+               if (!vidi->edid) {
+                       DRM_DEBUG_KMS("edid data is null.\n");
+                       return -EINVAL;
+               }
+               raw_edid = (struct edid *)(uint32_t)vidi->edid;
+               edid_len = (1 + raw_edid->extensions) * EDID_LENGTH;
+               ctx->raw_edid = kzalloc(edid_len, GFP_KERNEL);
+               if (!ctx->raw_edid) {
+                       DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
+                       return -ENOMEM;
+               }
+               memcpy(ctx->raw_edid, raw_edid, edid_len);
+       } else {
+               /*
+                * with connection = 0, free raw_edid
+                * only if raw edid data isn't same as fake data.
+                */
+               if (ctx->raw_edid && ctx->raw_edid !=
+                               (struct edid *)fake_edid_info) {
+                       kfree(ctx->raw_edid);
+                       ctx->raw_edid = NULL;
+               }
+       }
 
        ctx->connected = vidi->connection;
        drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
@@ -614,9 +641,6 @@ static int __devinit vidi_probe(struct platform_device *pdev)
 
        INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
 
-       /* for test */
-       ctx->raw_edid = (struct edid *)fake_edid_info;
-
        subdrv = &ctx->subdrv;
        subdrv->dev = dev;
        subdrv->manager = &vidi_manager;
@@ -644,6 +668,11 @@ static int __devexit vidi_remove(struct platform_device *pdev)
 
        exynos_drm_subdrv_unregister(&ctx->subdrv);
 
+       if (ctx->raw_edid != (struct edid *)fake_edid_info) {
+               kfree(ctx->raw_edid);
+               ctx->raw_edid = NULL;
+       }
+
        kfree(ctx);
 
        return 0;
index 066bde3f19c4fb97642b178c27b072519a4c1b10..409e2ec1207c3ddbe4ecae65f9fae1498fcd6410 100644 (file)
@@ -63,7 +63,6 @@ struct hdmi_context {
        bool                            dvi_mode;
        struct mutex                    hdmi_mutex;
 
-       struct resource                 *regs_res;
        void __iomem                    *regs;
        unsigned int                    external_irq;
        unsigned int                    internal_irq;
@@ -2280,16 +2279,17 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
+       drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
+                                                               GFP_KERNEL);
        if (!drm_hdmi_ctx) {
                DRM_ERROR("failed to allocate common hdmi context.\n");
                return -ENOMEM;
        }
 
-       hdata = kzalloc(sizeof(struct hdmi_context), GFP_KERNEL);
+       hdata = devm_kzalloc(&pdev->dev, sizeof(struct hdmi_context),
+                                                               GFP_KERNEL);
        if (!hdata) {
                DRM_ERROR("out of memory\n");
-               kfree(drm_hdmi_ctx);
                return -ENOMEM;
        }
 
@@ -2318,26 +2318,18 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
                goto err_resource;
        }
 
-       hdata->regs_res = request_mem_region(res->start, resource_size(res),
-                                          dev_name(dev));
-       if (!hdata->regs_res) {
-               DRM_ERROR("failed to claim register region\n");
-               ret = -ENOENT;
-               goto err_resource;
-       }
-
-       hdata->regs = ioremap(res->start, resource_size(res));
+       hdata->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (!hdata->regs) {
                DRM_ERROR("failed to map registers\n");
                ret = -ENXIO;
-               goto err_req_region;
+               goto err_resource;
        }
 
        /* DDC i2c driver */
        if (i2c_add_driver(&ddc_driver)) {
                DRM_ERROR("failed to register ddc i2c driver\n");
                ret = -ENOENT;
-               goto err_iomap;
+               goto err_resource;
        }
 
        hdata->ddc_port = hdmi_ddc;
@@ -2398,16 +2390,9 @@ err_hdmiphy:
        i2c_del_driver(&hdmiphy_driver);
 err_ddc:
        i2c_del_driver(&ddc_driver);
-err_iomap:
-       iounmap(hdata->regs);
-err_req_region:
-       release_mem_region(hdata->regs_res->start,
-                       resource_size(hdata->regs_res));
 err_resource:
        hdmi_resources_cleanup(hdata);
 err_data:
-       kfree(hdata);
-       kfree(drm_hdmi_ctx);
        return ret;
 }
 
@@ -2425,18 +2410,11 @@ static int __devexit hdmi_remove(struct platform_device *pdev)
 
        hdmi_resources_cleanup(hdata);
 
-       iounmap(hdata->regs);
-
-       release_mem_region(hdata->regs_res->start,
-                       resource_size(hdata->regs_res));
-
        /* hdmiphy i2c driver */
        i2c_del_driver(&hdmiphy_driver);
        /* DDC i2c driver */
        i2c_del_driver(&ddc_driver);
 
-       kfree(hdata);
-
        return 0;
 }
 
index e2147a2ddcecab72570db6f3055aabdb18fe85ea..30fcc12f81dd943802031936dcfc9ea81b8f1548 100644 (file)
@@ -956,7 +956,8 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
 
        clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
 
-       mixer_res->mixer_regs = ioremap(res->start, resource_size(res));
+       mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start,
+                                                       resource_size(res));
        if (mixer_res->mixer_regs == NULL) {
                dev_err(dev, "register mapping failed.\n");
                ret = -ENXIO;
@@ -967,38 +968,34 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
        if (res == NULL) {
                dev_err(dev, "get memory resource failed.\n");
                ret = -ENXIO;
-               goto fail_mixer_regs;
+               goto fail;
        }
 
-       mixer_res->vp_regs = ioremap(res->start, resource_size(res));
+       mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start,
+                                                       resource_size(res));
        if (mixer_res->vp_regs == NULL) {
                dev_err(dev, "register mapping failed.\n");
                ret = -ENXIO;
-               goto fail_mixer_regs;
+               goto fail;
        }
 
        res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
        if (res == NULL) {
                dev_err(dev, "get interrupt resource failed.\n");
                ret = -ENXIO;
-               goto fail_vp_regs;
+               goto fail;
        }
 
-       ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", ctx);
+       ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler,
+                                                       0, "drm_mixer", ctx);
        if (ret) {
                dev_err(dev, "request interrupt failed.\n");
-               goto fail_vp_regs;
+               goto fail;
        }
        mixer_res->irq = res->start;
 
        return 0;
 
-fail_vp_regs:
-       iounmap(mixer_res->vp_regs);
-
-fail_mixer_regs:
-       iounmap(mixer_res->mixer_regs);
-
 fail:
        if (!IS_ERR_OR_NULL(mixer_res->sclk_dac))
                clk_put(mixer_res->sclk_dac);
@@ -1013,16 +1010,6 @@ fail:
        return ret;
 }
 
-static void mixer_resources_cleanup(struct mixer_context *ctx)
-{
-       struct mixer_resources *res = &ctx->mixer_res;
-
-       free_irq(res->irq, ctx);
-
-       iounmap(res->vp_regs);
-       iounmap(res->mixer_regs);
-}
-
 static int __devinit mixer_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -1032,16 +1019,16 @@ static int __devinit mixer_probe(struct platform_device *pdev)
 
        dev_info(dev, "probe start\n");
 
-       drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
+       drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
+                                                               GFP_KERNEL);
        if (!drm_hdmi_ctx) {
                DRM_ERROR("failed to allocate common hdmi context.\n");
                return -ENOMEM;
        }
 
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx) {
                DRM_ERROR("failed to alloc mixer context.\n");
-               kfree(drm_hdmi_ctx);
                return -ENOMEM;
        }
 
@@ -1072,17 +1059,10 @@ fail:
 
 static int mixer_remove(struct platform_device *pdev)
 {
-       struct device *dev = &pdev->dev;
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx =
-                                       platform_get_drvdata(pdev);
-       struct mixer_context *ctx = drm_hdmi_ctx->ctx;
-
-       dev_info(dev, "remove successful\n");
+       dev_info(&pdev->dev, "remove successful\n");
 
        pm_runtime_disable(&pdev->dev);
 
-       mixer_resources_cleanup(ctx);
-
        return 0;
 }
 
index 563c02904ddf0ab9704d76f2ab78ae6e3e364cb0..23ab3c496b0505bb1ed3c2f0e43dfe2ef1a139a8 100644 (file)
@@ -927,6 +927,8 @@ static int acpi_power_meter_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+
 static int acpi_power_meter_resume(struct device *dev)
 {
        struct acpi_power_meter_resource *resource;
@@ -944,6 +946,8 @@ static int acpi_power_meter_resume(struct device *dev)
        return 0;
 }
 
+#endif /* CONFIG_PM_SLEEP */
+
 static SIMPLE_DEV_PM_OPS(acpi_power_meter_pm, NULL, acpi_power_meter_resume);
 
 static struct acpi_driver acpi_power_meter_driver = {
index 4d937a18fadb5cd6cc07bcbe8e4c32aadfb37ee0..282708860517e8de41e2f86c3aeb55a118aaca17 100644 (file)
@@ -55,9 +55,9 @@
 
 /* wait up to 32 ms for a status change. */
 #define APPLESMC_MIN_WAIT      0x0010
+#define APPLESMC_RETRY_WAIT    0x0100
 #define APPLESMC_MAX_WAIT      0x8000
 
-#define APPLESMC_STATUS_MASK   0x0f
 #define APPLESMC_READ_CMD      0x10
 #define APPLESMC_WRITE_CMD     0x11
 #define APPLESMC_GET_KEY_BY_INDEX_CMD  0x12
@@ -162,51 +162,68 @@ static unsigned int key_at_index;
 static struct workqueue_struct *applesmc_led_wq;
 
 /*
- * __wait_status - Wait up to 32ms for the status port to get a certain value
- * (masked with 0x0f), returning zero if the value is obtained.  Callers must
+ * wait_read - Wait for a byte to appear on SMC port. Callers must
  * hold applesmc_lock.
  */
-static int __wait_status(u8 val)
+static int wait_read(void)
 {
+       u8 status;
        int us;
-
-       val = val & APPLESMC_STATUS_MASK;
-
        for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
                udelay(us);
-               if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val)
+               status = inb(APPLESMC_CMD_PORT);
+               /* read: wait for smc to settle */
+               if (status & 0x01)
                        return 0;
        }
 
+       pr_warn("wait_read() fail: 0x%02x\n", status);
        return -EIO;
 }
 
 /*
- * special treatment of command port - on newer macbooks, it seems necessary
- * to resend the command byte before polling the status again. Callers must
- * hold applesmc_lock.
+ * send_byte - Write to SMC port, retrying when necessary. Callers
+ * must hold applesmc_lock.
  */
-static int send_command(u8 cmd)
+static int send_byte(u8 cmd, u16 port)
 {
+       u8 status;
        int us;
+
+       outb(cmd, port);
        for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
-               outb(cmd, APPLESMC_CMD_PORT);
                udelay(us);
-               if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
+               status = inb(APPLESMC_CMD_PORT);
+               /* write: wait for smc to settle */
+               if (status & 0x02)
+                       continue;
+               /* ready: cmd accepted, return */
+               if (status & 0x04)
                        return 0;
+               /* timeout: give up */
+               if (us << 1 == APPLESMC_MAX_WAIT)
+                       break;
+               /* busy: long wait and resend */
+               udelay(APPLESMC_RETRY_WAIT);
+               outb(cmd, port);
        }
+
+       pr_warn("send_byte(0x%02x, 0x%04x) fail: 0x%02x\n", cmd, port, status);
        return -EIO;
 }
 
+static int send_command(u8 cmd)
+{
+       return send_byte(cmd, APPLESMC_CMD_PORT);
+}
+
 static int send_argument(const char *key)
 {
        int i;
 
-       for (i = 0; i < 4; i++) {
-               outb(key[i], APPLESMC_DATA_PORT);
-               if (__wait_status(0x04))
+       for (i = 0; i < 4; i++)
+               if (send_byte(key[i], APPLESMC_DATA_PORT))
                        return -EIO;
-       }
        return 0;
 }
 
@@ -219,11 +236,14 @@ static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
                return -EIO;
        }
 
-       outb(len, APPLESMC_DATA_PORT);
+       if (send_byte(len, APPLESMC_DATA_PORT)) {
+               pr_warn("%.4s: read len fail\n", key);
+               return -EIO;
+       }
 
        for (i = 0; i < len; i++) {
-               if (__wait_status(0x05)) {
-                       pr_warn("%.4s: read data fail\n", key);
+               if (wait_read()) {
+                       pr_warn("%.4s: read data[%d] fail\n", key, i);
                        return -EIO;
                }
                buffer[i] = inb(APPLESMC_DATA_PORT);
@@ -241,14 +261,16 @@ static int write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
                return -EIO;
        }
 
-       outb(len, APPLESMC_DATA_PORT);
+       if (send_byte(len, APPLESMC_DATA_PORT)) {
+               pr_warn("%.4s: write len fail\n", key);
+               return -EIO;
+       }
 
        for (i = 0; i < len; i++) {
-               if (__wait_status(0x04)) {
+               if (send_byte(buffer[i], APPLESMC_DATA_PORT)) {
                        pr_warn("%s: write data fail\n", key);
                        return -EIO;
                }
-               outb(buffer[i], APPLESMC_DATA_PORT);
        }
 
        return 0;
index 637c51c11b44ca774057404b6e5326a4ba1de31d..faa16f80db9cf652bbc75aaa7e5fd0e73b788ca4 100644 (file)
@@ -793,7 +793,7 @@ static struct notifier_block coretemp_cpu_notifier __refdata = {
        .notifier_call = coretemp_cpu_callback,
 };
 
-static const struct x86_cpu_id coretemp_ids[] = {
+static const struct x86_cpu_id __initconst coretemp_ids[] = {
        { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM },
        {}
 };
index e72ba5d2a8248e04ebf4bf65662007e57b960ca3..e21e43c13156911989267fb555d24e5b98ddb67e 100644 (file)
@@ -57,7 +57,7 @@ static const unsigned short normal_i2c[] = {
 #define JC42_CFG_EVENT_LOCK    (1 << 7)
 #define JC42_CFG_SHUTDOWN      (1 << 8)
 #define JC42_CFG_HYST_SHIFT    9
-#define JC42_CFG_HYST_MASK     0x03
+#define JC42_CFG_HYST_MASK     (0x03 << 9)
 
 /* Capabilities */
 #define JC42_CAP_RANGE         (1 << 2)
@@ -287,8 +287,8 @@ static ssize_t show_temp_crit_hyst(struct device *dev,
                return PTR_ERR(data);
 
        temp = jc42_temp_from_reg(data->temp_crit);
-       hyst = jc42_hysteresis[(data->config >> JC42_CFG_HYST_SHIFT)
-                              & JC42_CFG_HYST_MASK];
+       hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
+                              >> JC42_CFG_HYST_SHIFT];
        return sprintf(buf, "%d\n", temp - hyst);
 }
 
@@ -302,8 +302,8 @@ static ssize_t show_temp_max_hyst(struct device *dev,
                return PTR_ERR(data);
 
        temp = jc42_temp_from_reg(data->temp_max);
-       hyst = jc42_hysteresis[(data->config >> JC42_CFG_HYST_SHIFT)
-                              & JC42_CFG_HYST_MASK];
+       hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
+                              >> JC42_CFG_HYST_SHIFT];
        return sprintf(buf, "%d\n", temp - hyst);
 }
 
@@ -362,8 +362,7 @@ static ssize_t set_temp_crit_hyst(struct device *dev,
        }
 
        mutex_lock(&data->update_lock);
-       data->config = (data->config
-                       & ~(JC42_CFG_HYST_MASK << JC42_CFG_HYST_SHIFT))
+       data->config = (data->config & ~JC42_CFG_HYST_MASK)
          | (hyst << JC42_CFG_HYST_SHIFT);
        err = i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG,
                                           data->config);
@@ -535,9 +534,16 @@ static int jc42_remove(struct i2c_client *client)
        struct jc42_data *data = i2c_get_clientdata(client);
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &jc42_group);
-       if (data->config != data->orig_config)
-               i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG,
-                                            data->orig_config);
+
+       /* Restore original configuration except hysteresis */
+       if ((data->config & ~JC42_CFG_HYST_MASK) !=
+           (data->orig_config & ~JC42_CFG_HYST_MASK)) {
+               int config;
+
+               config = (data->orig_config & ~JC42_CFG_HYST_MASK)
+                 | (data->config & JC42_CFG_HYST_MASK);
+               i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, config);
+       }
        return 0;
 }
 
index 8689664ef03cd86866aae1d868aacc55e10a95d9..ee4ebc198a9448e868f45af079e8f3d5f51968ae 100644 (file)
@@ -309,7 +309,7 @@ static struct notifier_block via_cputemp_cpu_notifier __refdata = {
        .notifier_call = via_cputemp_cpu_callback,
 };
 
-static const struct x86_cpu_id cputemp_ids[] = {
+static const struct x86_cpu_id __initconst cputemp_ids[] = {
        { X86_VENDOR_CENTAUR, 6, 0xa, }, /* C7 A */
        { X86_VENDOR_CENTAUR, 6, 0xd, }, /* C7 D */
        { X86_VENDOR_CENTAUR, 6, 0xf, }, /* Nano */
index 2e7530a4e7b8cdb37cc47cedef24a0da3d5cec12..b4aaa1bd6728503b629acea078f3021fc148115a 100644 (file)
@@ -462,7 +462,7 @@ config I2C_MPC
 
 config I2C_MV64XXX
        tristate "Marvell mv64xxx I2C Controller"
-       depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
+       depends on (MV64X60 || PLAT_ORION)
        help
          If you say yes to this option, support will be included for the
          built-in I2C interface on the Marvell 64xxx line of host bridges.
@@ -483,10 +483,11 @@ config I2C_MXS
 
 config I2C_NOMADIK
        tristate "ST-Ericsson Nomadik/Ux500 I2C Controller"
-       depends on PLAT_NOMADIK
+       depends on ARM_AMBA
        help
          If you say yes to this option, support will be included for the
-         I2C interface from ST-Ericsson's Nomadik and Ux500 architectures.
+         I2C interface from ST-Ericsson's Nomadik and Ux500 architectures,
+         as well as the STA2X11 PCIe I/O HUB.
 
 config I2C_NUC900
        tristate "NUC900 I2C Driver"
index 1679deef9c890131a951ee5cb8d50217ecb9bcf5..e24484beef078d9e3069b32066cd9c865ed25f22 100644 (file)
@@ -279,30 +279,31 @@ static int __devexit at91_i2c_remove(struct platform_device *pdev)
 
 /* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
 
-static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg)
+static int at91_i2c_suspend(struct device *dev)
 {
        clk_disable(twi_clk);
        return 0;
 }
 
-static int at91_i2c_resume(struct platform_device *pdev)
+static int at91_i2c_resume(struct device *dev)
 {
        return clk_enable(twi_clk);
 }
 
+static SIMPLE_DEV_PM_OPS(at91_i2c_pm, at91_i2c_suspend, at91_i2c_resume);
+#define AT91_I2C_PM    (&at91_i2c_pm)
+
 #else
-#define at91_i2c_suspend       NULL
-#define at91_i2c_resume                NULL
+#define AT91_I2C_PM    NULL
 #endif
 
 static struct platform_driver at91_i2c_driver = {
        .probe          = at91_i2c_probe,
        .remove         = __devexit_p(at91_i2c_remove),
-       .suspend        = at91_i2c_suspend,
-       .resume         = at91_i2c_resume,
        .driver         = {
                .name   = "at91_i2c",
                .owner  = THIS_MODULE,
+               .pm     = AT91_I2C_PM,
        },
 };
 
index cdb59e5b23f749aa81153eb6619269d4f248eb61..0cf780fd6ef12578b6640b82abb952e4d0d3585e 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/blackfin.h>
 #include <asm/portmux.h>
 #include <asm/irq.h>
+#include <asm/bfin_twi.h>
 
 /* SMBus mode*/
 #define TWI_I2C_MODE_STANDARD          1
 #define TWI_I2C_MODE_COMBINED          3
 #define TWI_I2C_MODE_REPEAT            4
 
-struct bfin_twi_iface {
-       int                     irq;
-       spinlock_t              lock;
-       char                    read_write;
-       u8                      command;
-       u8                      *transPtr;
-       int                     readNum;
-       int                     writeNum;
-       int                     cur_mode;
-       int                     manual_stop;
-       int                     result;
-       struct i2c_adapter      adap;
-       struct completion       complete;
-       struct i2c_msg          *pmsg;
-       int                     msg_num;
-       int                     cur_msg;
-       u16                     saved_clkdiv;
-       u16                     saved_control;
-       void __iomem            *regs_base;
-};
-
-
-#define DEFINE_TWI_REG(reg, off) \
-static inline u16 read_##reg(struct bfin_twi_iface *iface) \
-       { return bfin_read16(iface->regs_base + (off)); } \
-static inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \
-       { bfin_write16(iface->regs_base + (off), v); }
-
-DEFINE_TWI_REG(CLKDIV, 0x00)
-DEFINE_TWI_REG(CONTROL, 0x04)
-DEFINE_TWI_REG(SLAVE_CTL, 0x08)
-DEFINE_TWI_REG(SLAVE_STAT, 0x0C)
-DEFINE_TWI_REG(SLAVE_ADDR, 0x10)
-DEFINE_TWI_REG(MASTER_CTL, 0x14)
-DEFINE_TWI_REG(MASTER_STAT, 0x18)
-DEFINE_TWI_REG(MASTER_ADDR, 0x1C)
-DEFINE_TWI_REG(INT_STAT, 0x20)
-DEFINE_TWI_REG(INT_MASK, 0x24)
-DEFINE_TWI_REG(FIFO_CTL, 0x28)
-DEFINE_TWI_REG(FIFO_STAT, 0x2C)
-DEFINE_TWI_REG(XMT_DATA8, 0x80)
-DEFINE_TWI_REG(XMT_DATA16, 0x84)
-DEFINE_TWI_REG(RCV_DATA8, 0x88)
-DEFINE_TWI_REG(RCV_DATA16, 0x8C)
-
-static const u16 pin_req[2][3] = {
-       {P_TWI0_SCL, P_TWI0_SDA, 0},
-       {P_TWI1_SCL, P_TWI1_SDA, 0},
-};
-
 static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
                                        unsigned short twi_int_status)
 {
@@ -99,7 +50,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
                 */
                else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
                        write_MASTER_CTL(iface,
-                               read_MASTER_CTL(iface) | MDIR | RSTART);
+                               read_MASTER_CTL(iface) | MDIR);
                else if (iface->manual_stop)
                        write_MASTER_CTL(iface,
                                read_MASTER_CTL(iface) | STOP);
@@ -107,10 +58,10 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
                         iface->cur_msg + 1 < iface->msg_num) {
                        if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
                                write_MASTER_CTL(iface,
-                                       read_MASTER_CTL(iface) | RSTART | MDIR);
+                                       read_MASTER_CTL(iface) | MDIR);
                        else
                                write_MASTER_CTL(iface,
-                                       (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
+                                       read_MASTER_CTL(iface) & ~MDIR);
                }
        }
        if (twi_int_status & RCVSERV) {
@@ -130,17 +81,25 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
                        }
                        iface->transPtr++;
                        iface->readNum--;
-               } else if (iface->manual_stop) {
-                       write_MASTER_CTL(iface,
-                               read_MASTER_CTL(iface) | STOP);
-               } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
-                          iface->cur_msg + 1 < iface->msg_num) {
-                       if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
-                               write_MASTER_CTL(iface,
-                                       read_MASTER_CTL(iface) | RSTART | MDIR);
-                       else
+               }
+
+               if (iface->readNum == 0) {
+                       if (iface->manual_stop) {
+                               /* Temporary workaround to avoid possible bus stall -
+                                * Flush FIFO before issuing the STOP condition
+                                */
+                               read_RCV_DATA16(iface);
                                write_MASTER_CTL(iface,
-                                       (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
+                                       read_MASTER_CTL(iface) | STOP);
+                       } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+                                       iface->cur_msg + 1 < iface->msg_num) {
+                               if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+                                       write_MASTER_CTL(iface,
+                                               read_MASTER_CTL(iface) | MDIR);
+                               else
+                                       write_MASTER_CTL(iface,
+                                               read_MASTER_CTL(iface) & ~MDIR);
+                       }
                }
        }
        if (twi_int_status & MERR) {
@@ -193,7 +152,8 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
                return;
        }
        if (twi_int_status & MCOMP) {
-               if ((read_MASTER_CTL(iface) & MEN) == 0 &&
+               if (twi_int_status & (XMTSERV | RCVSERV) &&
+                       (read_MASTER_CTL(iface) & MEN) == 0 &&
                        (iface->cur_mode == TWI_I2C_MODE_REPEAT ||
                        iface->cur_mode == TWI_I2C_MODE_COMBINED)) {
                        iface->result = -1;
@@ -221,7 +181,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
                        write_MASTER_CTL(iface,
                                read_MASTER_CTL(iface) & ~RSTART);
                } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
-                               iface->cur_msg+1 < iface->msg_num) {
+                               iface->cur_msg + 1 < iface->msg_num) {
                        iface->cur_msg++;
                        iface->transPtr = iface->pmsg[iface->cur_msg].buf;
                        iface->writeNum = iface->readNum =
@@ -241,27 +201,29 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
                                }
                        }
 
-                       if (iface->pmsg[iface->cur_msg].len <= 255)
-                                       write_MASTER_CTL(iface,
+                       if (iface->pmsg[iface->cur_msg].len <= 255) {
+                               write_MASTER_CTL(iface,
                                        (read_MASTER_CTL(iface) &
                                        (~(0xff << 6))) |
-                               (iface->pmsg[iface->cur_msg].len << 6));
-                       else {
+                                       (iface->pmsg[iface->cur_msg].len << 6));
+                               iface->manual_stop = 0;
+                       } else {
                                write_MASTER_CTL(iface,
                                        (read_MASTER_CTL(iface) |
                                        (0xff << 6)));
                                iface->manual_stop = 1;
                        }
-                       /* remove restart bit and enable master receive */
-                       write_MASTER_CTL(iface,
-                               read_MASTER_CTL(iface) & ~RSTART);
+                       /* remove restart bit before last message */
+                       if (iface->cur_msg + 1 == iface->msg_num)
+                               write_MASTER_CTL(iface,
+                                       read_MASTER_CTL(iface) & ~RSTART);
                } else {
                        iface->result = 1;
                        write_INT_MASK(iface, 0);
                        write_MASTER_CTL(iface, 0);
                }
+               complete(&iface->complete);
        }
-       complete(&iface->complete);
 }
 
 /* Interrupt handler */
@@ -298,8 +260,8 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
        if (!(read_CONTROL(iface) & TWI_ENA))
                return -ENXIO;
 
-       while (read_MASTER_STAT(iface) & BUSBUSY)
-               yield();
+       if (read_MASTER_STAT(iface) & BUSBUSY)
+               return -EAGAIN;
 
        iface->pmsg = msgs;
        iface->msg_num = num;
@@ -311,7 +273,8 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
                return -EINVAL;
        }
 
-       iface->cur_mode = TWI_I2C_MODE_REPEAT;
+       if (iface->msg_num > 1)
+               iface->cur_mode = TWI_I2C_MODE_REPEAT;
        iface->manual_stop = 0;
        iface->transPtr = pmsg->buf;
        iface->writeNum = iface->readNum = pmsg->len;
@@ -356,6 +319,7 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
 
        /* Master enable */
        write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+               (iface->msg_num > 1 ? RSTART : 0) |
                ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
                ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
        SSYNC();
@@ -398,8 +362,8 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
        if (!(read_CONTROL(iface) & TWI_ENA))
                return -ENXIO;
 
-       while (read_MASTER_STAT(iface) & BUSBUSY)
-               yield();
+       if (read_MASTER_STAT(iface) & BUSBUSY)
+               return -EAGAIN;
 
        iface->writeNum = 0;
        iface->readNum = 0;
@@ -520,7 +484,7 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
                else
                        write_MASTER_CTL(iface, 0x1 << 6);
                /* Master enable */
-               write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+               write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN | RSTART |
                        ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
                break;
        default:
@@ -611,9 +575,9 @@ static struct i2c_algorithm bfin_twi_algorithm = {
        .functionality = bfin_twi_functionality,
 };
 
-static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state)
+static int i2c_bfin_twi_suspend(struct device *dev)
 {
-       struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+       struct bfin_twi_iface *iface = dev_get_drvdata(dev);
 
        iface->saved_clkdiv = read_CLKDIV(iface);
        iface->saved_control = read_CONTROL(iface);
@@ -626,14 +590,14 @@ static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state
        return 0;
 }
 
-static int i2c_bfin_twi_resume(struct platform_device *pdev)
+static int i2c_bfin_twi_resume(struct device *dev)
 {
-       struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+       struct bfin_twi_iface *iface = dev_get_drvdata(dev);
 
        int rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
-               0, pdev->name, iface);
+               0, to_platform_device(dev)->name, iface);
        if (rc) {
-               dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
+               dev_err(dev, "Can't get IRQ %d !\n", iface->irq);
                return -ENODEV;
        }
 
@@ -646,6 +610,9 @@ static int i2c_bfin_twi_resume(struct platform_device *pdev)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(i2c_bfin_twi_pm,
+                        i2c_bfin_twi_suspend, i2c_bfin_twi_resume);
+
 static int i2c_bfin_twi_probe(struct platform_device *pdev)
 {
        struct bfin_twi_iface *iface;
@@ -695,7 +662,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
        p_adap->timeout = 5 * HZ;
        p_adap->retries = 3;
 
-       rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
+       rc = peripheral_request_list((unsigned short *)pdev->dev.platform_data,
+                                       "i2c-bfin-twi");
        if (rc) {
                dev_err(&pdev->dev, "Can't setup pin mux!\n");
                goto out_error_pin_mux;
@@ -742,7 +710,7 @@ out_error_add_adapter:
        free_irq(iface->irq, iface);
 out_error_req_irq:
 out_error_no_irq:
-       peripheral_free_list(pin_req[pdev->id]);
+       peripheral_free_list((unsigned short *)pdev->dev.platform_data);
 out_error_pin_mux:
        iounmap(iface->regs_base);
 out_error_ioremap:
@@ -760,7 +728,7 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev)
 
        i2c_del_adapter(&(iface->adap));
        free_irq(iface->irq, iface);
-       peripheral_free_list(pin_req[pdev->id]);
+       peripheral_free_list((unsigned short *)pdev->dev.platform_data);
        iounmap(iface->regs_base);
        kfree(iface);
 
@@ -770,11 +738,10 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev)
 static struct platform_driver i2c_bfin_twi_driver = {
        .probe          = i2c_bfin_twi_probe,
        .remove         = i2c_bfin_twi_remove,
-       .suspend        = i2c_bfin_twi_suspend,
-       .resume         = i2c_bfin_twi_resume,
        .driver         = {
                .name   = "i2c-bfin-twi",
                .owner  = THIS_MODULE,
+               .pm     = &i2c_bfin_twi_pm,
        },
 };
 
index 370031ac8200d4765606437b1ffc8b61967dac12..0722f869465c3ba6e8904aa13c161abed412dbc9 100644 (file)
@@ -117,10 +117,8 @@ static u16 __initdata i2c_clk_div[50][2] = {
 
 struct imx_i2c_struct {
        struct i2c_adapter      adapter;
-       struct resource         *res;
        struct clk              *clk;
        void __iomem            *base;
-       int                     irq;
        wait_queue_head_t       queue;
        unsigned long           i2csr;
        unsigned int            disable_delay;
@@ -472,9 +470,8 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
        struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
        struct pinctrl *pinctrl;
        void __iomem *base;
-       resource_size_t res_size;
-       int irq, bitrate;
-       int ret;
+       int irq, ret;
+       u32 bitrate;
 
        dev_dbg(&pdev->dev, "<%s>\n", __func__);
 
@@ -489,25 +486,15 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
                return -ENOENT;
        }
 
-       res_size = resource_size(res);
-
-       if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
-               dev_err(&pdev->dev, "request_mem_region failed\n");
+       base = devm_request_and_ioremap(&pdev->dev, res);
+       if (!base)
                return -EBUSY;
-       }
-
-       base = ioremap(res->start, res_size);
-       if (!base) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -EIO;
-               goto fail1;
-       }
 
-       i2c_imx = kzalloc(sizeof(struct imx_i2c_struct), GFP_KERNEL);
+       i2c_imx = devm_kzalloc(&pdev->dev, sizeof(struct imx_i2c_struct),
+                               GFP_KERNEL);
        if (!i2c_imx) {
                dev_err(&pdev->dev, "can't allocate interface\n");
-               ret = -ENOMEM;
-               goto fail2;
+               return -ENOMEM;
        }
 
        /* Setup i2c_imx driver structure */
@@ -517,29 +504,27 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
        i2c_imx->adapter.dev.parent     = &pdev->dev;
        i2c_imx->adapter.nr             = pdev->id;
        i2c_imx->adapter.dev.of_node    = pdev->dev.of_node;
-       i2c_imx->irq                    = irq;
        i2c_imx->base                   = base;
-       i2c_imx->res                    = res;
 
        pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
        if (IS_ERR(pinctrl)) {
-               ret = PTR_ERR(pinctrl);
-               goto fail3;
+               dev_err(&pdev->dev, "can't get/select pinctrl\n");
+               return PTR_ERR(pinctrl);
        }
 
        /* Get I2C clock */
-       i2c_imx->clk = clk_get(&pdev->dev, "i2c_clk");
+       i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(i2c_imx->clk)) {
-               ret = PTR_ERR(i2c_imx->clk);
                dev_err(&pdev->dev, "can't get I2C clock\n");
-               goto fail3;
+               return PTR_ERR(i2c_imx->clk);
        }
 
        /* Request IRQ */
-       ret = request_irq(i2c_imx->irq, i2c_imx_isr, 0, pdev->name, i2c_imx);
+       ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
+                               pdev->name, i2c_imx);
        if (ret) {
-               dev_err(&pdev->dev, "can't claim irq %d\n", i2c_imx->irq);
-               goto fail4;
+               dev_err(&pdev->dev, "can't claim irq %d\n", irq);
+               return ret;
        }
 
        /* Init queue */
@@ -564,7 +549,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
        ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
        if (ret < 0) {
                dev_err(&pdev->dev, "registration failed\n");
-               goto fail5;
+               return ret;
        }
 
        of_i2c_register_devices(&i2c_imx->adapter);
@@ -572,28 +557,16 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
        /* Set up platform driver data */
        platform_set_drvdata(pdev, i2c_imx);
 
-       dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", i2c_imx->irq);
+       dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq);
        dev_dbg(&i2c_imx->adapter.dev, "device resources from 0x%x to 0x%x\n",
-               i2c_imx->res->start, i2c_imx->res->end);
-       dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x \n",
-               res_size, i2c_imx->res->start);
+               res->start, res->end);
+       dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x\n",
+               resource_size(res), res->start);
        dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",
                i2c_imx->adapter.name);
        dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
 
        return 0;   /* Return OK */
-
-fail5:
-       free_irq(i2c_imx->irq, i2c_imx);
-fail4:
-       clk_put(i2c_imx->clk);
-fail3:
-       kfree(i2c_imx);
-fail2:
-       iounmap(base);
-fail1:
-       release_mem_region(res->start, resource_size(res));
-       return ret; /* Return error number */
 }
 
 static int __exit i2c_imx_remove(struct platform_device *pdev)
@@ -605,20 +578,12 @@ static int __exit i2c_imx_remove(struct platform_device *pdev)
        i2c_del_adapter(&i2c_imx->adapter);
        platform_set_drvdata(pdev, NULL);
 
-       /* free interrupt */
-       free_irq(i2c_imx->irq, i2c_imx);
-
        /* setup chip registers to defaults */
        writeb(0, i2c_imx->base + IMX_I2C_IADR);
        writeb(0, i2c_imx->base + IMX_I2C_IFDR);
        writeb(0, i2c_imx->base + IMX_I2C_I2CR);
        writeb(0, i2c_imx->base + IMX_I2C_I2SR);
 
-       clk_put(i2c_imx->clk);
-
-       iounmap(i2c_imx->base);
-       release_mem_region(i2c_imx->res->start, resource_size(i2c_imx->res));
-       kfree(i2c_imx);
        return 0;
 }
 
index 4f44a33017b061db314e051f9df882d4dee6a9e0..2e9d56719e997e5318246fc93c4240c7dec6c96e 100644 (file)
 #include <linux/mv643xx_i2c.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_i2c.h>
+#include <linux/clk.h>
+#include <linux/err.h>
 
 /* Register defines */
 #define        MV64XXX_I2C_REG_SLAVE_ADDR                      0x00
@@ -98,6 +103,9 @@ struct mv64xxx_i2c_data {
        int                     rc;
        u32                     freq_m;
        u32                     freq_n;
+#if defined(CONFIG_HAVE_CLK)
+       struct clk              *clk;
+#endif
        wait_queue_head_t       waitq;
        spinlock_t              lock;
        struct i2c_msg          *msg;
@@ -521,6 +529,82 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
        drv_data->reg_base_p = 0;
 }
 
+#ifdef CONFIG_OF
+static int __devinit
+mv64xxx_calc_freq(const int tclk, const int n, const int m)
+{
+       return tclk / (10 * (m + 1) * (2 << n));
+}
+
+static bool __devinit
+mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n,
+                         u32 *best_m)
+{
+       int freq, delta, best_delta = INT_MAX;
+       int m, n;
+
+       for (n = 0; n <= 7; n++)
+               for (m = 0; m <= 15; m++) {
+                       freq = mv64xxx_calc_freq(tclk, n, m);
+                       delta = req_freq - freq;
+                       if (delta >= 0 && delta < best_delta) {
+                               *best_m = m;
+                               *best_n = n;
+                               best_delta = delta;
+                       }
+                       if (best_delta == 0)
+                               return true;
+               }
+       if (best_delta == INT_MAX)
+               return false;
+       return true;
+}
+
+static int __devinit
+mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
+                 struct device_node *np)
+{
+       u32 bus_freq, tclk;
+       int rc = 0;
+
+       /* CLK is mandatory when using DT to describe the i2c bus. We
+        * need to know tclk in order to calculate bus clock
+        * factors.
+        */
+#if !defined(CONFIG_HAVE_CLK)
+       /* Have OF but no CLK */
+       return -ENODEV;
+#else
+       if (IS_ERR(drv_data->clk)) {
+               rc = -ENODEV;
+               goto out;
+       }
+       tclk = clk_get_rate(drv_data->clk);
+       of_property_read_u32(np, "clock-frequency", &bus_freq);
+       if (!mv64xxx_find_baud_factors(bus_freq, tclk,
+                                      &drv_data->freq_n, &drv_data->freq_m)) {
+               rc = -EINVAL;
+               goto out;
+       }
+       drv_data->irq = irq_of_parse_and_map(np, 0);
+
+       /* Its not yet defined how timeouts will be specified in device tree.
+        * So hard code the value to 1 second.
+        */
+       drv_data->adapter.timeout = HZ;
+out:
+       return rc;
+#endif
+}
+#else /* CONFIG_OF */
+static int __devinit
+mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
+                 struct device_node *np)
+{
+       return -ENODEV;
+}
+#endif /* CONFIG_OF */
+
 static int __devinit
 mv64xxx_i2c_probe(struct platform_device *pd)
 {
@@ -528,7 +612,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
        struct mv64xxx_i2c_pdata        *pdata = pd->dev.platform_data;
        int     rc;
 
-       if ((pd->id != 0) || !pdata)
+       if ((!pdata && !pd->dev.of_node))
                return -ENODEV;
 
        drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL);
@@ -546,19 +630,35 @@ mv64xxx_i2c_probe(struct platform_device *pd)
        init_waitqueue_head(&drv_data->waitq);
        spin_lock_init(&drv_data->lock);
 
-       drv_data->freq_m = pdata->freq_m;
-       drv_data->freq_n = pdata->freq_n;
-       drv_data->irq = platform_get_irq(pd, 0);
+#if defined(CONFIG_HAVE_CLK)
+       /* Not all platforms have a clk */
+       drv_data->clk = clk_get(&pd->dev, NULL);
+       if (!IS_ERR(drv_data->clk)) {
+               clk_prepare(drv_data->clk);
+               clk_enable(drv_data->clk);
+       }
+#endif
+       if (pdata) {
+               drv_data->freq_m = pdata->freq_m;
+               drv_data->freq_n = pdata->freq_n;
+               drv_data->irq = platform_get_irq(pd, 0);
+               drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
+       } else if (pd->dev.of_node) {
+               rc = mv64xxx_of_config(drv_data, pd->dev.of_node);
+               if (rc)
+                       goto exit_unmap_regs;
+       }
        if (drv_data->irq < 0) {
                rc = -ENXIO;
                goto exit_unmap_regs;
        }
+
        drv_data->adapter.dev.parent = &pd->dev;
        drv_data->adapter.algo = &mv64xxx_i2c_algo;
        drv_data->adapter.owner = THIS_MODULE;
        drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
-       drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
        drv_data->adapter.nr = pd->id;
+       drv_data->adapter.dev.of_node = pd->dev.of_node;
        platform_set_drvdata(pd, drv_data);
        i2c_set_adapdata(&drv_data->adapter, drv_data);
 
@@ -577,11 +677,20 @@ mv64xxx_i2c_probe(struct platform_device *pd)
                goto exit_free_irq;
        }
 
+       of_i2c_register_devices(&drv_data->adapter);
+
        return 0;
 
        exit_free_irq:
                free_irq(drv_data->irq, drv_data);
        exit_unmap_regs:
+#if defined(CONFIG_HAVE_CLK)
+       /* Not all platforms have a clk */
+       if (!IS_ERR(drv_data->clk)) {
+               clk_disable(drv_data->clk);
+               clk_unprepare(drv_data->clk);
+       }
+#endif
                mv64xxx_i2c_unmap_regs(drv_data);
        exit_kfree:
                kfree(drv_data);
@@ -597,17 +706,31 @@ mv64xxx_i2c_remove(struct platform_device *dev)
        rc = i2c_del_adapter(&drv_data->adapter);
        free_irq(drv_data->irq, drv_data);
        mv64xxx_i2c_unmap_regs(drv_data);
+#if defined(CONFIG_HAVE_CLK)
+       /* Not all platforms have a clk */
+       if (!IS_ERR(drv_data->clk)) {
+               clk_disable(drv_data->clk);
+               clk_unprepare(drv_data->clk);
+       }
+#endif
        kfree(drv_data);
 
        return rc;
 }
 
+static const struct of_device_id mv64xxx_i2c_of_match_table[] __devinitdata = {
+       { .compatible = "marvell,mv64xxx-i2c", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
+
 static struct platform_driver mv64xxx_i2c_driver = {
        .probe  = mv64xxx_i2c_probe,
        .remove = __devexit_p(mv64xxx_i2c_remove),
        .driver = {
                .owner  = THIS_MODULE,
                .name   = MV64XXX_I2C_CTLR_NAME,
+               .of_match_table = of_match_ptr(mv64xxx_i2c_of_match_table),
        },
 };
 
index 04eb441b6ce1945b8375b81cb7c7cd89cf172f7c..088c5c1ed17dfe831c4345ee8f02dd0ef4e1c82d 100644 (file)
 #define MXS_I2C_CTRL0_DIRECTION                        0x00010000
 #define MXS_I2C_CTRL0_XFER_COUNT(v)            ((v) & 0x0000FFFF)
 
+#define MXS_I2C_TIMING0                (0x10)
+#define MXS_I2C_TIMING1                (0x20)
+#define MXS_I2C_TIMING2                (0x30)
+
 #define MXS_I2C_CTRL1          (0x40)
 #define MXS_I2C_CTRL1_SET      (0x44)
 #define MXS_I2C_CTRL1_CLR      (0x48)
 #define MXS_CMD_I2C_READ       (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \
                                 MXS_I2C_CTRL0_MASTER_MODE)
 
+struct mxs_i2c_speed_config {
+       uint32_t        timing0;
+       uint32_t        timing1;
+       uint32_t        timing2;
+};
+
+/*
+ * Timing values for the default 24MHz clock supplied into the i2c block.
+ *
+ * The bus can operate at 95kHz or at 400kHz with the following timing
+ * register configurations. The 100kHz mode isn't present because it's
+ * values are not stated in the i.MX233/i.MX28 datasheet. The 95kHz mode
+ * shall be close enough replacement. Therefore when the bus is configured
+ * for 100kHz operation, 95kHz timing settings are actually loaded.
+ *
+ * For details, see i.MX233 [25.4.2 - 25.4.4] and i.MX28 [27.5.2 - 27.5.4].
+ */
+static const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
+       .timing0        = 0x00780030,
+       .timing1        = 0x00800030,
+       .timing2        = 0x00300030,
+};
+
+static const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
+       .timing0        = 0x000f0007,
+       .timing1        = 0x001f000f,
+       .timing2        = 0x00300030,
+};
+
 /**
  * struct mxs_i2c_dev - per device, private MXS-I2C data
  *
@@ -112,11 +145,17 @@ struct mxs_i2c_dev {
        struct completion cmd_complete;
        u32 cmd_err;
        struct i2c_adapter adapter;
+       const struct mxs_i2c_speed_config *speed;
 };
 
 static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
 {
        stmp_reset_block(i2c->regs);
+
+       writel(i2c->speed->timing0, i2c->regs + MXS_I2C_TIMING0);
+       writel(i2c->speed->timing1, i2c->regs + MXS_I2C_TIMING1);
+       writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);
+
        writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
        writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
                        i2c->regs + MXS_I2C_QUEUECTRL_SET);
@@ -193,7 +232,7 @@ static int mxs_i2c_wait_for_data(struct mxs_i2c_dev *i2c)
 
 static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)
 {
-       u32 data;
+       u32 uninitialized_var(data);
        int i;
 
        for (i = 0; i < len; i++) {
@@ -319,6 +358,28 @@ static const struct i2c_algorithm mxs_i2c_algo = {
        .functionality = mxs_i2c_func,
 };
 
+static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
+{
+       uint32_t speed;
+       struct device *dev = i2c->dev;
+       struct device_node *node = dev->of_node;
+       int ret;
+
+       if (!node)
+               return -EINVAL;
+
+       i2c->speed = &mxs_i2c_95kHz_config;
+       ret = of_property_read_u32(node, "clock-frequency", &speed);
+       if (ret)
+               dev_warn(dev, "No I2C speed selected, using 100kHz\n");
+       else if (speed == 400000)
+               i2c->speed = &mxs_i2c_400kHz_config;
+       else if (speed != 100000)
+               dev_warn(dev, "Unsupported I2C speed selected, using 100kHz\n");
+
+       return 0;
+}
+
 static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -358,6 +419,11 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
                return err;
 
        i2c->dev = dev;
+
+       err = mxs_i2c_get_ofdata(i2c);
+       if (err)
+               return err;
+
        platform_set_drvdata(pdev, i2c);
 
        /* Do reset to enforce correct startup after pinmuxing */
index a92440dbef078ba18c6c5561a74f7f8265ba72c4..5e6f1eed4f83f233da76202c70d7564f773d3e1c 100644 (file)
@@ -14,7 +14,8 @@
  */
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
+#include <linux/atomic.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
@@ -23,8 +24,7 @@
 #include <linux/io.h>
 #include <linux/regulator/consumer.h>
 #include <linux/pm_runtime.h>
-
-#include <plat/i2c.h>
+#include <linux/platform_data/i2c-nomadik.h>
 
 #define DRIVER_NAME "nmk-i2c"
 
@@ -136,7 +136,7 @@ struct i2c_nmk_client {
 
 /**
  * struct nmk_i2c_dev - private data structure of the controller.
- * @pdev: parent platform device.
+ * @adev: parent amba device.
  * @adap: corresponding I2C adapter.
  * @irq: interrupt line for the controller.
  * @virtbase: virtual io memory area.
@@ -150,7 +150,7 @@ struct i2c_nmk_client {
  * @busy: Busy doing transfer.
  */
 struct nmk_i2c_dev {
-       struct platform_device          *pdev;
+       struct amba_device              *adev;
        struct i2c_adapter              adap;
        int                             irq;
        void __iomem                    *virtbase;
@@ -217,7 +217,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
                }
        }
 
-       dev_err(&dev->pdev->dev,
+       dev_err(&dev->adev->dev,
                "flushing operation timed out giving up after %d attempts",
                LOOP_ATTEMPTS);
 
@@ -276,15 +276,32 @@ exit:
 /**
  * load_i2c_mcr_reg() - load the MCR register
  * @dev: private data of controller
+ * @flags: message flags
  */
-static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev)
+static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev, u16 flags)
 {
        u32 mcr = 0;
+       unsigned short slave_adr_3msb_bits;
 
-       /* 7-bit address transaction */
-       mcr |= GEN_MASK(1, I2C_MCR_AM, 12);
        mcr |= GEN_MASK(dev->cli.slave_adr, I2C_MCR_A7, 1);
 
+       if (unlikely(flags & I2C_M_TEN)) {
+               /* 10-bit address transaction */
+               mcr |= GEN_MASK(2, I2C_MCR_AM, 12);
+               /*
+                * Get the top 3 bits.
+                * EA10 represents extended address in MCR. This includes
+                * the extension (MSB bits) of the 7 bit address loaded
+                * in A7
+                */
+               slave_adr_3msb_bits = (dev->cli.slave_adr >> 7) & 0x7;
+
+               mcr |= GEN_MASK(slave_adr_3msb_bits, I2C_MCR_EA10, 8);
+       } else {
+               /* 7-bit address transaction */
+               mcr |= GEN_MASK(1, I2C_MCR_AM, 12);
+       }
+
        /* start byte procedure not applied */
        mcr |= GEN_MASK(0, I2C_MCR_SB, 11);
 
@@ -364,7 +381,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
         * and high speed (up to 3.4 Mb/s)
         */
        if (dev->cfg.sm > I2C_FREQ_MODE_FAST) {
-               dev_err(&dev->pdev->dev,
+               dev_err(&dev->adev->dev,
                        "do not support this mode defaulting to std. mode\n");
                brcr2 = i2c_clk/(100000 * 2) & 0xffff;
                writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
@@ -381,19 +398,20 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
 /**
  * read_i2c() - Read from I2C client device
  * @dev: private data of I2C Driver
+ * @flags: message flags
  *
  * This function reads from i2c client device when controller is in
  * master mode. There is a completion timeout. If there is no transfer
  * before timeout error is returned.
  */
-static int read_i2c(struct nmk_i2c_dev *dev)
+static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
 {
        u32 status = 0;
        u32 mcr;
        u32 irq_mask = 0;
        int timeout;
 
-       mcr = load_i2c_mcr_reg(dev);
+       mcr = load_i2c_mcr_reg(dev, flags);
        writel(mcr, dev->virtbase + I2C_MCR);
 
        /* load the current CR value */
@@ -423,7 +441,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
                &dev->xfer_complete, dev->adap.timeout);
 
        if (timeout < 0) {
-               dev_err(&dev->pdev->dev,
+               dev_err(&dev->adev->dev,
                        "wait_for_completion_timeout "
                        "returned %d waiting for event\n", timeout);
                status = timeout;
@@ -431,7 +449,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
 
        if (timeout == 0) {
                /* Controller timed out */
-               dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n",
+               dev_err(&dev->adev->dev, "read from slave 0x%x timed out\n",
                                dev->cli.slave_adr);
                status = -ETIMEDOUT;
        }
@@ -459,17 +477,18 @@ static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes)
 /**
  * write_i2c() - Write data to I2C client.
  * @dev: private data of I2C Driver
+ * @flags: message flags
  *
  * This function writes data to I2C client
  */
-static int write_i2c(struct nmk_i2c_dev *dev)
+static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
 {
        u32 status = 0;
        u32 mcr;
        u32 irq_mask = 0;
        int timeout;
 
-       mcr = load_i2c_mcr_reg(dev);
+       mcr = load_i2c_mcr_reg(dev, flags);
 
        writel(mcr, dev->virtbase + I2C_MCR);
 
@@ -510,7 +529,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
                &dev->xfer_complete, dev->adap.timeout);
 
        if (timeout < 0) {
-               dev_err(&dev->pdev->dev,
+               dev_err(&dev->adev->dev,
                        "wait_for_completion_timeout "
                        "returned %d waiting for event\n", timeout);
                status = timeout;
@@ -518,7 +537,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
 
        if (timeout == 0) {
                /* Controller timed out */
-               dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n",
+               dev_err(&dev->adev->dev, "write to slave 0x%x timed out\n",
                                dev->cli.slave_adr);
                status = -ETIMEDOUT;
        }
@@ -538,11 +557,11 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
        if (flags & I2C_M_RD) {
                /* read operation */
                dev->cli.operation = I2C_READ;
-               status = read_i2c(dev);
+               status = read_i2c(dev, flags);
        } else {
                /* write operation */
                dev->cli.operation = I2C_WRITE;
-               status = write_i2c(dev);
+               status = write_i2c(dev, flags);
        }
 
        if (status || (dev->result)) {
@@ -557,7 +576,7 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
                if (((i2c_sr >> 2) & 0x3) == 0x3) {
                        /* get the abort cause */
                        cause = (i2c_sr >> 4) & 0x7;
-                       dev_err(&dev->pdev->dev, "%s\n",
+                       dev_err(&dev->adev->dev, "%s\n",
                                cause >= ARRAY_SIZE(abort_causes) ?
                                "unknown reason" :
                                abort_causes[cause]);
@@ -630,7 +649,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
 
        if (dev->regulator)
                regulator_enable(dev->regulator);
-       pm_runtime_get_sync(&dev->pdev->dev);
+       pm_runtime_get_sync(&dev->adev->dev);
 
        clk_enable(dev->clk);
 
@@ -644,13 +663,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
                setup_i2c_controller(dev);
 
                for (i = 0; i < num_msgs; i++) {
-                       if (unlikely(msgs[i].flags & I2C_M_TEN)) {
-                               dev_err(&dev->pdev->dev,
-                                       "10 bit addressing not supported\n");
-
-                               status = -EINVAL;
-                               goto out;
-                       }
                        dev->cli.slave_adr      = msgs[i].addr;
                        dev->cli.buffer         = msgs[i].buf;
                        dev->cli.count          = msgs[i].len;
@@ -667,7 +679,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
 
 out:
        clk_disable(dev->clk);
-       pm_runtime_put_sync(&dev->pdev->dev);
+       pm_runtime_put_sync(&dev->adev->dev);
        if (dev->regulator)
                regulator_disable(dev->regulator);
 
@@ -790,7 +802,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 
                if (dev->cli.count) {
                        dev->result = -EIO;
-                       dev_err(&dev->pdev->dev,
+                       dev_err(&dev->adev->dev,
                                "%lu bytes still remain to be xfered\n",
                                dev->cli.count);
                        (void) init_hw(dev);
@@ -834,7 +846,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
                dev->result = -EIO;
                (void) init_hw(dev);
 
-               dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
+               dev_err(&dev->adev->dev, "Tx Fifo Over run\n");
                complete(&dev->xfer_complete);
 
                break;
@@ -847,10 +859,10 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
        case I2C_IT_RFSE:
        case I2C_IT_WTSR:
        case I2C_IT_STD:
-               dev_err(&dev->pdev->dev, "unhandled Interrupt\n");
+               dev_err(&dev->adev->dev, "unhandled Interrupt\n");
                break;
        default:
-               dev_err(&dev->pdev->dev, "spurious Interrupt..\n");
+               dev_err(&dev->adev->dev, "spurious Interrupt..\n");
                break;
        }
 
@@ -861,8 +873,8 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 #ifdef CONFIG_PM
 static int nmk_i2c_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev);
+       struct amba_device *adev = to_amba_device(dev);
+       struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
 
        if (nmk_i2c->busy)
                return -EBUSY;
@@ -891,7 +903,7 @@ static const struct dev_pm_ops nmk_i2c_pm = {
 
 static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
 {
-       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
 }
 
 static const struct i2c_algorithm nmk_i2c_algo = {
@@ -899,78 +911,69 @@ static const struct i2c_algorithm nmk_i2c_algo = {
        .functionality  = nmk_i2c_functionality
 };
 
-static int __devinit nmk_i2c_probe(struct platform_device *pdev)
+static atomic_t adapter_id = ATOMIC_INIT(0);
+
+static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
 {
        int ret = 0;
-       struct resource *res;
        struct nmk_i2c_controller *pdata =
-                       pdev->dev.platform_data;
+                       adev->dev.platform_data;
        struct nmk_i2c_dev      *dev;
        struct i2c_adapter *adap;
 
+       if (!pdata) {
+               dev_warn(&adev->dev, "no platform data\n");
+               return -ENODEV;
+       }
        dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
        if (!dev) {
-               dev_err(&pdev->dev, "cannot allocate memory\n");
+               dev_err(&adev->dev, "cannot allocate memory\n");
                ret = -ENOMEM;
                goto err_no_mem;
        }
        dev->busy = false;
-       dev->pdev = pdev;
-       platform_set_drvdata(pdev, dev);
+       dev->adev = adev;
+       amba_set_drvdata(adev, dev);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENOENT;
-               goto err_no_resource;
-       }
-
-       if (request_mem_region(res->start, resource_size(res),
-               DRIVER_NAME "I/O region") == NULL) {
-               ret = -EBUSY;
-               goto err_no_region;
-       }
-
-       dev->virtbase = ioremap(res->start, resource_size(res));
+       dev->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
        if (!dev->virtbase) {
                ret = -ENOMEM;
                goto err_no_ioremap;
        }
 
-       dev->irq = platform_get_irq(pdev, 0);
+       dev->irq = adev->irq[0];
        ret = request_irq(dev->irq, i2c_irq_handler, 0,
                                DRIVER_NAME, dev);
        if (ret) {
-               dev_err(&pdev->dev, "cannot claim the irq %d\n", dev->irq);
+               dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq);
                goto err_irq;
        }
 
-       dev->regulator = regulator_get(&pdev->dev, "v-i2c");
+       dev->regulator = regulator_get(&adev->dev, "v-i2c");
        if (IS_ERR(dev->regulator)) {
-               dev_warn(&pdev->dev, "could not get i2c regulator\n");
+               dev_warn(&adev->dev, "could not get i2c regulator\n");
                dev->regulator = NULL;
        }
 
-       pm_suspend_ignore_children(&pdev->dev, true);
-       pm_runtime_enable(&pdev->dev);
+       pm_suspend_ignore_children(&adev->dev, true);
 
-       dev->clk = clk_get(&pdev->dev, NULL);
+       dev->clk = clk_get(&adev->dev, NULL);
        if (IS_ERR(dev->clk)) {
-               dev_err(&pdev->dev, "could not get i2c clock\n");
+               dev_err(&adev->dev, "could not get i2c clock\n");
                ret = PTR_ERR(dev->clk);
                goto err_no_clk;
        }
 
        adap = &dev->adap;
-       adap->dev.parent = &pdev->dev;
+       adap->dev.parent = &adev->dev;
        adap->owner     = THIS_MODULE;
        adap->class     = I2C_CLASS_HWMON | I2C_CLASS_SPD;
        adap->algo      = &nmk_i2c_algo;
        adap->timeout   = msecs_to_jiffies(pdata->timeout);
+       adap->nr = atomic_read(&adapter_id);
        snprintf(adap->name, sizeof(adap->name),
-                "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
-
-       /* fetch the controller id */
-       adap->nr        = pdev->id;
+                "Nomadik I2C%d at %pR", adap->nr, &adev->res);
+       atomic_inc(&adapter_id);
 
        /* fetch the controller configuration from machine */
        dev->cfg.clk_freq = pdata->clk_freq;
@@ -981,16 +984,18 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 
        i2c_set_adapdata(adap, dev);
 
-       dev_info(&pdev->dev,
+       dev_info(&adev->dev,
                 "initialize %s on virtual base %p\n",
                 adap->name, dev->virtbase);
 
        ret = i2c_add_numbered_adapter(adap);
        if (ret) {
-               dev_err(&pdev->dev, "failed to add adapter\n");
+               dev_err(&adev->dev, "failed to add adapter\n");
                goto err_add_adap;
        }
 
+       pm_runtime_put(&adev->dev);
+
        return 0;
 
  err_add_adap:
@@ -998,25 +1003,21 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
  err_no_clk:
        if (dev->regulator)
                regulator_put(dev->regulator);
-       pm_runtime_disable(&pdev->dev);
        free_irq(dev->irq, dev);
  err_irq:
        iounmap(dev->virtbase);
  err_no_ioremap:
-       release_mem_region(res->start, resource_size(res));
- err_no_region:
-       platform_set_drvdata(pdev, NULL);
- err_no_resource:
+       amba_set_drvdata(adev, NULL);
        kfree(dev);
  err_no_mem:
 
        return ret;
 }
 
-static int __devexit nmk_i2c_remove(struct platform_device *pdev)
+static int nmk_i2c_remove(struct amba_device *adev)
 {
-       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       struct nmk_i2c_dev *dev = platform_get_drvdata(pdev);
+       struct resource *res = &adev->res;
+       struct nmk_i2c_dev *dev = amba_get_drvdata(adev);
 
        i2c_del_adapter(&dev->adap);
        flush_i2c_fifo(dev);
@@ -1031,31 +1032,46 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)
        clk_put(dev->clk);
        if (dev->regulator)
                regulator_put(dev->regulator);
-       pm_runtime_disable(&pdev->dev);
-       platform_set_drvdata(pdev, NULL);
+       pm_runtime_disable(&adev->dev);
+       amba_set_drvdata(adev, NULL);
        kfree(dev);
 
        return 0;
 }
 
-static struct platform_driver nmk_i2c_driver = {
-       .driver = {
+static struct amba_id nmk_i2c_ids[] = {
+       {
+               .id     = 0x00180024,
+               .mask   = 0x00ffffff,
+       },
+       {
+               .id     = 0x00380024,
+               .mask   = 0x00ffffff,
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(amba, nmk_i2c_ids);
+
+static struct amba_driver nmk_i2c_driver = {
+       .drv = {
                .owner = THIS_MODULE,
                .name = DRIVER_NAME,
                .pm = &nmk_i2c_pm,
        },
+       .id_table = nmk_i2c_ids,
        .probe = nmk_i2c_probe,
-       .remove = __devexit_p(nmk_i2c_remove),
+       .remove = nmk_i2c_remove,
 };
 
 static int __init nmk_i2c_init(void)
 {
-       return platform_driver_register(&nmk_i2c_driver);
+       return amba_driver_register(&nmk_i2c_driver);
 }
 
 static void __exit nmk_i2c_exit(void)
 {
-       platform_driver_unregister(&nmk_i2c_driver);
+       amba_driver_unregister(&nmk_i2c_driver);
 }
 
 subsys_initcall(nmk_i2c_init);
@@ -1064,4 +1080,3 @@ module_exit(nmk_i2c_exit);
 MODULE_AUTHOR("Sachin Verma, Srinidhi KASAGAR");
 MODULE_DESCRIPTION("Nomadik/Ux500 I2C driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRIVER_NAME);
index 75194c579b6d78f419f8886de4d028a2447e08a4..bffd5501ac2ddd5516f29dfb08bb12add1e196fe 100644 (file)
  */
 
 /*
- * Device tree configuration:
- *
- * Required properties:
- * - compatible      : "opencores,i2c-ocores"
- * - reg             : bus address start and address range size of device
- * - interrupts      : interrupt number
- * - regstep         : size of device registers in bytes
- * - clock-frequency : frequency of bus clock in Hz
- * 
- * Example:
- *
- *  i2c0: ocores@a0000000 {
- *              compatible = "opencores,i2c-ocores";
- *              reg = <0xa0000000 0x8>;
- *              interrupts = <10>;
- *
- *              regstep = <1>;
- *              clock-frequency = <20000000>;
- *
- * -- Devices connected on this I2C bus get
- * -- defined here; address- and size-cells
- * -- apply to these child devices
- *
- *              #address-cells = <1>;
- *              #size-cells = <0>;
- *
- *              dummy@60 {
- *                     compatible = "dummy";
- *                     reg = <60>;
- *              };
- *  };
- *
+ * This driver can be used from the device tree, see
+ *     Documentation/devicetree/bindings/i2c/ocore-i2c.txt
  */
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/of_i2c.h>
+#include <linux/log2.h>
 
 struct ocores_i2c {
        void __iomem *base;
-       int regstep;
+       u32 reg_shift;
+       u32 reg_io_width;
        wait_queue_head_t wait;
        struct i2c_adapter adap;
        struct i2c_msg *msg;
@@ -102,12 +73,22 @@ struct ocores_i2c {
 
 static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
 {
-       iowrite8(value, i2c->base + reg * i2c->regstep);
+       if (i2c->reg_io_width == 4)
+               iowrite32(value, i2c->base + (reg << i2c->reg_shift));
+       else if (i2c->reg_io_width == 2)
+               iowrite16(value, i2c->base + (reg << i2c->reg_shift));
+       else
+               iowrite8(value, i2c->base + (reg << i2c->reg_shift));
 }
 
 static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
 {
-       return ioread8(i2c->base + reg * i2c->regstep);
+       if (i2c->reg_io_width == 4)
+               return ioread32(i2c->base + (reg << i2c->reg_shift));
+       else if (i2c->reg_io_width == 2)
+               return ioread16(i2c->base + (reg << i2c->reg_shift));
+       else
+               return ioread8(i2c->base + (reg << i2c->reg_shift));
 }
 
 static void ocores_process(struct ocores_i2c *i2c)
@@ -247,26 +228,35 @@ static struct i2c_adapter ocores_adapter = {
 };
 
 #ifdef CONFIG_OF
-static int ocores_i2c_of_probe(struct platform_devicepdev,
-                               struct ocores_i2ci2c)
+static int ocores_i2c_of_probe(struct platform_device *pdev,
+                               struct ocores_i2c *i2c)
 {
-       const __be32* val;
-
-       val = of_get_property(pdev->dev.of_node, "regstep", NULL);
-       if (!val) {
-               dev_err(&pdev->dev, "Missing required parameter 'regstep'");
-               return -ENODEV;
+       struct device_node *np = pdev->dev.of_node;
+       u32 val;
+
+       if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) {
+               /* no 'reg-shift', check for deprecated 'regstep' */
+               if (!of_property_read_u32(np, "regstep", &val)) {
+                       if (!is_power_of_2(val)) {
+                               dev_err(&pdev->dev, "invalid regstep %d\n",
+                                       val);
+                               return -EINVAL;
+                       }
+                       i2c->reg_shift = ilog2(val);
+                       dev_warn(&pdev->dev,
+                               "regstep property deprecated, use reg-shift\n");
+               }
        }
-       i2c->regstep = be32_to_cpup(val);
 
-       val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL);
-       if (!val) {
+       if (of_property_read_u32(np, "clock-frequency", &val)) {
                dev_err(&pdev->dev,
-                       "Missing required parameter 'clock-frequency'");
+                       "Missing required parameter 'clock-frequency'\n");
                return -ENODEV;
        }
-       i2c->clock_khz = be32_to_cpup(val) / 1000;
+       i2c->clock_khz = val / 1000;
 
+       of_property_read_u32(pdev->dev.of_node, "reg-io-width",
+                               &i2c->reg_io_width);
        return 0;
 }
 #else
@@ -308,7 +298,8 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
 
        pdata = pdev->dev.platform_data;
        if (pdata) {
-               i2c->regstep = pdata->regstep;
+               i2c->reg_shift = pdata->reg_shift;
+               i2c->reg_io_width = pdata->reg_io_width;
                i2c->clock_khz = pdata->clock_khz;
        } else {
                ret = ocores_i2c_of_probe(pdev, i2c);
@@ -316,6 +307,9 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
                        return ret;
        }
 
+       if (i2c->reg_io_width == 0)
+               i2c->reg_io_width = 1; /* Set to default value */
+
        ocores_init(i2c);
 
        init_waitqueue_head(&i2c->wait);
@@ -351,7 +345,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit ocores_i2c_remove(struct platform_devicepdev)
+static int __devexit ocores_i2c_remove(struct platform_device *pdev)
 {
        struct ocores_i2c *i2c = platform_get_drvdata(pdev);
 
@@ -367,9 +361,9 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev)
 }
 
 #ifdef CONFIG_PM
-static int ocores_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+static int ocores_i2c_suspend(struct device *dev)
 {
-       struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+       struct ocores_i2c *i2c = dev_get_drvdata(dev);
        u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
 
        /* make sure the device is disabled */
@@ -378,17 +372,19 @@ static int ocores_i2c_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int ocores_i2c_resume(struct platform_device *pdev)
+static int ocores_i2c_resume(struct device *dev)
 {
-       struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+       struct ocores_i2c *i2c = dev_get_drvdata(dev);
 
        ocores_init(i2c);
 
        return 0;
 }
+
+static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume);
+#define OCORES_I2C_PM  (&ocores_i2c_pm)
 #else
-#define ocores_i2c_suspend     NULL
-#define ocores_i2c_resume      NULL
+#define OCORES_I2C_PM  NULL
 #endif
 
 static struct of_device_id ocores_i2c_match[] = {
@@ -400,12 +396,11 @@ MODULE_DEVICE_TABLE(of, ocores_i2c_match);
 static struct platform_driver ocores_i2c_driver = {
        .probe   = ocores_i2c_probe,
        .remove  = __devexit_p(ocores_i2c_remove),
-       .suspend = ocores_i2c_suspend,
-       .resume  = ocores_i2c_resume,
        .driver  = {
                .owner = THIS_MODULE,
                .name = "ocores-i2c",
                .of_match_table = ocores_i2c_match,
+               .pm = OCORES_I2C_PM,
        },
 };
 
index ee139a598814ea46da91fc494d6d2ded770ddef4..f44c83549fe5a4c5380eb8e18f5d19faae77c9c7 100644 (file)
@@ -2,7 +2,7 @@
  * (C) Copyright 2009-2010
  * Nokia Siemens Networks, michael.lawnick.ext@nsn.com
  *
- * Portions Copyright (C) 2010 Cavium Networks, Inc.
+ * Portions Copyright (C) 2010, 2011 Cavium Networks, Inc.
  *
  * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
  *
  * warranty of any kind, whether express or implied.
  */
 
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of_i2c.h>
+#include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-
-#include <linux/io.h>
 #include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of.h>
 
 #include <asm/octeon/octeon.h>
 
@@ -65,7 +66,7 @@ struct octeon_i2c {
        wait_queue_head_t queue;
        struct i2c_adapter adap;
        int irq;
-       int twsi_freq;
+       u32 twsi_freq;
        int sys_freq;
        resource_size_t twsi_phys;
        void __iomem *twsi_base;
@@ -121,10 +122,8 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
  */
 static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
 {
-       u64 tmp;
-
        __raw_writeq(data, i2c->twsi_base + TWSI_INT);
-       tmp = __raw_readq(i2c->twsi_base + TWSI_INT);
+       __raw_readq(i2c->twsi_base + TWSI_INT);
 }
 
 /**
@@ -515,7 +514,6 @@ static int __devinit octeon_i2c_probe(struct platform_device *pdev)
 {
        int irq, result = 0;
        struct octeon_i2c *i2c;
-       struct octeon_i2c_data *i2c_data;
        struct resource *res_mem;
 
        /* All adaptors have an irq.  */
@@ -523,86 +521,90 @@ static int __devinit octeon_i2c_probe(struct platform_device *pdev)
        if (irq < 0)
                return irq;
 
-       i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+       i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
        if (!i2c) {
                dev_err(&pdev->dev, "kzalloc failed\n");
                result = -ENOMEM;
                goto out;
        }
        i2c->dev = &pdev->dev;
-       i2c_data = pdev->dev.platform_data;
 
        res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        if (res_mem == NULL) {
                dev_err(i2c->dev, "found no memory resource\n");
                result = -ENXIO;
-               goto fail_region;
+               goto out;
        }
+       i2c->twsi_phys = res_mem->start;
+       i2c->regsize = resource_size(res_mem);
 
-       if (i2c_data == NULL) {
-               dev_err(i2c->dev, "no I2C frequency data\n");
+       /*
+        * "clock-rate" is a legacy binding, the official binding is
+        * "clock-frequency".  Try the official one first and then
+        * fall back if it doesn't exist.
+        */
+       if (of_property_read_u32(pdev->dev.of_node,
+                                "clock-frequency", &i2c->twsi_freq) &&
+           of_property_read_u32(pdev->dev.of_node,
+                                "clock-rate", &i2c->twsi_freq)) {
+               dev_err(i2c->dev,
+                       "no I2C 'clock-rate' or 'clock-frequency' property\n");
                result = -ENXIO;
-               goto fail_region;
+               goto out;
        }
 
-       i2c->twsi_phys = res_mem->start;
-       i2c->regsize = resource_size(res_mem);
-       i2c->twsi_freq = i2c_data->i2c_freq;
-       i2c->sys_freq = i2c_data->sys_freq;
+       i2c->sys_freq = octeon_get_io_clock_rate();
 
-       if (!request_mem_region(i2c->twsi_phys, i2c->regsize, res_mem->name)) {
+       if (!devm_request_mem_region(&pdev->dev, i2c->twsi_phys, i2c->regsize,
+                                     res_mem->name)) {
                dev_err(i2c->dev, "request_mem_region failed\n");
-               goto fail_region;
+               goto out;
        }
-       i2c->twsi_base = ioremap(i2c->twsi_phys, i2c->regsize);
+       i2c->twsi_base = devm_ioremap(&pdev->dev, i2c->twsi_phys, i2c->regsize);
 
        init_waitqueue_head(&i2c->queue);
 
        i2c->irq = irq;
 
-       result = request_irq(i2c->irq, octeon_i2c_isr, 0, DRV_NAME, i2c);
+       result = devm_request_irq(&pdev->dev, i2c->irq,
+                                 octeon_i2c_isr, 0, DRV_NAME, i2c);
        if (result < 0) {
                dev_err(i2c->dev, "failed to attach interrupt\n");
-               goto fail_irq;
+               goto out;
        }
 
        result = octeon_i2c_initlowlevel(i2c);
        if (result) {
                dev_err(i2c->dev, "init low level failed\n");
-               goto  fail_add;
+               goto  out;
        }
 
        result = octeon_i2c_setclock(i2c);
        if (result) {
                dev_err(i2c->dev, "clock init failed\n");
-               goto  fail_add;
+               goto  out;
        }
 
        i2c->adap = octeon_i2c_ops;
        i2c->adap.dev.parent = &pdev->dev;
-       i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;
+       i2c->adap.dev.of_node = pdev->dev.of_node;
        i2c_set_adapdata(&i2c->adap, i2c);
        platform_set_drvdata(pdev, i2c);
 
-       result = i2c_add_numbered_adapter(&i2c->adap);
+       result = i2c_add_adapter(&i2c->adap);
        if (result < 0) {
                dev_err(i2c->dev, "failed to add adapter\n");
                goto fail_add;
        }
-
        dev_info(i2c->dev, "version %s\n", DRV_VERSION);
 
-       return result;
+       of_i2c_register_devices(&i2c->adap);
+
+       return 0;
 
 fail_add:
        platform_set_drvdata(pdev, NULL);
-       free_irq(i2c->irq, i2c);
-fail_irq:
-       iounmap(i2c->twsi_base);
-       release_mem_region(i2c->twsi_phys, i2c->regsize);
-fail_region:
-       kfree(i2c);
 out:
        return result;
 };
@@ -613,19 +615,24 @@ static int __devexit octeon_i2c_remove(struct platform_device *pdev)
 
        i2c_del_adapter(&i2c->adap);
        platform_set_drvdata(pdev, NULL);
-       free_irq(i2c->irq, i2c);
-       iounmap(i2c->twsi_base);
-       release_mem_region(i2c->twsi_phys, i2c->regsize);
-       kfree(i2c);
        return 0;
 };
 
+static struct of_device_id octeon_i2c_match[] = {
+       {
+               .compatible = "cavium,octeon-3860-twsi",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, octeon_i2c_match);
+
 static struct platform_driver octeon_i2c_driver = {
        .probe          = octeon_i2c_probe,
        .remove         = __devexit_p(octeon_i2c_remove),
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = DRV_NAME,
+               .of_match_table = octeon_i2c_match,
        },
 };
 
@@ -635,4 +642,3 @@ MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>");
 MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-MODULE_ALIAS("platform:" DRV_NAME);
index c2148332de0f641fdffcdd395741785cee93af77..6849635b268a81fe8f85d380d2d80d16ba6ab2b1 100644 (file)
@@ -49,8 +49,8 @@
 
 /* I2C controller revisions present on specific hardware */
 #define OMAP_I2C_REV_ON_2430           0x36
-#define OMAP_I2C_REV_ON_3430           0x3C
-#define OMAP_I2C_REV_ON_3530_4430      0x40
+#define OMAP_I2C_REV_ON_3430_3530      0x3C
+#define OMAP_I2C_REV_ON_3630_4430      0x40
 
 /* timeout waiting for the controller to respond */
 #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
@@ -173,7 +173,7 @@ enum {
 
 /* Errata definitions */
 #define I2C_OMAP_ERRATA_I207           (1 << 0)
-#define I2C_OMAP3_1P153                        (1 << 1)
+#define I2C_OMAP_ERRATA_I462           (1 << 1)
 
 struct omap_i2c_dev {
        struct device           *dev;
@@ -269,47 +269,6 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
                                (i2c_dev->regs[reg] << i2c_dev->reg_shift));
 }
 
-static void omap_i2c_unidle(struct omap_i2c_dev *dev)
-{
-       if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
-               omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
-               omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
-               omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
-               omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate);
-               omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate);
-               omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate);
-               omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
-               omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
-       }
-
-       /*
-        * Don't write to this register if the IE state is 0 as it can
-        * cause deadlock.
-        */
-       if (dev->iestate)
-               omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
-}
-
-static void omap_i2c_idle(struct omap_i2c_dev *dev)
-{
-       u16 iv;
-
-       dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
-       if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
-               omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1);
-       else
-               omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
-
-       if (dev->rev < OMAP_I2C_OMAP1_REV_2) {
-               iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
-       } else {
-               omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
-
-               /* Flush posted write */
-               omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
-       }
-}
-
 static int omap_i2c_init(struct omap_i2c_dev *dev)
 {
        u16 psc = 0, scll = 0, sclh = 0, buf = 0;
@@ -346,7 +305,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                        omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
                                           SYSC_AUTOIDLE_MASK);
 
-               } else if (dev->rev >= OMAP_I2C_REV_ON_3430) {
+               } else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) {
                        dev->syscstate = SYSC_AUTOIDLE_MASK;
                        dev->syscstate |= SYSC_ENAWAKEUP_MASK;
                        dev->syscstate |= (SYSC_IDLEMODE_SMART <<
@@ -468,11 +427,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
        /* Take the I2C module out of reset: */
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
 
-       dev->errata = 0;
-
-       if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
-               dev->errata |= I2C_OMAP_ERRATA_I207;
-
        /* Enable interrupts */
        dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
                        OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
@@ -514,7 +468,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
                             struct i2c_msg *msg, int stop)
 {
        struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
-       int r;
+       unsigned long timeout;
        u16 w;
 
        dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
@@ -536,7 +490,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
        w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
        omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
 
-       init_completion(&dev->cmd_complete);
+       INIT_COMPLETION(dev->cmd_complete);
        dev->cmd_err = 0;
 
        w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
@@ -584,12 +538,10 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
         * REVISIT: We should abort the transfer on signals, but the bus goes
         * into arbitration and we're currently unable to recover from it.
         */
-       r = wait_for_completion_timeout(&dev->cmd_complete,
-                                       OMAP_I2C_TIMEOUT);
+       timeout = wait_for_completion_timeout(&dev->cmd_complete,
+                                               OMAP_I2C_TIMEOUT);
        dev->buf_len = 0;
-       if (r < 0)
-               return r;
-       if (r == 0) {
+       if (timeout == 0) {
                dev_err(dev->dev, "controller timed out\n");
                omap_i2c_init(dev);
                return -ETIMEDOUT;
@@ -630,7 +582,9 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        int i;
        int r;
 
-       pm_runtime_get_sync(dev->dev);
+       r = pm_runtime_get_sync(dev->dev);
+       if (IS_ERR_VALUE(r))
+               return r;
 
        r = omap_i2c_wait_for_bb(dev);
        if (r < 0)
@@ -767,11 +721,11 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id)
 #endif
 
 /*
- * OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing
+ * OMAP3430 Errata i462: When an XRDY/XDR is hit, wait for XUDF before writing
  * data to DATA_REG. Otherwise some data bytes can be lost while transferring
  * them from the memory to the I2C interface.
  */
-static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
+static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err)
 {
        unsigned long timeout = 10000;
 
@@ -779,7 +733,6 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
                if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
                        omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY |
                                                        OMAP_I2C_STAT_XDR));
-                       *err |= OMAP_I2C_STAT_XUDF;
                        return -ETIMEDOUT;
                }
 
@@ -792,6 +745,7 @@ static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
                return 0;
        }
 
+       *err |= OMAP_I2C_STAT_XUDF;
        return 0;
 }
 
@@ -930,8 +884,8 @@ complete:
                                        break;
                                }
 
-                               if ((dev->errata & I2C_OMAP3_1P153) &&
-                                   errata_omap3_1p153(dev, &stat, &err))
+                               if ((dev->errata & I2C_OMAP_ERRATA_I462) &&
+                                   errata_omap3_i462(dev, &stat, &err))
                                        goto complete;
 
                                omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
@@ -1048,6 +1002,7 @@ omap_i2c_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, dev);
+       init_completion(&dev->cmd_complete);
 
        dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
 
@@ -1057,12 +1012,19 @@ omap_i2c_probe(struct platform_device *pdev)
                dev->regs = (u8 *)reg_map_ip_v1;
 
        pm_runtime_enable(dev->dev);
-       pm_runtime_get_sync(dev->dev);
+       r = pm_runtime_get_sync(dev->dev);
+       if (IS_ERR_VALUE(r))
+               goto err_free_mem;
 
        dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
 
-       if (dev->rev <= OMAP_I2C_REV_ON_3430)
-               dev->errata |= I2C_OMAP3_1P153;
+       dev->errata = 0;
+
+       if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
+               dev->errata |= I2C_OMAP_ERRATA_I207;
+
+       if (dev->rev <= OMAP_I2C_REV_ON_3430_3530)
+               dev->errata |= I2C_OMAP_ERRATA_I462;
 
        if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) {
                u16 s;
@@ -1079,7 +1041,7 @@ omap_i2c_probe(struct platform_device *pdev)
 
                dev->fifo_size = (dev->fifo_size / 2);
 
-               if (dev->rev >= OMAP_I2C_REV_ON_3530_4430)
+               if (dev->rev >= OMAP_I2C_REV_ON_3630_4430)
                        dev->b_hw = 0; /* Disable hardware fixes */
                else
                        dev->b_hw = 1; /* Enable hardware fixes */
@@ -1095,7 +1057,7 @@ omap_i2c_probe(struct platform_device *pdev)
 
        isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr :
                                                                   omap_i2c_isr;
-       r = request_irq(dev->irq, isr, 0, pdev->name, dev);
+       r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev);
 
        if (r) {
                dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
@@ -1105,8 +1067,6 @@ omap_i2c_probe(struct platform_device *pdev)
        dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id,
                 dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
 
-       pm_runtime_put(dev->dev);
-
        adap = &dev->adapter;
        i2c_set_adapdata(adap, dev);
        adap->owner = THIS_MODULE;
@@ -1126,6 +1086,8 @@ omap_i2c_probe(struct platform_device *pdev)
 
        of_i2c_register_devices(adap);
 
+       pm_runtime_put(dev->dev);
+
        return 0;
 
 err_free_irq:
@@ -1134,6 +1096,7 @@ err_unuse_clocks:
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
        pm_runtime_put(dev->dev);
        iounmap(dev->base);
+       pm_runtime_disable(&pdev->dev);
 err_free_mem:
        platform_set_drvdata(pdev, NULL);
        kfree(dev);
@@ -1143,17 +1106,23 @@ err_release_region:
        return r;
 }
 
-static int
-omap_i2c_remove(struct platform_device *pdev)
+static int __devexit omap_i2c_remove(struct platform_device *pdev)
 {
        struct omap_i2c_dev     *dev = platform_get_drvdata(pdev);
        struct resource         *mem;
+       int ret;
 
        platform_set_drvdata(pdev, NULL);
 
        free_irq(dev->irq, dev);
        i2c_del_adapter(&dev->adapter);
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (IS_ERR_VALUE(ret))
+               return ret;
+
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+       pm_runtime_put(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
        iounmap(dev->base);
        kfree(dev);
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1161,13 +1130,26 @@ omap_i2c_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
 #ifdef CONFIG_PM_RUNTIME
 static int omap_i2c_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
+       u16 iv;
+
+       _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG);
+
+       omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0);
 
-       omap_i2c_idle(_dev);
+       if (_dev->rev < OMAP_I2C_OMAP1_REV_2) {
+               iv = omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */
+       } else {
+               omap_i2c_write_reg(_dev, OMAP_I2C_STAT_REG, _dev->iestate);
+
+               /* Flush posted write */
+               omap_i2c_read_reg(_dev, OMAP_I2C_STAT_REG);
+       }
 
        return 0;
 }
@@ -1177,23 +1159,40 @@ static int omap_i2c_runtime_resume(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
 
-       omap_i2c_unidle(_dev);
+       if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
+               omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0);
+               omap_i2c_write_reg(_dev, OMAP_I2C_PSC_REG, _dev->pscstate);
+               omap_i2c_write_reg(_dev, OMAP_I2C_SCLL_REG, _dev->scllstate);
+               omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate);
+               omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate);
+               omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate);
+               omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate);
+               omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+       }
+
+       /*
+        * Don't write to this register if the IE state is 0 as it can
+        * cause deadlock.
+        */
+       if (_dev->iestate)
+               omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, _dev->iestate);
 
        return 0;
 }
+#endif /* CONFIG_PM_RUNTIME */
 
 static struct dev_pm_ops omap_i2c_pm_ops = {
-       .runtime_suspend = omap_i2c_runtime_suspend,
-       .runtime_resume = omap_i2c_runtime_resume,
+       SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend,
+                          omap_i2c_runtime_resume, NULL)
 };
 #define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
 #else
 #define OMAP_I2C_PM_OPS NULL
-#endif
+#endif /* CONFIG_PM */
 
 static struct platform_driver omap_i2c_driver = {
        .probe          = omap_i2c_probe,
-       .remove         = omap_i2c_remove,
+       .remove         = __devexit_p(omap_i2c_remove),
        .driver         = {
                .name   = "omap_i2c",
                .owner  = THIS_MODULE,
index 99389d2eae515deaf4a3fee7983bf0ba38ffdd7b..5d54416770b01e7816cc85cd7dcbf403bf407442 100644 (file)
@@ -587,25 +587,27 @@ static struct i2c_algorithm pnx_algorithm = {
 };
 
 #ifdef CONFIG_PM
-static int i2c_pnx_controller_suspend(struct platform_device *pdev,
-                                     pm_message_t state)
+static int i2c_pnx_controller_suspend(struct device *dev)
 {
-       struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+       struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev);
 
        clk_disable(alg_data->clk);
 
        return 0;
 }
 
-static int i2c_pnx_controller_resume(struct platform_device *pdev)
+static int i2c_pnx_controller_resume(struct device *dev)
 {
-       struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+       struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev);
 
        return clk_enable(alg_data->clk);
 }
+
+static SIMPLE_DEV_PM_OPS(i2c_pnx_pm,
+                        i2c_pnx_controller_suspend, i2c_pnx_controller_resume);
+#define PNX_I2C_PM     (&i2c_pnx_pm)
 #else
-#define i2c_pnx_controller_suspend     NULL
-#define i2c_pnx_controller_resume      NULL
+#define PNX_I2C_PM     NULL
 #endif
 
 static int __devinit i2c_pnx_probe(struct platform_device *pdev)
@@ -783,11 +785,10 @@ static struct platform_driver i2c_pnx_driver = {
                .name = "pnx-i2c",
                .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(i2c_pnx_of_match),
+               .pm = PNX_I2C_PM,
        },
        .probe = i2c_pnx_probe,
        .remove = __devexit_p(i2c_pnx_remove),
-       .suspend = i2c_pnx_controller_suspend,
-       .resume = i2c_pnx_controller_resume,
 };
 
 static int __init i2c_adap_pnx_init(void)
index 93709fbe30eb4c248527fa528bce2ae278807b8e..d8515be00b98a8b325620fca2069a06905a06969 100644 (file)
@@ -254,7 +254,7 @@ static int __devexit puv3_i2c_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state)
+static int puv3_i2c_suspend(struct device *dev)
 {
        int poll_count;
        /* Disable the IIC */
@@ -267,23 +267,20 @@ static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state)
        return 0;
 }
 
-static int puv3_i2c_resume(struct platform_device *dev)
-{
-       return 0 ;
-}
+static SIMPLE_DEV_PM_OPS(puv3_i2c_pm, puv3_i2c_suspend, NULL);
+#define PUV3_I2C_PM    (&puv3_i2c_pm)
+
 #else
-#define puv3_i2c_suspend NULL
-#define puv3_i2c_resume NULL
+#define PUV3_I2C_PM    NULL
 #endif
 
 static struct platform_driver puv3_i2c_driver = {
        .probe          = puv3_i2c_probe,
        .remove         = __devexit_p(puv3_i2c_remove),
-       .suspend        = puv3_i2c_suspend,
-       .resume         = puv3_i2c_resume,
        .driver         = {
                .name   = "PKUnity-v3-I2C",
                .owner  = THIS_MODULE,
+               .pm     = PUV3_I2C_PM,
        }
 };
 
index a997c7d3f95dec538c68dfc8948906b87395df2a..1034d93fb838d0b31774bb172af1e3cb6123bad1 100644 (file)
 
 #include <asm/irq.h>
 
-#ifndef CONFIG_HAVE_CLK
-#define clk_get(dev, id)       NULL
-#define clk_put(clk)           do { } while (0)
-#define clk_disable(clk)       do { } while (0)
-#define clk_enable(clk)                do { } while (0)
-#endif
-
 struct pxa_reg_layout {
        u32 ibmr;
        u32 idbr;
index 01959154572d88f0eb954327759fc66bcf9da5c8..5ae3b0236bd325443cb508d12ca6438d1190276b 100644 (file)
@@ -122,7 +122,7 @@ static inline unsigned int s3c24xx_get_device_quirks(struct platform_device *pde
 {
        if (pdev->dev.of_node) {
                const struct of_device_id *match;
-               match = of_match_node(&s3c24xx_i2c_match, pdev->dev.of_node);
+               match = of_match_node(s3c24xx_i2c_match, pdev->dev.of_node);
                return (unsigned int)match->data;
        }
 
@@ -609,7 +609,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
 
                if (ret != -EAGAIN) {
                        clk_disable(i2c->clk);
-                       pm_runtime_put_sync(&adap->dev);
+                       pm_runtime_put(&adap->dev);
                        return ret;
                }
 
@@ -619,7 +619,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
        }
 
        clk_disable(i2c->clk);
-       pm_runtime_put_sync(&adap->dev);
+       pm_runtime_put(&adap->dev);
        return -EREMOTEIO;
 }
 
index 4d44af181f377f2d886fee0d42afb13265a6d32b..580a0c04cb42d6b3b16716b57f5f352ecaa314c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2009 ST-Ericsson AB
+ * Copyright (C) 2007-2012 ST-Ericsson AB
  * License terms: GNU General Public License (GPL) version 2
  * ST DDC I2C master mode driver, used in e.g. U300 series platforms.
  * Author: Linus Walleij <linus.walleij@stericsson.com>
@@ -139,8 +139,6 @@ module_param(scl_frequency, uint,  0644);
  * struct stu300_dev - the stu300 driver state holder
  * @pdev: parent platform device
  * @adapter: corresponding I2C adapter
- * @phybase: location of I/O area in memory
- * @physize: size of I/O area in memory
  * @clk: hardware block clock
  * @irq: assigned interrupt line
  * @cmd_issue_lock: this locks the following cmd_ variables
@@ -155,8 +153,6 @@ module_param(scl_frequency, uint,  0644);
 struct stu300_dev {
        struct platform_device  *pdev;
        struct i2c_adapter      adapter;
-       resource_size_t         phybase;
-       resource_size_t         physize;
        void __iomem            *virtbase;
        struct clk              *clk;
        int                     irq;
@@ -873,64 +869,44 @@ stu300_probe(struct platform_device *pdev)
        int ret = 0;
        char clk_name[] = "I2C0";
 
-       dev = kzalloc(sizeof(struct stu300_dev), GFP_KERNEL);
+       dev = devm_kzalloc(&pdev->dev, sizeof(struct stu300_dev), GFP_KERNEL);
        if (!dev) {
                dev_err(&pdev->dev, "could not allocate device struct\n");
-               ret = -ENOMEM;
-               goto err_no_devmem;
+               return -ENOMEM;
        }
 
        bus_nr = pdev->id;
        clk_name[3] += (char)bus_nr;
-       dev->clk = clk_get(&pdev->dev, clk_name);
+       dev->clk = devm_clk_get(&pdev->dev, clk_name);
        if (IS_ERR(dev->clk)) {
-               ret = PTR_ERR(dev->clk);
                dev_err(&pdev->dev, "could not retrieve i2c bus clock\n");
-               goto err_no_clk;
+               return PTR_ERR(dev->clk);
        }
 
        dev->pdev = pdev;
-       platform_set_drvdata(pdev, dev);
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENOENT;
-               goto err_no_resource;
-       }
-
-       dev->phybase = res->start;
-       dev->physize = resource_size(res);
-
-       if (request_mem_region(dev->phybase, dev->physize,
-                              NAME " I/O Area") == NULL) {
-               ret = -EBUSY;
-               goto err_no_ioregion;
-       }
+       if (!res)
+               return -ENOENT;
 
-       dev->virtbase = ioremap(dev->phybase, dev->physize);
+       dev->virtbase = devm_request_and_ioremap(&pdev->dev, res);
        dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual "
                "base %p\n", bus_nr, dev->virtbase);
-       if (!dev->virtbase) {
-               ret = -ENOMEM;
-               goto err_no_ioremap;
-       }
+       if (!dev->virtbase)
+               return -ENOMEM;
 
        dev->irq = platform_get_irq(pdev, 0);
-       if (request_irq(dev->irq, stu300_irh, 0,
-                       NAME, dev)) {
-               ret = -EIO;
-               goto err_no_irq;
-       }
+       ret = devm_request_irq(&pdev->dev, dev->irq, stu300_irh, 0, NAME, dev);
+       if (ret < 0)
+               return ret;
 
        dev->speed = scl_frequency;
 
-       clk_enable(dev->clk);
+       clk_prepare_enable(dev->clk);
        ret = stu300_init_hw(dev);
        clk_disable(dev->clk);
-
        if (ret != 0) {
                dev_err(&dev->pdev->dev, "error initializing hardware.\n");
-               goto err_init_hw;
+               return -EIO;
        }
 
        /* IRQ event handling initialization */
@@ -952,57 +928,43 @@ stu300_probe(struct platform_device *pdev)
        /* i2c device drivers may be active on return from add_adapter() */
        ret = i2c_add_numbered_adapter(adap);
        if (ret) {
-               dev_err(&dev->pdev->dev, "failure adding ST Micro DDC "
+               dev_err(&pdev->dev, "failure adding ST Micro DDC "
                       "I2C adapter\n");
-               goto err_add_adapter;
+               return ret;
        }
-       return 0;
 
- err_add_adapter:
- err_init_hw:
-       free_irq(dev->irq, dev);
- err_no_irq:
-       iounmap(dev->virtbase);
- err_no_ioremap:
-       release_mem_region(dev->phybase, dev->physize);
- err_no_ioregion:
-       platform_set_drvdata(pdev, NULL);
- err_no_resource:
-       clk_put(dev->clk);
- err_no_clk:
-       kfree(dev);
- err_no_devmem:
-       dev_err(&pdev->dev, "failed to add " NAME " adapter: %d\n",
-               pdev->id);
-       return ret;
+       platform_set_drvdata(pdev, dev);
+       return 0;
 }
 
 #ifdef CONFIG_PM
-static int stu300_suspend(struct platform_device *pdev, pm_message_t state)
+static int stu300_suspend(struct device *device)
 {
-       struct stu300_dev *dev = platform_get_drvdata(pdev);
+       struct stu300_dev *dev = dev_get_drvdata(device);
 
        /* Turn off everything */
        stu300_wr8(0x00, dev->virtbase + I2C_CR);
        return 0;
 }
 
-static int stu300_resume(struct platform_device *pdev)
+static int stu300_resume(struct device *device)
 {
        int ret = 0;
-       struct stu300_dev *dev = platform_get_drvdata(pdev);
+       struct stu300_dev *dev = dev_get_drvdata(device);
 
        clk_enable(dev->clk);
        ret = stu300_init_hw(dev);
        clk_disable(dev->clk);
 
        if (ret != 0)
-               dev_err(&pdev->dev, "error re-initializing hardware.\n");
+               dev_err(device, "error re-initializing hardware.\n");
        return ret;
 }
+
+static SIMPLE_DEV_PM_OPS(stu300_pm, stu300_suspend, stu300_resume);
+#define STU300_I2C_PM  (&stu300_pm)
 #else
-#define stu300_suspend NULL
-#define stu300_resume NULL
+#define STU300_I2C_PM  NULL
 #endif
 
 static int __exit
@@ -1013,12 +975,7 @@ stu300_remove(struct platform_device *pdev)
        i2c_del_adapter(&dev->adapter);
        /* Turn off everything */
        stu300_wr8(0x00, dev->virtbase + I2C_CR);
-       free_irq(dev->irq, dev);
-       iounmap(dev->virtbase);
-       release_mem_region(dev->phybase, dev->physize);
-       clk_put(dev->clk);
        platform_set_drvdata(pdev, NULL);
-       kfree(dev);
        return 0;
 }
 
@@ -1026,10 +983,9 @@ static struct platform_driver stu300_i2c_driver = {
        .driver = {
                .name   = NAME,
                .owner  = THIS_MODULE,
+               .pm     = STU300_I2C_PM,
        },
        .remove         = __exit_p(stu300_remove),
-       .suspend        = stu300_suspend,
-       .resume         = stu300_resume,
 
 };
 
index 3da7ee3eb505e0816d809093958f0259816c3450..66eb53fac2022363c3cf90fa96d0ad6358234acc 100644 (file)
 #define I2C_HEADER_10BIT_ADDR                  (1<<18)
 #define I2C_HEADER_IE_ENABLE                   (1<<17)
 #define I2C_HEADER_REPEAT_START                        (1<<16)
+#define I2C_HEADER_CONTINUE_XFER               (1<<15)
 #define I2C_HEADER_MASTER_ADDR_SHIFT           12
 #define I2C_HEADER_SLAVE_ADDR_SHIFT            1
+/*
+ * msg_end_type: The bus control which need to be send at end of transfer.
+ * @MSG_END_STOP: Send stop pulse at end of transfer.
+ * @MSG_END_REPEAT_START: Send repeat start at end of transfer.
+ * @MSG_END_CONTINUE: The following on message is coming and so do not send
+ *             stop or repeat start.
+ */
+enum msg_end_type {
+       MSG_END_STOP,
+       MSG_END_REPEAT_START,
+       MSG_END_CONTINUE,
+};
 
 /**
  * struct tegra_i2c_dev        - per device i2c context
  * @adapter: core i2c layer adapter information
  * @clk: clock reference for i2c controller
  * @i2c_clk: clock reference for i2c bus
- * @iomem: memory resource for registers
  * @base: ioremapped registers cookie
  * @cont_id: i2c controller id, used for for packet header
  * @irq: irq number of transfer complete interrupt
@@ -124,7 +136,6 @@ struct tegra_i2c_dev {
        struct i2c_adapter adapter;
        struct clk *clk;
        struct clk *i2c_clk;
-       struct resource *iomem;
        void __iomem *base;
        int cont_id;
        int irq;
@@ -165,6 +176,10 @@ static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
        unsigned long reg)
 {
        writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+
+       /* Read back register to make sure that register writes completed */
+       if (reg != I2C_TX_FIFO)
+               readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
 }
 
 static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
@@ -449,7 +464,7 @@ err:
 }
 
 static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
-       struct i2c_msg *msg, int stop)
+       struct i2c_msg *msg, enum msg_end_type end_state)
 {
        u32 packet_header;
        u32 int_mask;
@@ -476,7 +491,9 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
        i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
 
        packet_header = I2C_HEADER_IE_ENABLE;
-       if (!stop)
+       if (end_state == MSG_END_CONTINUE)
+               packet_header |= I2C_HEADER_CONTINUE_XFER;
+       else if (end_state == MSG_END_REPEAT_START)
                packet_header |= I2C_HEADER_REPEAT_START;
        if (msg->flags & I2C_M_TEN) {
                packet_header |= msg->addr;
@@ -548,8 +565,14 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
 
        clk_prepare_enable(i2c_dev->clk);
        for (i = 0; i < num; i++) {
-               int stop = (i == (num - 1)) ? 1  : 0;
-               ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop);
+               enum msg_end_type end_type = MSG_END_STOP;
+               if (i < (num - 1)) {
+                       if (msgs[i + 1].flags & I2C_M_NOSTART)
+                               end_type = MSG_END_CONTINUE;
+                       else
+                               end_type = MSG_END_REPEAT_START;
+               }
+               ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], end_type);
                if (ret)
                        break;
        }
@@ -559,7 +582,8 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
 
 static u32 tegra_i2c_func(struct i2c_adapter *adap)
 {
-       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
+               I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART;
 }
 
 static const struct i2c_algorithm tegra_i2c_algo = {
@@ -572,7 +596,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
        struct tegra_i2c_dev *i2c_dev;
        struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data;
        struct resource *res;
-       struct resource *iomem;
        struct clk *clk;
        struct clk *i2c_clk;
        const unsigned int *prop;
@@ -585,50 +608,41 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "no mem resource\n");
                return -EINVAL;
        }
-       iomem = request_mem_region(res->start, resource_size(res), pdev->name);
-       if (!iomem) {
-               dev_err(&pdev->dev, "I2C region already claimed\n");
-               return -EBUSY;
-       }
 
-       base = ioremap(iomem->start, resource_size(iomem));
+       base = devm_request_and_ioremap(&pdev->dev, res);
        if (!base) {
-               dev_err(&pdev->dev, "Cannot ioremap I2C region\n");
-               return -ENOMEM;
+               dev_err(&pdev->dev, "Cannot request/ioremap I2C registers\n");
+               return -EADDRNOTAVAIL;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
                dev_err(&pdev->dev, "no irq resource\n");
-               ret = -EINVAL;
-               goto err_iounmap;
+               return -EINVAL;
        }
        irq = res->start;
 
-       clk = clk_get(&pdev->dev, NULL);
+       clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(clk)) {
                dev_err(&pdev->dev, "missing controller clock");
-               ret = PTR_ERR(clk);
-               goto err_release_region;
+               return PTR_ERR(clk);
        }
 
-       i2c_clk = clk_get(&pdev->dev, "i2c");
+       i2c_clk = devm_clk_get(&pdev->dev, "i2c");
        if (IS_ERR(i2c_clk)) {
                dev_err(&pdev->dev, "missing bus clock");
-               ret = PTR_ERR(i2c_clk);
-               goto err_clk_put;
+               return PTR_ERR(i2c_clk);
        }
 
-       i2c_dev = kzalloc(sizeof(struct tegra_i2c_dev), GFP_KERNEL);
+       i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
        if (!i2c_dev) {
-               ret = -ENOMEM;
-               goto err_i2c_clk_put;
+               dev_err(&pdev->dev, "Could not allocate struct tegra_i2c_dev");
+               return -ENOMEM;
        }
 
        i2c_dev->base = base;
        i2c_dev->clk = clk;
        i2c_dev->i2c_clk = i2c_clk;
-       i2c_dev->iomem = iomem;
        i2c_dev->adapter.algo = &tegra_i2c_algo;
        i2c_dev->irq = irq;
        i2c_dev->cont_id = pdev->id;
@@ -657,13 +671,14 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
        ret = tegra_i2c_init(i2c_dev);
        if (ret) {
                dev_err(&pdev->dev, "Failed to initialize i2c controller");
-               goto err_free;
+               return ret;
        }
 
-       ret = request_irq(i2c_dev->irq, tegra_i2c_isr, 0, pdev->name, i2c_dev);
+       ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
+                       tegra_i2c_isr, 0, pdev->name, i2c_dev);
        if (ret) {
                dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
-               goto err_free;
+               return ret;
        }
 
        clk_prepare_enable(i2c_dev->i2c_clk);
@@ -681,45 +696,26 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
        ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
        if (ret) {
                dev_err(&pdev->dev, "Failed to add I2C adapter\n");
-               goto err_free_irq;
+               clk_disable_unprepare(i2c_dev->i2c_clk);
+               return ret;
        }
 
        of_i2c_register_devices(&i2c_dev->adapter);
 
        return 0;
-err_free_irq:
-       free_irq(i2c_dev->irq, i2c_dev);
-err_free:
-       kfree(i2c_dev);
-err_i2c_clk_put:
-       clk_put(i2c_clk);
-err_clk_put:
-       clk_put(clk);
-err_release_region:
-       release_mem_region(iomem->start, resource_size(iomem));
-err_iounmap:
-       iounmap(base);
-       return ret;
 }
 
 static int __devexit tegra_i2c_remove(struct platform_device *pdev)
 {
        struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
        i2c_del_adapter(&i2c_dev->adapter);
-       free_irq(i2c_dev->irq, i2c_dev);
-       clk_put(i2c_dev->i2c_clk);
-       clk_put(i2c_dev->clk);
-       release_mem_region(i2c_dev->iomem->start,
-               resource_size(i2c_dev->iomem));
-       iounmap(i2c_dev->base);
-       kfree(i2c_dev);
        return 0;
 }
 
 #ifdef CONFIG_PM
-static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+static int tegra_i2c_suspend(struct device *dev)
 {
-       struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+       struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
 
        i2c_lock_adapter(&i2c_dev->adapter);
        i2c_dev->is_suspended = true;
@@ -728,9 +724,9 @@ static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int tegra_i2c_resume(struct platform_device *pdev)
+static int tegra_i2c_resume(struct device *dev)
 {
-       struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+       struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
        int ret;
 
        i2c_lock_adapter(&i2c_dev->adapter);
@@ -748,6 +744,11 @@ static int tegra_i2c_resume(struct platform_device *pdev)
 
        return 0;
 }
+
+static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume);
+#define TEGRA_I2C_PM   (&tegra_i2c_pm)
+#else
+#define TEGRA_I2C_PM   NULL
 #endif
 
 #if defined(CONFIG_OF)
@@ -758,21 +759,16 @@ static const struct of_device_id tegra_i2c_of_match[] __devinitconst = {
        {},
 };
 MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
-#else
-#define tegra_i2c_of_match NULL
 #endif
 
 static struct platform_driver tegra_i2c_driver = {
        .probe   = tegra_i2c_probe,
        .remove  = __devexit_p(tegra_i2c_remove),
-#ifdef CONFIG_PM
-       .suspend = tegra_i2c_suspend,
-       .resume  = tegra_i2c_resume,
-#endif
        .driver  = {
                .name  = "tegra-i2c",
                .owner = THIS_MODULE,
-               .of_match_table = tegra_i2c_of_match,
+               .of_match_table = of_match_ptr(tegra_i2c_of_match),
+               .pm    = TEGRA_I2C_PM,
        },
 };
 
index 26488aa893d5e5dc62ac2d01c332dd2d4ca9d2a1..2efa56c5ff2c32d10ff3018def5bc077b8492e4e 100644 (file)
@@ -1311,6 +1311,37 @@ module_exit(i2c_exit);
  * ----------------------------------------------------
  */
 
+/**
+ * __i2c_transfer - unlocked flavor of i2c_transfer
+ * @adap: Handle to I2C bus
+ * @msgs: One or more messages to execute before STOP is issued to
+ *     terminate the operation; each message begins with a START.
+ * @num: Number of messages to be executed.
+ *
+ * Returns negative errno, else the number of messages executed.
+ *
+ * Adapter lock must be held when calling this function. No debug logging
+ * takes place. adap->algo->master_xfer existence isn't checked.
+ */
+int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+       unsigned long orig_jiffies;
+       int ret, try;
+
+       /* Retry automatically on arbitration loss */
+       orig_jiffies = jiffies;
+       for (ret = 0, try = 0; try <= adap->retries; try++) {
+               ret = adap->algo->master_xfer(adap, msgs, num);
+               if (ret != -EAGAIN)
+                       break;
+               if (time_after(jiffies, orig_jiffies + adap->timeout))
+                       break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(__i2c_transfer);
+
 /**
  * i2c_transfer - execute a single or combined I2C message
  * @adap: Handle to I2C bus
@@ -1325,8 +1356,7 @@ module_exit(i2c_exit);
  */
 int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 {
-       unsigned long orig_jiffies;
-       int ret, try;
+       int ret;
 
        /* REVISIT the fault reporting model here is weak:
         *
@@ -1364,15 +1394,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                        i2c_lock_adapter(adap);
                }
 
-               /* Retry automatically on arbitration loss */
-               orig_jiffies = jiffies;
-               for (ret = 0, try = 0; try <= adap->retries; try++) {
-                       ret = adap->algo->master_xfer(adap, msgs, num);
-                       if (ret != -EAGAIN)
-                               break;
-                       if (time_after(jiffies, orig_jiffies + adap->timeout))
-                               break;
-               }
+               ret = __i2c_transfer(adap, msgs, num);
                i2c_unlock_adapter(adap);
 
                return ret;
diff --git a/drivers/input/misc/88pm80x_onkey.c b/drivers/input/misc/88pm80x_onkey.c
new file mode 100644 (file)
index 0000000..7f26e7b
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Marvell 88PM80x ONKEY driver
+ *
+ * Copyright (C) 2012 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.com>
+ * Qiao Zhou <zhouqiao@marvell.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/mfd/88pm80x.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define PM800_LONG_ONKEY_EN            (1 << 0)
+#define PM800_LONG_KEY_DELAY           (8)     /* 1 .. 16 seconds */
+#define PM800_LONKEY_PRESS_TIME                ((PM800_LONG_KEY_DELAY-1) << 4)
+#define PM800_LONKEY_PRESS_TIME_MASK   (0xF0)
+#define PM800_SW_PDOWN                 (1 << 5)
+
+struct pm80x_onkey_info {
+       struct input_dev *idev;
+       struct pm80x_chip *pm80x;
+       struct regmap *map;
+       int irq;
+};
+
+/* 88PM80x gives us an interrupt when ONKEY is held */
+static irqreturn_t pm80x_onkey_handler(int irq, void *data)
+{
+       struct pm80x_onkey_info *info = data;
+       int ret = 0;
+       unsigned int val;
+
+       ret = regmap_read(info->map, PM800_STATUS_1, &val);
+       if (ret < 0) {
+               dev_err(info->idev->dev.parent, "failed to read status: %d\n", ret);
+               return IRQ_NONE;
+       }
+       val &= PM800_ONKEY_STS1;
+
+       input_report_key(info->idev, KEY_POWER, val);
+       input_sync(info->idev);
+
+       return IRQ_HANDLED;
+}
+
+static SIMPLE_DEV_PM_OPS(pm80x_onkey_pm_ops, pm80x_dev_suspend,
+                        pm80x_dev_resume);
+
+static int __devinit pm80x_onkey_probe(struct platform_device *pdev)
+{
+
+       struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct pm80x_onkey_info *info;
+       int err;
+
+       info = kzalloc(sizeof(struct pm80x_onkey_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->pm80x = chip;
+
+       info->irq = platform_get_irq(pdev, 0);
+       if (info->irq < 0) {
+               dev_err(&pdev->dev, "No IRQ resource!\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       info->map = info->pm80x->regmap;
+       if (!info->map) {
+               dev_err(&pdev->dev, "no regmap!\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       info->idev = input_allocate_device();
+       if (!info->idev) {
+               dev_err(&pdev->dev, "Failed to allocate input dev\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       info->idev->name = "88pm80x_on";
+       info->idev->phys = "88pm80x_on/input0";
+       info->idev->id.bustype = BUS_I2C;
+       info->idev->dev.parent = &pdev->dev;
+       info->idev->evbit[0] = BIT_MASK(EV_KEY);
+       __set_bit(KEY_POWER, info->idev->keybit);
+
+       err = pm80x_request_irq(info->pm80x, info->irq, pm80x_onkey_handler,
+                                           IRQF_ONESHOT, "onkey", info);
+       if (err < 0) {
+               dev_err(&pdev->dev, "Failed to request IRQ: #%d: %d\n",
+                       info->irq, err);
+               goto out_reg;
+       }
+
+       err = input_register_device(info->idev);
+       if (err) {
+               dev_err(&pdev->dev, "Can't register input device: %d\n", err);
+               goto out_irq;
+       }
+
+       platform_set_drvdata(pdev, info);
+
+       /* Enable long onkey detection */
+       regmap_update_bits(info->map, PM800_RTC_MISC4, PM800_LONG_ONKEY_EN,
+                          PM800_LONG_ONKEY_EN);
+       /* Set 8-second interval */
+       regmap_update_bits(info->map, PM800_RTC_MISC3,
+                          PM800_LONKEY_PRESS_TIME_MASK,
+                          PM800_LONKEY_PRESS_TIME);
+
+       device_init_wakeup(&pdev->dev, 1);
+       return 0;
+
+out_irq:
+       pm80x_free_irq(info->pm80x, info->irq, info);
+out_reg:
+       input_free_device(info->idev);
+out:
+       kfree(info);
+       return err;
+}
+
+static int __devexit pm80x_onkey_remove(struct platform_device *pdev)
+{
+       struct pm80x_onkey_info *info = platform_get_drvdata(pdev);
+
+       device_init_wakeup(&pdev->dev, 0);
+       pm80x_free_irq(info->pm80x, info->irq, info);
+       input_unregister_device(info->idev);
+       kfree(info);
+       return 0;
+}
+
+static struct platform_driver pm80x_onkey_driver = {
+       .driver = {
+                  .name = "88pm80x-onkey",
+                  .owner = THIS_MODULE,
+                  .pm = &pm80x_onkey_pm_ops,
+                  },
+       .probe = pm80x_onkey_probe,
+       .remove = __devexit_p(pm80x_onkey_remove),
+};
+
+module_platform_driver(pm80x_onkey_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Marvell 88PM80x ONKEY driver");
+MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>");
+MODULE_ALIAS("platform:88pm80x-onkey");
index 7faf4a7fcaa9219d278b67b75a77a6c10081f678..7c0f1ecfdd7a3ff88fed02671e1cf0fba5847b24 100644 (file)
@@ -22,6 +22,16 @@ config INPUT_88PM860X_ONKEY
          To compile this driver as a module, choose M here: the module
          will be called 88pm860x_onkey.
 
+config INPUT_88PM80X_ONKEY
+       tristate "88PM80x ONKEY support"
+       depends on MFD_88PM800
+       help
+         Support the ONKEY of Marvell 88PM80x PMICs as an input device
+         reporting power button status.
+
+         To compile this driver as a module, choose M here: the module
+         will be called 88pm80x_onkey.
+
 config INPUT_AB8500_PONKEY
        tristate "AB8500 Pon (PowerOn) Key"
        depends on AB8500_CORE
index f55cdf4916fae2d717a3828099f130c71bbffd02..83fe6f5b77d120e9b3194325f0fc83879a474a0a 100644 (file)
@@ -5,6 +5,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_INPUT_88PM860X_ONKEY)     += 88pm860x_onkey.o
+obj-$(CONFIG_INPUT_88PM80X_ONKEY)      += 88pm80x_onkey.o
 obj-$(CONFIG_INPUT_AB8500_PONKEY)      += ab8500-ponkey.o
 obj-$(CONFIG_INPUT_AD714X)             += ad714x.o
 obj-$(CONFIG_INPUT_AD714X_I2C)         += ad714x-i2c.o
index 84ec691c05aa983751492a8dff29c5ca87b27ad2..f06231b7cab1ef762d7ad5db073b3a6b64d39987 100644 (file)
@@ -74,8 +74,8 @@ static int __devinit ab8500_ponkey_probe(struct platform_device *pdev)
 
        ponkey->idev = input;
        ponkey->ab8500 = ab8500;
-       ponkey->irq_dbf = irq_dbf;
-       ponkey->irq_dbr = irq_dbr;
+       ponkey->irq_dbf = ab8500_irq_get_virq(ab8500, irq_dbf);
+       ponkey->irq_dbr = ab8500_irq_get_virq(ab8500, irq_dbr);
 
        input->name = "AB8500 POn(PowerOn) Key";
        input->dev.parent = &pdev->dev;
index d5b390f75c9a97f38e147bb0a7a111cf7a9e15b3..14eaecea2b70660f7377c0a3196809e28c406d4a 100644 (file)
  * Note that newer firmware allows querying device for maximum useable
  * coordinates.
  */
+#define XMIN 0
+#define XMAX 6143
+#define YMIN 0
+#define YMAX 6143
 #define XMIN_NOMINAL 1472
 #define XMAX_NOMINAL 5472
 #define YMIN_NOMINAL 1408
 #define YMAX_NOMINAL 4448
 
+/* Size in bits of absolute position values reported by the hardware */
+#define ABS_POS_BITS 13
+
+/*
+ * Any position values from the hardware above the following limits are
+ * treated as "wrapped around negative" values that have been truncated to
+ * the 13-bit reporting range of the hardware. These are just reasonable
+ * guesses and can be adjusted if hardware is found that operates outside
+ * of these parameters.
+ */
+#define X_MAX_POSITIVE (((1 << ABS_POS_BITS) + XMAX) / 2)
+#define Y_MAX_POSITIVE (((1 << ABS_POS_BITS) + YMAX) / 2)
 
 /*****************************************************************************
  *     Stuff we need even when we do not want native Synaptics support
@@ -588,6 +604,12 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
                hw->right = (buf[0] & 0x02) ? 1 : 0;
        }
 
+       /* Convert wrap-around values to negative */
+       if (hw->x > X_MAX_POSITIVE)
+               hw->x -= 1 << ABS_POS_BITS;
+       if (hw->y > Y_MAX_POSITIVE)
+               hw->y -= 1 << ABS_POS_BITS;
+
        return 0;
 }
 
index 6533f44be5bd6636f22457f9ca32eaa7f404505c..002041975de9c902f193f2448865d051f0ce98dc 100644 (file)
@@ -464,7 +464,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
                t = (data[6] << 2) | ((data[7] >> 6) & 3);
                if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
                     (features->type >= INTUOS5S && features->type <= INTUOS5L) ||
-                   features->type == WACOM_21UX2 || features->type == WACOM_24HD) {
+                   (features->type >= WACOM_21UX2 && features->type <= WACOM_24HD)) {
                        t = (t << 1) | (data[1] & 1);
                }
                input_report_abs(input, ABS_PRESSURE, t);
@@ -614,7 +614,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                                input_report_abs(input, ABS_MISC, 0);
                        }
                } else {
-                       if (features->type == WACOM_21UX2) {
+                       if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
                                input_report_key(input, BTN_0, (data[5] & 0x01));
                                input_report_key(input, BTN_1, (data[6] & 0x01));
                                input_report_key(input, BTN_2, (data[6] & 0x02));
@@ -633,6 +633,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                                input_report_key(input, BTN_Z, (data[8] & 0x20));
                                input_report_key(input, BTN_BASE, (data[8] & 0x40));
                                input_report_key(input, BTN_BASE2, (data[8] & 0x80));
+
+                               if (features->type == WACOM_22HD) {
+                                       input_report_key(input, KEY_PROG1, data[9] & 0x01);
+                                       input_report_key(input, KEY_PROG2, data[9] & 0x02);
+                                       input_report_key(input, KEY_PROG3, data[9] & 0x04);
+                               }
                        } else {
                                input_report_key(input, BTN_0, (data[5] & 0x01));
                                input_report_key(input, BTN_1, (data[5] & 0x02));
@@ -1231,6 +1237,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
        case CINTIQ:
        case WACOM_BEE:
        case WACOM_21UX2:
+       case WACOM_22HD:
        case WACOM_24HD:
                sync = wacom_intuos_irq(wacom_wac);
                break;
@@ -1432,6 +1439,12 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
                wacom_setup_cintiq(wacom_wac);
                break;
 
+       case WACOM_22HD:
+               __set_bit(KEY_PROG1, input_dev->keybit);
+               __set_bit(KEY_PROG2, input_dev->keybit);
+               __set_bit(KEY_PROG3, input_dev->keybit);
+               /* fall through */
+
        case WACOM_21UX2:
                __set_bit(BTN_A, input_dev->keybit);
                __set_bit(BTN_B, input_dev->keybit);
@@ -1858,6 +1871,9 @@ static const struct wacom_features wacom_features_0xF0 =
 static const struct wacom_features wacom_features_0xCC =
        { "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    87200, 65600, 2047,
          63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0xFA =
+       { "Wacom Cintiq 22HD",    WACOM_PKGLEN_INTUOS,    95840, 54260, 2047,
+         63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0x90 =
        { "Wacom ISDv4 90",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
          0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2075,6 +2091,7 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xEF) },
        { USB_DEVICE_WACOM(0x47) },
        { USB_DEVICE_WACOM(0xF4) },
+       { USB_DEVICE_WACOM(0xFA) },
        { USB_DEVICE_LENOVO(0x6004) },
        { }
 };
index bd5d37b28714917e0a352ea94b54912151bd398b..96c185cc301eb95bf062440e59c49114458c0028 100644 (file)
@@ -73,8 +73,9 @@ enum {
        INTUOS5S,
        INTUOS5,
        INTUOS5L,
-       WACOM_24HD,
        WACOM_21UX2,
+       WACOM_22HD,
+       WACOM_24HD,
        CINTIQ,
        WACOM_BEE,
        WACOM_MO,
index 73bd2f6b82ec7fe2943fd5adcee4d5226979e5c0..1ba232cbc09d4e8744e1a827c3939ad7292e85a6 100644 (file)
@@ -472,6 +472,19 @@ config TOUCHSCREEN_PENMOUNT
          To compile this driver as a module, choose M here: the
          module will be called penmount.
 
+config TOUCHSCREEN_EDT_FT5X06
+       tristate "EDT FocalTech FT5x06 I2C Touchscreen support"
+       depends on I2C
+       help
+         Say Y here if you have an EDT "Polytouch" touchscreen based
+         on the FocalTech FT5x06 family of controllers connected to
+         your system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called edt-ft5x06.
+
 config TOUCHSCREEN_MIGOR
        tristate "Renesas MIGO-R touchscreen"
        depends on SH_MIGOR && I2C
index 5920c60f999d674184c67d3c4590f0989ed1c502..178eb128d90fe24fd6b851eea5c94abd685db322 100644 (file)
@@ -24,6 +24,7 @@ obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI)  += cyttsp_spi.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)       += da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DA9052)       += da9052_tsi.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)      += dynapro.o
+obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06)   += edt-ft5x06.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)    += hampshire.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)                += gunze.o
 obj-$(CONFIG_TOUCHSCREEN_EETI)         += eeti_ts.o
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
new file mode 100644 (file)
index 0000000..9afc777
--- /dev/null
@@ -0,0 +1,898 @@
+/*
+ * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * This is a driver for the EDT "Polytouch" family of touch controllers
+ * based on the FocalTech FT5x06 line of chips.
+ *
+ * Development of this driver has been sponsored by Glyn:
+ *    http://www.glyn.com/Products/Displays
+ */
+
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/input/mt.h>
+#include <linux/input/edt-ft5x06.h>
+
+#define MAX_SUPPORT_POINTS             5
+
+#define WORK_REGISTER_THRESHOLD                0x00
+#define WORK_REGISTER_REPORT_RATE      0x08
+#define WORK_REGISTER_GAIN             0x30
+#define WORK_REGISTER_OFFSET           0x31
+#define WORK_REGISTER_NUM_X            0x33
+#define WORK_REGISTER_NUM_Y            0x34
+
+#define WORK_REGISTER_OPMODE           0x3c
+#define FACTORY_REGISTER_OPMODE                0x01
+
+#define TOUCH_EVENT_DOWN               0x00
+#define TOUCH_EVENT_UP                 0x01
+#define TOUCH_EVENT_ON                 0x02
+#define TOUCH_EVENT_RESERVED           0x03
+
+#define EDT_NAME_LEN                   23
+#define EDT_SWITCH_MODE_RETRIES                10
+#define EDT_SWITCH_MODE_DELAY          5 /* msec */
+#define EDT_RAW_DATA_RETRIES           100
+#define EDT_RAW_DATA_DELAY             1 /* msec */
+
+struct edt_ft5x06_ts_data {
+       struct i2c_client *client;
+       struct input_dev *input;
+       u16 num_x;
+       u16 num_y;
+
+#if defined(CONFIG_DEBUG_FS)
+       struct dentry *debug_dir;
+       u8 *raw_buffer;
+       size_t raw_bufsize;
+#endif
+
+       struct mutex mutex;
+       bool factory_mode;
+       int threshold;
+       int gain;
+       int offset;
+       int report_rate;
+
+       char name[EDT_NAME_LEN];
+};
+
+static int edt_ft5x06_ts_readwrite(struct i2c_client *client,
+                                  u16 wr_len, u8 *wr_buf,
+                                  u16 rd_len, u8 *rd_buf)
+{
+       struct i2c_msg wrmsg[2];
+       int i = 0;
+       int ret;
+
+       if (wr_len) {
+               wrmsg[i].addr  = client->addr;
+               wrmsg[i].flags = 0;
+               wrmsg[i].len = wr_len;
+               wrmsg[i].buf = wr_buf;
+               i++;
+       }
+       if (rd_len) {
+               wrmsg[i].addr  = client->addr;
+               wrmsg[i].flags = I2C_M_RD;
+               wrmsg[i].len = rd_len;
+               wrmsg[i].buf = rd_buf;
+               i++;
+       }
+
+       ret = i2c_transfer(client->adapter, wrmsg, i);
+       if (ret < 0)
+               return ret;
+       if (ret != i)
+               return -EIO;
+
+       return 0;
+}
+
+static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata,
+                                   u8 *buf, int buflen)
+{
+       int i;
+       u8 crc = 0;
+
+       for (i = 0; i < buflen - 1; i++)
+               crc ^= buf[i];
+
+       if (crc != buf[buflen-1]) {
+               dev_err_ratelimited(&tsdata->client->dev,
+                                   "crc error: 0x%02x expected, got 0x%02x\n",
+                                   crc, buf[buflen-1]);
+               return false;
+       }
+
+       return true;
+}
+
+static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
+{
+       struct edt_ft5x06_ts_data *tsdata = dev_id;
+       struct device *dev = &tsdata->client->dev;
+       u8 cmd = 0xf9;
+       u8 rdbuf[26];
+       int i, type, x, y, id;
+       int error;
+
+       memset(rdbuf, 0, sizeof(rdbuf));
+
+       error = edt_ft5x06_ts_readwrite(tsdata->client,
+                                       sizeof(cmd), &cmd,
+                                       sizeof(rdbuf), rdbuf);
+       if (error) {
+               dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",
+                                   error);
+               goto out;
+       }
+
+       if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || rdbuf[2] != 26) {
+               dev_err_ratelimited(dev, "Unexpected header: %02x%02x%02x!\n",
+                                   rdbuf[0], rdbuf[1], rdbuf[2]);
+               goto out;
+       }
+
+       if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, 26))
+               goto out;
+
+       for (i = 0; i < MAX_SUPPORT_POINTS; i++) {
+               u8 *buf = &rdbuf[i * 4 + 5];
+               bool down;
+
+               type = buf[0] >> 6;
+               /* ignore Reserved events */
+               if (type == TOUCH_EVENT_RESERVED)
+                       continue;
+
+               x = ((buf[0] << 8) | buf[1]) & 0x0fff;
+               y = ((buf[2] << 8) | buf[3]) & 0x0fff;
+               id = (buf[2] >> 4) & 0x0f;
+               down = (type != TOUCH_EVENT_UP);
+
+               input_mt_slot(tsdata->input, id);
+               input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down);
+
+               if (!down)
+                       continue;
+
+               input_report_abs(tsdata->input, ABS_MT_POSITION_X, x);
+               input_report_abs(tsdata->input, ABS_MT_POSITION_Y, y);
+       }
+
+       input_mt_report_pointer_emulation(tsdata->input, true);
+       input_sync(tsdata->input);
+
+out:
+       return IRQ_HANDLED;
+}
+
+static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
+                                    u8 addr, u8 value)
+{
+       u8 wrbuf[4];
+
+       wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
+       wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
+       wrbuf[2] = value;
+       wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
+
+       return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL);
+}
+
+static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
+                                   u8 addr)
+{
+       u8 wrbuf[2], rdbuf[2];
+       int error;
+
+       wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
+       wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
+       wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
+
+       error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, rdbuf);
+       if (error)
+               return error;
+
+       if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) {
+               dev_err(&tsdata->client->dev,
+                       "crc error: 0x%02x expected, got 0x%02x\n",
+                       wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], rdbuf[1]);
+               return -EIO;
+       }
+
+       return rdbuf[0];
+}
+
+struct edt_ft5x06_attribute {
+       struct device_attribute dattr;
+       size_t field_offset;
+       u8 limit_low;
+       u8 limit_high;
+       u8 addr;
+};
+
+#define EDT_ATTR(_field, _mode, _addr, _limit_low, _limit_high)                \
+       struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = {        \
+               .dattr = __ATTR(_field, _mode,                          \
+                               edt_ft5x06_setting_show,                \
+                               edt_ft5x06_setting_store),              \
+               .field_offset =                                         \
+                       offsetof(struct edt_ft5x06_ts_data, _field),    \
+               .limit_low = _limit_low,                                \
+               .limit_high = _limit_high,                              \
+               .addr = _addr,                                          \
+       }
+
+static ssize_t edt_ft5x06_setting_show(struct device *dev,
+                                      struct device_attribute *dattr,
+                                      char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
+       struct edt_ft5x06_attribute *attr =
+                       container_of(dattr, struct edt_ft5x06_attribute, dattr);
+       u8 *field = (u8 *)((char *)tsdata + attr->field_offset);
+       int val;
+       size_t count = 0;
+       int error = 0;
+
+       mutex_lock(&tsdata->mutex);
+
+       if (tsdata->factory_mode) {
+               error = -EIO;
+               goto out;
+       }
+
+       val = edt_ft5x06_register_read(tsdata, attr->addr);
+       if (val < 0) {
+               error = val;
+               dev_err(&tsdata->client->dev,
+                       "Failed to fetch attribute %s, error %d\n",
+                       dattr->attr.name, error);
+               goto out;
+       }
+
+       if (val != *field) {
+               dev_warn(&tsdata->client->dev,
+                        "%s: read (%d) and stored value (%d) differ\n",
+                        dattr->attr.name, val, *field);
+               *field = val;
+       }
+
+       count = scnprintf(buf, PAGE_SIZE, "%d\n", val);
+out:
+       mutex_unlock(&tsdata->mutex);
+       return error ?: count;
+}
+
+static ssize_t edt_ft5x06_setting_store(struct device *dev,
+                                       struct device_attribute *dattr,
+                                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
+       struct edt_ft5x06_attribute *attr =
+                       container_of(dattr, struct edt_ft5x06_attribute, dattr);
+       u8 *field = (u8 *)((char *)tsdata + attr->field_offset);
+       unsigned int val;
+       int error;
+
+       mutex_lock(&tsdata->mutex);
+
+       if (tsdata->factory_mode) {
+               error = -EIO;
+               goto out;
+       }
+
+       error = kstrtouint(buf, 0, &val);
+       if (error)
+               goto out;
+
+       if (val < attr->limit_low || val > attr->limit_high) {
+               error = -ERANGE;
+               goto out;
+       }
+
+       error = edt_ft5x06_register_write(tsdata, attr->addr, val);
+       if (error) {
+               dev_err(&tsdata->client->dev,
+                       "Failed to update attribute %s, error: %d\n",
+                       dattr->attr.name, error);
+               goto out;
+       }
+
+       *field = val;
+
+out:
+       mutex_unlock(&tsdata->mutex);
+       return error ?: count;
+}
+
+static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, 0, 31);
+static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, 0, 31);
+static EDT_ATTR(threshold, S_IWUSR | S_IRUGO,
+               WORK_REGISTER_THRESHOLD, 20, 80);
+static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO,
+               WORK_REGISTER_REPORT_RATE, 3, 14);
+
+static struct attribute *edt_ft5x06_attrs[] = {
+       &edt_ft5x06_attr_gain.dattr.attr,
+       &edt_ft5x06_attr_offset.dattr.attr,
+       &edt_ft5x06_attr_threshold.dattr.attr,
+       &edt_ft5x06_attr_report_rate.dattr.attr,
+       NULL
+};
+
+static const struct attribute_group edt_ft5x06_attr_group = {
+       .attrs = edt_ft5x06_attrs,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
+{
+       struct i2c_client *client = tsdata->client;
+       int retries = EDT_SWITCH_MODE_RETRIES;
+       int ret;
+       int error;
+
+       disable_irq(client->irq);
+
+       if (!tsdata->raw_buffer) {
+               tsdata->raw_bufsize = tsdata->num_x * tsdata->num_y *
+                                     sizeof(u16);
+               tsdata->raw_buffer = kzalloc(tsdata->raw_bufsize, GFP_KERNEL);
+               if (!tsdata->raw_buffer) {
+                       error = -ENOMEM;
+                       goto err_out;
+               }
+       }
+
+       /* mode register is 0x3c when in the work mode */
+       error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
+       if (error) {
+               dev_err(&client->dev,
+                       "failed to switch to factory mode, error %d\n", error);
+               goto err_out;
+       }
+
+       tsdata->factory_mode = true;
+       do {
+               mdelay(EDT_SWITCH_MODE_DELAY);
+               /* mode register is 0x01 when in factory mode */
+               ret = edt_ft5x06_register_read(tsdata, FACTORY_REGISTER_OPMODE);
+               if (ret == 0x03)
+                       break;
+       } while (--retries > 0);
+
+       if (retries == 0) {
+               dev_err(&client->dev, "not in factory mode after %dms.\n",
+                       EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY);
+               error = -EIO;
+               goto err_out;
+       }
+
+       return 0;
+
+err_out:
+       kfree(tsdata->raw_buffer);
+       tsdata->raw_buffer = NULL;
+       tsdata->factory_mode = false;
+       enable_irq(client->irq);
+
+       return error;
+}
+
+static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
+{
+       struct i2c_client *client = tsdata->client;
+       int retries = EDT_SWITCH_MODE_RETRIES;
+       int ret;
+       int error;
+
+       /* mode register is 0x01 when in the factory mode */
+       error = edt_ft5x06_register_write(tsdata, FACTORY_REGISTER_OPMODE, 0x1);
+       if (error) {
+               dev_err(&client->dev,
+                       "failed to switch to work mode, error: %d\n", error);
+               return error;
+       }
+
+       tsdata->factory_mode = false;
+
+       do {
+               mdelay(EDT_SWITCH_MODE_DELAY);
+               /* mode register is 0x01 when in factory mode */
+               ret = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OPMODE);
+               if (ret == 0x01)
+                       break;
+       } while (--retries > 0);
+
+       if (retries == 0) {
+               dev_err(&client->dev, "not in work mode after %dms.\n",
+                       EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY);
+               tsdata->factory_mode = true;
+               return -EIO;
+       }
+
+       if (tsdata->raw_buffer)
+               kfree(tsdata->raw_buffer);
+       tsdata->raw_buffer = NULL;
+
+       /* restore parameters */
+       edt_ft5x06_register_write(tsdata, WORK_REGISTER_THRESHOLD,
+                                 tsdata->threshold);
+       edt_ft5x06_register_write(tsdata, WORK_REGISTER_GAIN,
+                                 tsdata->gain);
+       edt_ft5x06_register_write(tsdata, WORK_REGISTER_OFFSET,
+                                 tsdata->offset);
+       edt_ft5x06_register_write(tsdata, WORK_REGISTER_REPORT_RATE,
+                                 tsdata->report_rate);
+
+       enable_irq(client->irq);
+
+       return 0;
+}
+
+static int edt_ft5x06_debugfs_mode_get(void *data, u64 *mode)
+{
+       struct edt_ft5x06_ts_data *tsdata = data;
+
+       *mode = tsdata->factory_mode;
+
+       return 0;
+};
+
+static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode)
+{
+       struct edt_ft5x06_ts_data *tsdata = data;
+       int retval = 0;
+
+       if (mode > 1)
+               return -ERANGE;
+
+       mutex_lock(&tsdata->mutex);
+
+       if (mode != tsdata->factory_mode) {
+               retval = mode ? edt_ft5x06_factory_mode(tsdata) :
+                               edt_ft5x06_work_mode(tsdata);
+       }
+
+       mutex_unlock(&tsdata->mutex);
+
+       return retval;
+};
+
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get,
+                       edt_ft5x06_debugfs_mode_set, "%llu\n");
+
+static int edt_ft5x06_debugfs_raw_data_open(struct inode *inode,
+                                           struct file *file)
+{
+       file->private_data = inode->i_private;
+
+       return 0;
+}
+
+static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file,
+                               char __user *buf, size_t count, loff_t *off)
+{
+       struct edt_ft5x06_ts_data *tsdata = file->private_data;
+       struct i2c_client *client = tsdata->client;
+       int retries  = EDT_RAW_DATA_RETRIES;
+       int val, i, error;
+       size_t read = 0;
+       int colbytes;
+       char wrbuf[3];
+       u8 *rdbuf;
+
+       if (*off < 0 || *off >= tsdata->raw_bufsize)
+               return 0;
+
+       mutex_lock(&tsdata->mutex);
+
+       if (!tsdata->factory_mode || !tsdata->raw_buffer) {
+               error = -EIO;
+               goto out;
+       }
+
+       error = edt_ft5x06_register_write(tsdata, 0x08, 0x01);
+       if (error) {
+               dev_dbg(&client->dev,
+                       "failed to write 0x08 register, error %d\n", error);
+               goto out;
+       }
+
+       do {
+               msleep(EDT_RAW_DATA_DELAY);
+               val = edt_ft5x06_register_read(tsdata, 0x08);
+               if (val < 1)
+                       break;
+       } while (--retries > 0);
+
+       if (val < 0) {
+               error = val;
+               dev_dbg(&client->dev,
+                       "failed to read 0x08 register, error %d\n", error);
+               goto out;
+       }
+
+       if (retries == 0) {
+               dev_dbg(&client->dev,
+                       "timed out waiting for register to settle\n");
+               error = -ETIMEDOUT;
+               goto out;
+       }
+
+       rdbuf = tsdata->raw_buffer;
+       colbytes = tsdata->num_y * sizeof(u16);
+
+       wrbuf[0] = 0xf5;
+       wrbuf[1] = 0x0e;
+       for (i = 0; i < tsdata->num_x; i++) {
+               wrbuf[2] = i;  /* column index */
+               error = edt_ft5x06_ts_readwrite(tsdata->client,
+                                               sizeof(wrbuf), wrbuf,
+                                               colbytes, rdbuf);
+               if (error)
+                       goto out;
+
+               rdbuf += colbytes;
+       }
+
+       read = min_t(size_t, count, tsdata->raw_bufsize - *off);
+       error = copy_to_user(buf, tsdata->raw_buffer + *off, read);
+       if (!error)
+               *off += read;
+out:
+       mutex_unlock(&tsdata->mutex);
+       return error ?: read;
+};
+
+
+static const struct file_operations debugfs_raw_data_fops = {
+       .open = edt_ft5x06_debugfs_raw_data_open,
+       .read = edt_ft5x06_debugfs_raw_data_read,
+};
+
+static void __devinit
+edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
+                             const char *debugfs_name)
+{
+       tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL);
+       if (!tsdata->debug_dir)
+               return;
+
+       debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x);
+       debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y);
+
+       debugfs_create_file("mode", S_IRUSR | S_IWUSR,
+                           tsdata->debug_dir, tsdata, &debugfs_mode_fops);
+       debugfs_create_file("raw_data", S_IRUSR,
+                           tsdata->debug_dir, tsdata, &debugfs_raw_data_fops);
+}
+
+static void __devexit
+edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
+{
+       if (tsdata->debug_dir)
+               debugfs_remove_recursive(tsdata->debug_dir);
+}
+
+#else
+
+static inline void
+edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
+                             const char *debugfs_name)
+{
+}
+
+static inline void
+edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
+{
+}
+
+#endif /* CONFIG_DEBUGFS */
+
+
+
+static int __devinit edt_ft5x06_ts_reset(struct i2c_client *client,
+                                        int reset_pin)
+{
+       int error;
+
+       if (gpio_is_valid(reset_pin)) {
+               /* this pulls reset down, enabling the low active reset */
+               error = gpio_request_one(reset_pin, GPIOF_OUT_INIT_LOW,
+                                        "edt-ft5x06 reset");
+               if (error) {
+                       dev_err(&client->dev,
+                               "Failed to request GPIO %d as reset pin, error %d\n",
+                               reset_pin, error);
+                       return error;
+               }
+
+               mdelay(50);
+               gpio_set_value(reset_pin, 1);
+               mdelay(100);
+       }
+
+       return 0;
+}
+
+static int __devinit edt_ft5x06_ts_identify(struct i2c_client *client,
+                                           char *model_name,
+                                           char *fw_version)
+{
+       u8 rdbuf[EDT_NAME_LEN];
+       char *p;
+       int error;
+
+       error = edt_ft5x06_ts_readwrite(client, 1, "\xbb",
+                                       EDT_NAME_LEN - 1, rdbuf);
+       if (error)
+               return error;
+
+       /* remove last '$' end marker */
+       rdbuf[EDT_NAME_LEN - 1] = '\0';
+       if (rdbuf[EDT_NAME_LEN - 2] == '$')
+               rdbuf[EDT_NAME_LEN - 2] = '\0';
+
+       /* look for Model/Version separator */
+       p = strchr(rdbuf, '*');
+       if (p)
+               *p++ = '\0';
+
+       strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
+       strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
+
+       return 0;
+}
+
+#define EDT_ATTR_CHECKSET(name, reg) \
+       if (pdata->name >= edt_ft5x06_attr_##name.limit_low &&          \
+           pdata->name <= edt_ft5x06_attr_##name.limit_high)           \
+               edt_ft5x06_register_write(tsdata, reg, pdata->name)
+
+static void __devinit
+edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
+                          const struct edt_ft5x06_platform_data *pdata)
+{
+       if (!pdata->use_parameters)
+               return;
+
+       /* pick up defaults from the platform data */
+       EDT_ATTR_CHECKSET(threshold, WORK_REGISTER_THRESHOLD);
+       EDT_ATTR_CHECKSET(gain, WORK_REGISTER_GAIN);
+       EDT_ATTR_CHECKSET(offset, WORK_REGISTER_OFFSET);
+       EDT_ATTR_CHECKSET(report_rate, WORK_REGISTER_REPORT_RATE);
+}
+
+static void __devinit
+edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
+{
+       tsdata->threshold = edt_ft5x06_register_read(tsdata,
+                                                    WORK_REGISTER_THRESHOLD);
+       tsdata->gain = edt_ft5x06_register_read(tsdata, WORK_REGISTER_GAIN);
+       tsdata->offset = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OFFSET);
+       tsdata->report_rate = edt_ft5x06_register_read(tsdata,
+                                               WORK_REGISTER_REPORT_RATE);
+       tsdata->num_x = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_X);
+       tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y);
+}
+
+static int __devinit edt_ft5x06_ts_probe(struct i2c_client *client,
+                                        const struct i2c_device_id *id)
+{
+       const struct edt_ft5x06_platform_data *pdata =
+                                               client->dev.platform_data;
+       struct edt_ft5x06_ts_data *tsdata;
+       struct input_dev *input;
+       int error;
+       char fw_version[EDT_NAME_LEN];
+
+       dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
+
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data?\n");
+               return -EINVAL;
+       }
+
+       error = edt_ft5x06_ts_reset(client, pdata->reset_pin);
+       if (error)
+               return error;
+
+       if (gpio_is_valid(pdata->irq_pin)) {
+               error = gpio_request_one(pdata->irq_pin,
+                                        GPIOF_IN, "edt-ft5x06 irq");
+               if (error) {
+                       dev_err(&client->dev,
+                               "Failed to request GPIO %d, error %d\n",
+                               pdata->irq_pin, error);
+                       return error;
+               }
+       }
+
+       tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!tsdata || !input) {
+               dev_err(&client->dev, "failed to allocate driver data.\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       mutex_init(&tsdata->mutex);
+       tsdata->client = client;
+       tsdata->input = input;
+       tsdata->factory_mode = false;
+
+       error = edt_ft5x06_ts_identify(client, tsdata->name, fw_version);
+       if (error) {
+               dev_err(&client->dev, "touchscreen probe failed\n");
+               goto err_free_mem;
+       }
+
+       edt_ft5x06_ts_get_defaults(tsdata, pdata);
+       edt_ft5x06_ts_get_parameters(tsdata);
+
+       dev_dbg(&client->dev,
+               "Model \"%s\", Rev. \"%s\", %dx%d sensors\n",
+               tsdata->name, fw_version, tsdata->num_x, tsdata->num_y);
+
+       input->name = tsdata->name;
+       input->id.bustype = BUS_I2C;
+       input->dev.parent = &client->dev;
+
+       __set_bit(EV_SYN, input->evbit);
+       __set_bit(EV_KEY, input->evbit);
+       __set_bit(EV_ABS, input->evbit);
+       __set_bit(BTN_TOUCH, input->keybit);
+       input_set_abs_params(input, ABS_X, 0, tsdata->num_x * 64 - 1, 0, 0);
+       input_set_abs_params(input, ABS_Y, 0, tsdata->num_y * 64 - 1, 0, 0);
+       input_set_abs_params(input, ABS_MT_POSITION_X,
+                            0, tsdata->num_x * 64 - 1, 0, 0);
+       input_set_abs_params(input, ABS_MT_POSITION_Y,
+                            0, tsdata->num_y * 64 - 1, 0, 0);
+       error = input_mt_init_slots(input, MAX_SUPPORT_POINTS);
+       if (error) {
+               dev_err(&client->dev, "Unable to init MT slots.\n");
+               goto err_free_mem;
+       }
+
+       input_set_drvdata(input, tsdata);
+       i2c_set_clientdata(client, tsdata);
+
+       error = request_threaded_irq(client->irq, NULL, edt_ft5x06_ts_isr,
+                                    IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                    client->name, tsdata);
+       if (error) {
+               dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+               goto err_free_mem;
+       }
+
+       error = sysfs_create_group(&client->dev.kobj, &edt_ft5x06_attr_group);
+       if (error)
+               goto err_free_irq;
+
+       error = input_register_device(input);
+       if (error)
+               goto err_remove_attrs;
+
+       edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
+       device_init_wakeup(&client->dev, 1);
+
+       dev_dbg(&client->dev,
+               "EDT FT5x06 initialized: IRQ pin %d, Reset pin %d.\n",
+               pdata->irq_pin, pdata->reset_pin);
+
+       return 0;
+
+err_remove_attrs:
+       sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
+err_free_irq:
+       free_irq(client->irq, tsdata);
+err_free_mem:
+       input_free_device(input);
+       kfree(tsdata);
+
+       if (gpio_is_valid(pdata->irq_pin))
+               gpio_free(pdata->irq_pin);
+
+       return error;
+}
+
+static int __devexit edt_ft5x06_ts_remove(struct i2c_client *client)
+{
+       const struct edt_ft5x06_platform_data *pdata =
+                                               dev_get_platdata(&client->dev);
+       struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
+
+       edt_ft5x06_ts_teardown_debugfs(tsdata);
+       sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
+
+       free_irq(client->irq, tsdata);
+       input_unregister_device(tsdata->input);
+
+       if (gpio_is_valid(pdata->irq_pin))
+               gpio_free(pdata->irq_pin);
+       if (gpio_is_valid(pdata->reset_pin))
+               gpio_free(pdata->reset_pin);
+
+       kfree(tsdata->raw_buffer);
+       kfree(tsdata);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int edt_ft5x06_ts_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(client->irq);
+
+       return 0;
+}
+
+static int edt_ft5x06_ts_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(client->irq);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
+                        edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
+
+static const struct i2c_device_id edt_ft5x06_ts_id[] = {
+       { "edt-ft5x06", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
+
+static struct i2c_driver edt_ft5x06_ts_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "edt_ft5x06",
+               .pm = &edt_ft5x06_ts_pm_ops,
+       },
+       .id_table = edt_ft5x06_ts_id,
+       .probe    = edt_ft5x06_ts_probe,
+       .remove   = __devexit_p(edt_ft5x06_ts_remove),
+};
+
+module_i2c_driver(edt_ft5x06_ts_driver);
+
+MODULE_AUTHOR("Simon Budig <simon.budig@kernelconcepts.de>");
+MODULE_DESCRIPTION("EDT FT5x06 I2C Touchscreen Driver");
+MODULE_LICENSE("GPL");
index 10f122a3a8566acc5a1046b4a9b35ef04ad45fab..1eee45b69b71617f9108a88b10085a56bef42c3c 100644 (file)
@@ -260,15 +260,6 @@ config DM_DEBUG_BLOCK_STACK_TRACING
 
          If unsure, say N.
 
-config DM_DEBUG_SPACE_MAPS
-       boolean "Extra validation for thin provisioning space maps"
-       depends on DM_THIN_PROVISIONING
-       ---help---
-         Enable this for messages that may help debug problems with the
-         space maps used by thin provisioning.
-
-          If unsure, say N.
-
 config DM_MIRROR
        tristate "Mirror target"
        depends on BLK_DEV_DM
index 3f06df59fd824022fd80a9c77551178660909eb6..664743d6a6cdb7961ea7555544185ea4cff06357 100644 (file)
@@ -42,21 +42,21 @@ struct convert_context {
        unsigned int offset_out;
        unsigned int idx_in;
        unsigned int idx_out;
-       sector_t sector;
-       atomic_t pending;
+       sector_t cc_sector;
+       atomic_t cc_pending;
 };
 
 /*
  * per bio private data
  */
 struct dm_crypt_io {
-       struct dm_target *target;
+       struct crypt_config *cc;
        struct bio *base_bio;
        struct work_struct work;
 
        struct convert_context ctx;
 
-       atomic_t pending;
+       atomic_t io_pending;
        int error;
        sector_t sector;
        struct dm_crypt_io *base_io;
@@ -109,9 +109,6 @@ enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID };
  */
 struct crypt_cpu {
        struct ablkcipher_request *req;
-       /* ESSIV: struct crypto_cipher *essiv_tfm */
-       void *iv_private;
-       struct crypto_ablkcipher *tfms[0];
 };
 
 /*
@@ -151,6 +148,10 @@ struct crypt_config {
         * per_cpu_ptr() only.
         */
        struct crypt_cpu __percpu *cpu;
+
+       /* ESSIV: struct crypto_cipher *essiv_tfm */
+       void *iv_private;
+       struct crypto_ablkcipher **tfms;
        unsigned tfms_count;
 
        /*
@@ -193,7 +194,7 @@ static struct crypt_cpu *this_crypt_config(struct crypt_config *cc)
  */
 static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc)
 {
-       return __this_cpu_ptr(cc->cpu)->tfms[0];
+       return cc->tfms[0];
 }
 
 /*
@@ -258,7 +259,7 @@ static int crypt_iv_essiv_init(struct crypt_config *cc)
        struct hash_desc desc;
        struct scatterlist sg;
        struct crypto_cipher *essiv_tfm;
-       int err, cpu;
+       int err;
 
        sg_init_one(&sg, cc->key, cc->key_size);
        desc.tfm = essiv->hash_tfm;
@@ -268,14 +269,12 @@ static int crypt_iv_essiv_init(struct crypt_config *cc)
        if (err)
                return err;
 
-       for_each_possible_cpu(cpu) {
-               essiv_tfm = per_cpu_ptr(cc->cpu, cpu)->iv_private,
+       essiv_tfm = cc->iv_private;
 
-               err = crypto_cipher_setkey(essiv_tfm, essiv->salt,
-                                   crypto_hash_digestsize(essiv->hash_tfm));
-               if (err)
-                       return err;
-       }
+       err = crypto_cipher_setkey(essiv_tfm, essiv->salt,
+                           crypto_hash_digestsize(essiv->hash_tfm));
+       if (err)
+               return err;
 
        return 0;
 }
@@ -286,16 +285,14 @@ static int crypt_iv_essiv_wipe(struct crypt_config *cc)
        struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
        unsigned salt_size = crypto_hash_digestsize(essiv->hash_tfm);
        struct crypto_cipher *essiv_tfm;
-       int cpu, r, err = 0;
+       int r, err = 0;
 
        memset(essiv->salt, 0, salt_size);
 
-       for_each_possible_cpu(cpu) {
-               essiv_tfm = per_cpu_ptr(cc->cpu, cpu)->iv_private;
-               r = crypto_cipher_setkey(essiv_tfm, essiv->salt, salt_size);
-               if (r)
-                       err = r;
-       }
+       essiv_tfm = cc->iv_private;
+       r = crypto_cipher_setkey(essiv_tfm, essiv->salt, salt_size);
+       if (r)
+               err = r;
 
        return err;
 }
@@ -335,8 +332,6 @@ static struct crypto_cipher *setup_essiv_cpu(struct crypt_config *cc,
 
 static void crypt_iv_essiv_dtr(struct crypt_config *cc)
 {
-       int cpu;
-       struct crypt_cpu *cpu_cc;
        struct crypto_cipher *essiv_tfm;
        struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
 
@@ -346,15 +341,12 @@ static void crypt_iv_essiv_dtr(struct crypt_config *cc)
        kzfree(essiv->salt);
        essiv->salt = NULL;
 
-       for_each_possible_cpu(cpu) {
-               cpu_cc = per_cpu_ptr(cc->cpu, cpu);
-               essiv_tfm = cpu_cc->iv_private;
+       essiv_tfm = cc->iv_private;
 
-               if (essiv_tfm)
-                       crypto_free_cipher(essiv_tfm);
+       if (essiv_tfm)
+               crypto_free_cipher(essiv_tfm);
 
-               cpu_cc->iv_private = NULL;
-       }
+       cc->iv_private = NULL;
 }
 
 static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
@@ -363,7 +355,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
        struct crypto_cipher *essiv_tfm = NULL;
        struct crypto_hash *hash_tfm = NULL;
        u8 *salt = NULL;
-       int err, cpu;
+       int err;
 
        if (!opts) {
                ti->error = "Digest algorithm missing for ESSIV mode";
@@ -388,15 +380,13 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
        cc->iv_gen_private.essiv.salt = salt;
        cc->iv_gen_private.essiv.hash_tfm = hash_tfm;
 
-       for_each_possible_cpu(cpu) {
-               essiv_tfm = setup_essiv_cpu(cc, ti, salt,
-                                       crypto_hash_digestsize(hash_tfm));
-               if (IS_ERR(essiv_tfm)) {
-                       crypt_iv_essiv_dtr(cc);
-                       return PTR_ERR(essiv_tfm);
-               }
-               per_cpu_ptr(cc->cpu, cpu)->iv_private = essiv_tfm;
+       essiv_tfm = setup_essiv_cpu(cc, ti, salt,
+                               crypto_hash_digestsize(hash_tfm));
+       if (IS_ERR(essiv_tfm)) {
+               crypt_iv_essiv_dtr(cc);
+               return PTR_ERR(essiv_tfm);
        }
+       cc->iv_private = essiv_tfm;
 
        return 0;
 
@@ -410,7 +400,7 @@ bad:
 static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv,
                              struct dm_crypt_request *dmreq)
 {
-       struct crypto_cipher *essiv_tfm = this_crypt_config(cc)->iv_private;
+       struct crypto_cipher *essiv_tfm = cc->iv_private;
 
        memset(iv, 0, cc->iv_size);
        *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector);
@@ -664,7 +654,7 @@ static void crypt_convert_init(struct crypt_config *cc,
        ctx->offset_out = 0;
        ctx->idx_in = bio_in ? bio_in->bi_idx : 0;
        ctx->idx_out = bio_out ? bio_out->bi_idx : 0;
-       ctx->sector = sector + cc->iv_offset;
+       ctx->cc_sector = sector + cc->iv_offset;
        init_completion(&ctx->restart);
 }
 
@@ -695,12 +685,12 @@ static int crypt_convert_block(struct crypt_config *cc,
        struct bio_vec *bv_out = bio_iovec_idx(ctx->bio_out, ctx->idx_out);
        struct dm_crypt_request *dmreq;
        u8 *iv;
-       int r = 0;
+       int r;
 
        dmreq = dmreq_of_req(cc, req);
        iv = iv_of_dmreq(cc, dmreq);
 
-       dmreq->iv_sector = ctx->sector;
+       dmreq->iv_sector = ctx->cc_sector;
        dmreq->ctx = ctx;
        sg_init_table(&dmreq->sg_in, 1);
        sg_set_page(&dmreq->sg_in, bv_in->bv_page, 1 << SECTOR_SHIFT,
@@ -749,12 +739,12 @@ static void crypt_alloc_req(struct crypt_config *cc,
                            struct convert_context *ctx)
 {
        struct crypt_cpu *this_cc = this_crypt_config(cc);
-       unsigned key_index = ctx->sector & (cc->tfms_count - 1);
+       unsigned key_index = ctx->cc_sector & (cc->tfms_count - 1);
 
        if (!this_cc->req)
                this_cc->req = mempool_alloc(cc->req_pool, GFP_NOIO);
 
-       ablkcipher_request_set_tfm(this_cc->req, this_cc->tfms[key_index]);
+       ablkcipher_request_set_tfm(this_cc->req, cc->tfms[key_index]);
        ablkcipher_request_set_callback(this_cc->req,
            CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
            kcryptd_async_done, dmreq_of_req(cc, this_cc->req));
@@ -769,14 +759,14 @@ static int crypt_convert(struct crypt_config *cc,
        struct crypt_cpu *this_cc = this_crypt_config(cc);
        int r;
 
-       atomic_set(&ctx->pending, 1);
+       atomic_set(&ctx->cc_pending, 1);
 
        while(ctx->idx_in < ctx->bio_in->bi_vcnt &&
              ctx->idx_out < ctx->bio_out->bi_vcnt) {
 
                crypt_alloc_req(cc, ctx);
 
-               atomic_inc(&ctx->pending);
+               atomic_inc(&ctx->cc_pending);
 
                r = crypt_convert_block(cc, ctx, this_cc->req);
 
@@ -788,19 +778,19 @@ static int crypt_convert(struct crypt_config *cc,
                        /* fall through*/
                case -EINPROGRESS:
                        this_cc->req = NULL;
-                       ctx->sector++;
+                       ctx->cc_sector++;
                        continue;
 
                /* sync */
                case 0:
-                       atomic_dec(&ctx->pending);
-                       ctx->sector++;
+                       atomic_dec(&ctx->cc_pending);
+                       ctx->cc_sector++;
                        cond_resched();
                        continue;
 
                /* error */
                default:
-                       atomic_dec(&ctx->pending);
+                       atomic_dec(&ctx->cc_pending);
                        return r;
                }
        }
@@ -811,7 +801,7 @@ static int crypt_convert(struct crypt_config *cc,
 static void dm_crypt_bio_destructor(struct bio *bio)
 {
        struct dm_crypt_io *io = bio->bi_private;
-       struct crypt_config *cc = io->target->private;
+       struct crypt_config *cc = io->cc;
 
        bio_free(bio, cc->bs);
 }
@@ -825,7 +815,7 @@ static void dm_crypt_bio_destructor(struct bio *bio)
 static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size,
                                      unsigned *out_of_pages)
 {
-       struct crypt_config *cc = io->target->private;
+       struct crypt_config *cc = io->cc;
        struct bio *clone;
        unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
        gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
@@ -884,26 +874,25 @@ static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone)
        }
 }
 
-static struct dm_crypt_io *crypt_io_alloc(struct dm_target *ti,
+static struct dm_crypt_io *crypt_io_alloc(struct crypt_config *cc,
                                          struct bio *bio, sector_t sector)
 {
-       struct crypt_config *cc = ti->private;
        struct dm_crypt_io *io;
 
        io = mempool_alloc(cc->io_pool, GFP_NOIO);
-       io->target = ti;
+       io->cc = cc;
        io->base_bio = bio;
        io->sector = sector;
        io->error = 0;
        io->base_io = NULL;
-       atomic_set(&io->pending, 0);
+       atomic_set(&io->io_pending, 0);
 
        return io;
 }
 
 static void crypt_inc_pending(struct dm_crypt_io *io)
 {
-       atomic_inc(&io->pending);
+       atomic_inc(&io->io_pending);
 }
 
 /*
@@ -913,12 +902,12 @@ static void crypt_inc_pending(struct dm_crypt_io *io)
  */
 static void crypt_dec_pending(struct dm_crypt_io *io)
 {
-       struct crypt_config *cc = io->target->private;
+       struct crypt_config *cc = io->cc;
        struct bio *base_bio = io->base_bio;
        struct dm_crypt_io *base_io = io->base_io;
        int error = io->error;
 
-       if (!atomic_dec_and_test(&io->pending))
+       if (!atomic_dec_and_test(&io->io_pending))
                return;
 
        mempool_free(io, cc->io_pool);
@@ -952,7 +941,7 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
 static void crypt_endio(struct bio *clone, int error)
 {
        struct dm_crypt_io *io = clone->bi_private;
-       struct crypt_config *cc = io->target->private;
+       struct crypt_config *cc = io->cc;
        unsigned rw = bio_data_dir(clone);
 
        if (unlikely(!bio_flagged(clone, BIO_UPTODATE) && !error))
@@ -979,7 +968,7 @@ static void crypt_endio(struct bio *clone, int error)
 
 static void clone_init(struct dm_crypt_io *io, struct bio *clone)
 {
-       struct crypt_config *cc = io->target->private;
+       struct crypt_config *cc = io->cc;
 
        clone->bi_private = io;
        clone->bi_end_io  = crypt_endio;
@@ -990,7 +979,7 @@ static void clone_init(struct dm_crypt_io *io, struct bio *clone)
 
 static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
 {
-       struct crypt_config *cc = io->target->private;
+       struct crypt_config *cc = io->cc;
        struct bio *base_bio = io->base_bio;
        struct bio *clone;
 
@@ -1038,7 +1027,7 @@ static void kcryptd_io(struct work_struct *work)
 
 static void kcryptd_queue_io(struct dm_crypt_io *io)
 {
-       struct crypt_config *cc = io->target->private;
+       struct crypt_config *cc = io->cc;
 
        INIT_WORK(&io->work, kcryptd_io);
        queue_work(cc->io_queue, &io->work);
@@ -1047,7 +1036,7 @@ static void kcryptd_queue_io(struct dm_crypt_io *io)
 static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
 {
        struct bio *clone = io->ctx.bio_out;
-       struct crypt_config *cc = io->target->private;
+       struct crypt_config *cc = io->cc;
 
        if (unlikely(io->error < 0)) {
                crypt_free_buffer_pages(cc, clone);
@@ -1069,7 +1058,7 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
 
 static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
 {
-       struct crypt_config *cc = io->target->private;
+       struct crypt_config *cc = io->cc;
        struct bio *clone;
        struct dm_crypt_io *new_io;
        int crypt_finished;
@@ -1107,7 +1096,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
                if (r < 0)
                        io->error = -EIO;
 
-               crypt_finished = atomic_dec_and_test(&io->ctx.pending);
+               crypt_finished = atomic_dec_and_test(&io->ctx.cc_pending);
 
                /* Encryption was already finished, submit io now */
                if (crypt_finished) {
@@ -1135,7 +1124,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
                 * between fragments, so switch to a new dm_crypt_io structure.
                 */
                if (unlikely(!crypt_finished && remaining)) {
-                       new_io = crypt_io_alloc(io->target, io->base_bio,
+                       new_io = crypt_io_alloc(io->cc, io->base_bio,
                                                sector);
                        crypt_inc_pending(new_io);
                        crypt_convert_init(cc, &new_io->ctx, NULL,
@@ -1169,7 +1158,7 @@ static void kcryptd_crypt_read_done(struct dm_crypt_io *io)
 
 static void kcryptd_crypt_read_convert(struct dm_crypt_io *io)
 {
-       struct crypt_config *cc = io->target->private;
+       struct crypt_config *cc = io->cc;
        int r = 0;
 
        crypt_inc_pending(io);
@@ -1181,7 +1170,7 @@ static void kcryptd_crypt_read_convert(struct dm_crypt_io *io)
        if (r < 0)
                io->error = -EIO;
 
-       if (atomic_dec_and_test(&io->ctx.pending))
+       if (atomic_dec_and_test(&io->ctx.cc_pending))
                kcryptd_crypt_read_done(io);
 
        crypt_dec_pending(io);
@@ -1193,7 +1182,7 @@ static void kcryptd_async_done(struct crypto_async_request *async_req,
        struct dm_crypt_request *dmreq = async_req->data;
        struct convert_context *ctx = dmreq->ctx;
        struct dm_crypt_io *io = container_of(ctx, struct dm_crypt_io, ctx);
-       struct crypt_config *cc = io->target->private;
+       struct crypt_config *cc = io->cc;
 
        if (error == -EINPROGRESS) {
                complete(&ctx->restart);
@@ -1208,7 +1197,7 @@ static void kcryptd_async_done(struct crypto_async_request *async_req,
 
        mempool_free(req_of_dmreq(cc, dmreq), cc->req_pool);
 
-       if (!atomic_dec_and_test(&ctx->pending))
+       if (!atomic_dec_and_test(&ctx->cc_pending))
                return;
 
        if (bio_data_dir(io->base_bio) == READ)
@@ -1229,7 +1218,7 @@ static void kcryptd_crypt(struct work_struct *work)
 
 static void kcryptd_queue_crypt(struct dm_crypt_io *io)
 {
-       struct crypt_config *cc = io->target->private;
+       struct crypt_config *cc = io->cc;
 
        INIT_WORK(&io->work, kcryptd_crypt);
        queue_work(cc->crypt_queue, &io->work);
@@ -1241,7 +1230,6 @@ static void kcryptd_queue_crypt(struct dm_crypt_io *io)
 static int crypt_decode_key(u8 *key, char *hex, unsigned int size)
 {
        char buffer[3];
-       char *endp;
        unsigned int i;
 
        buffer[2] = '\0';
@@ -1250,9 +1238,7 @@ static int crypt_decode_key(u8 *key, char *hex, unsigned int size)
                buffer[0] = *hex++;
                buffer[1] = *hex++;
 
-               key[i] = (u8)simple_strtoul(buffer, &endp, 16);
-
-               if (endp != &buffer[2])
+               if (kstrtou8(buffer, 16, &key[i]))
                        return -EINVAL;
        }
 
@@ -1276,29 +1262,38 @@ static void crypt_encode_key(char *hex, u8 *key, unsigned int size)
        }
 }
 
-static void crypt_free_tfms(struct crypt_config *cc, int cpu)
+static void crypt_free_tfms(struct crypt_config *cc)
 {
-       struct crypt_cpu *cpu_cc = per_cpu_ptr(cc->cpu, cpu);
        unsigned i;
 
+       if (!cc->tfms)
+               return;
+
        for (i = 0; i < cc->tfms_count; i++)
-               if (cpu_cc->tfms[i] && !IS_ERR(cpu_cc->tfms[i])) {
-                       crypto_free_ablkcipher(cpu_cc->tfms[i]);
-                       cpu_cc->tfms[i] = NULL;
+               if (cc->tfms[i] && !IS_ERR(cc->tfms[i])) {
+                       crypto_free_ablkcipher(cc->tfms[i]);
+                       cc->tfms[i] = NULL;
                }
+
+       kfree(cc->tfms);
+       cc->tfms = NULL;
 }
 
-static int crypt_alloc_tfms(struct crypt_config *cc, int cpu, char *ciphermode)
+static int crypt_alloc_tfms(struct crypt_config *cc, char *ciphermode)
 {
-       struct crypt_cpu *cpu_cc = per_cpu_ptr(cc->cpu, cpu);
        unsigned i;
        int err;
 
+       cc->tfms = kmalloc(cc->tfms_count * sizeof(struct crypto_ablkcipher *),
+                          GFP_KERNEL);
+       if (!cc->tfms)
+               return -ENOMEM;
+
        for (i = 0; i < cc->tfms_count; i++) {
-               cpu_cc->tfms[i] = crypto_alloc_ablkcipher(ciphermode, 0, 0);
-               if (IS_ERR(cpu_cc->tfms[i])) {
-                       err = PTR_ERR(cpu_cc->tfms[i]);
-                       crypt_free_tfms(cc, cpu);
+               cc->tfms[i] = crypto_alloc_ablkcipher(ciphermode, 0, 0);
+               if (IS_ERR(cc->tfms[i])) {
+                       err = PTR_ERR(cc->tfms[i]);
+                       crypt_free_tfms(cc);
                        return err;
                }
        }
@@ -1309,15 +1304,14 @@ static int crypt_alloc_tfms(struct crypt_config *cc, int cpu, char *ciphermode)
 static int crypt_setkey_allcpus(struct crypt_config *cc)
 {
        unsigned subkey_size = cc->key_size >> ilog2(cc->tfms_count);
-       int cpu, err = 0, i, r;
-
-       for_each_possible_cpu(cpu) {
-               for (i = 0; i < cc->tfms_count; i++) {
-                       r = crypto_ablkcipher_setkey(per_cpu_ptr(cc->cpu, cpu)->tfms[i],
-                                                    cc->key + (i * subkey_size), subkey_size);
-                       if (r)
-                               err = r;
-               }
+       int err = 0, i, r;
+
+       for (i = 0; i < cc->tfms_count; i++) {
+               r = crypto_ablkcipher_setkey(cc->tfms[i],
+                                            cc->key + (i * subkey_size),
+                                            subkey_size);
+               if (r)
+                       err = r;
        }
 
        return err;
@@ -1379,9 +1373,10 @@ static void crypt_dtr(struct dm_target *ti)
                        cpu_cc = per_cpu_ptr(cc->cpu, cpu);
                        if (cpu_cc->req)
                                mempool_free(cpu_cc->req, cc->req_pool);
-                       crypt_free_tfms(cc, cpu);
                }
 
+       crypt_free_tfms(cc);
+
        if (cc->bs)
                bioset_free(cc->bs);
 
@@ -1414,7 +1409,7 @@ static int crypt_ctr_cipher(struct dm_target *ti,
        struct crypt_config *cc = ti->private;
        char *tmp, *cipher, *chainmode, *ivmode, *ivopts, *keycount;
        char *cipher_api = NULL;
-       int cpu, ret = -EINVAL;
+       int ret = -EINVAL;
        char dummy;
 
        /* Convert to crypto api definition? */
@@ -1455,8 +1450,7 @@ static int crypt_ctr_cipher(struct dm_target *ti,
        if (tmp)
                DMWARN("Ignoring unexpected additional cipher options");
 
-       cc->cpu = __alloc_percpu(sizeof(*(cc->cpu)) +
-                                cc->tfms_count * sizeof(*(cc->cpu->tfms)),
+       cc->cpu = __alloc_percpu(sizeof(*(cc->cpu)),
                                 __alignof__(struct crypt_cpu));
        if (!cc->cpu) {
                ti->error = "Cannot allocate per cpu state";
@@ -1489,12 +1483,10 @@ static int crypt_ctr_cipher(struct dm_target *ti,
        }
 
        /* Allocate cipher */
-       for_each_possible_cpu(cpu) {
-               ret = crypt_alloc_tfms(cc, cpu, cipher_api);
-               if (ret < 0) {
-                       ti->error = "Error allocating crypto tfm";
-                       goto bad;
-               }
+       ret = crypt_alloc_tfms(cc, cipher_api);
+       if (ret < 0) {
+               ti->error = "Error allocating crypto tfm";
+               goto bad;
        }
 
        /* Initialize and set key */
@@ -1702,7 +1694,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
 
        ti->num_flush_requests = 1;
-       ti->discard_zeroes_data_unsupported = 1;
+       ti->discard_zeroes_data_unsupported = true;
 
        return 0;
 
@@ -1715,7 +1707,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
                     union map_info *map_context)
 {
        struct dm_crypt_io *io;
-       struct crypt_config *cc;
+       struct crypt_config *cc = ti->private;
 
        /*
         * If bio is REQ_FLUSH or REQ_DISCARD, just bypass crypt queues.
@@ -1723,14 +1715,13 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
         * - for REQ_DISCARD caller must use flush if IO ordering matters
         */
        if (unlikely(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))) {
-               cc = ti->private;
                bio->bi_bdev = cc->dev->bdev;
                if (bio_sectors(bio))
                        bio->bi_sector = cc->start + dm_target_offset(ti, bio->bi_sector);
                return DM_MAPIO_REMAPPED;
        }
 
-       io = crypt_io_alloc(ti, bio, dm_target_offset(ti, bio->bi_sector));
+       io = crypt_io_alloc(cc, bio, dm_target_offset(ti, bio->bi_sector));
 
        if (bio_data_dir(io->base_bio) == READ) {
                if (kcryptd_io_read(io, GFP_NOWAIT))
@@ -1742,7 +1733,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
 }
 
 static int crypt_status(struct dm_target *ti, status_type_t type,
-                       char *result, unsigned int maxlen)
+                       unsigned status_flags, char *result, unsigned maxlen)
 {
        struct crypt_config *cc = ti->private;
        unsigned int sz = 0;
index 2dc22dddb2ae31abe4b5bb2371dfb8eaedfeec73..f53846f9ab502466be3208312e8cea518a8eff4d 100644 (file)
@@ -295,7 +295,7 @@ static int delay_map(struct dm_target *ti, struct bio *bio,
 }
 
 static int delay_status(struct dm_target *ti, status_type_t type,
-                       char *result, unsigned maxlen)
+                       unsigned status_flags, char *result, unsigned maxlen)
 {
        struct delay_c *dc = ti->private;
        int sz = 0;
index aa70f7d43a1ab87750cee933d244eb098cb8d92b..ebaa4f803eec3a08a0cd9fcd9a9a1b933618c50c 100644 (file)
@@ -142,24 +142,19 @@ EXPORT_SYMBOL(dm_exception_store_type_unregister);
 static int set_chunk_size(struct dm_exception_store *store,
                          const char *chunk_size_arg, char **error)
 {
-       unsigned long chunk_size_ulong;
-       char *value;
+       unsigned chunk_size;
 
-       chunk_size_ulong = simple_strtoul(chunk_size_arg, &value, 10);
-       if (*chunk_size_arg == '\0' || *value != '\0' ||
-           chunk_size_ulong > UINT_MAX) {
+       if (kstrtouint(chunk_size_arg, 10, &chunk_size)) {
                *error = "Invalid chunk size";
                return -EINVAL;
        }
 
-       if (!chunk_size_ulong) {
+       if (!chunk_size) {
                store->chunk_size = store->chunk_mask = store->chunk_shift = 0;
                return 0;
        }
 
-       return dm_exception_store_set_chunk_size(store,
-                                                (unsigned) chunk_size_ulong,
-                                                error);
+       return dm_exception_store_set_chunk_size(store, chunk_size, error);
 }
 
 int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
index ac49c01f1a44bc6264ab50fcb1f7ba34bf271346..cc15543a6ad7088d712151df371a5b0b92d02dbe 100644 (file)
@@ -333,7 +333,7 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio,
 }
 
 static int flakey_status(struct dm_target *ti, status_type_t type,
-                        char *result, unsigned int maxlen)
+                        unsigned status_flags, char *result, unsigned maxlen)
 {
        unsigned sz = 0;
        struct flakey_c *fc = ti->private;
index a1a3e6df17b82624490952b0c91f94a9ea1e1f86..afd95986d09903a11652aafe8e90912db9f356ca 100644 (file)
@@ -1054,6 +1054,7 @@ static void retrieve_status(struct dm_table *table,
        char *outbuf, *outptr;
        status_type_t type;
        size_t remaining, len, used = 0;
+       unsigned status_flags = 0;
 
        outptr = outbuf = get_result_buffer(param, param_size, &len);
 
@@ -1090,7 +1091,9 @@ static void retrieve_status(struct dm_table *table,
 
                /* Get the status/table string from the target driver */
                if (ti->type->status) {
-                       if (ti->type->status(ti, type, outptr, remaining)) {
+                       if (param->flags & DM_NOFLUSH_FLAG)
+                               status_flags |= DM_STATUS_NOFLUSH_FLAG;
+                       if (ti->type->status(ti, type, status_flags, outptr, remaining)) {
                                param->flags |= DM_BUFFER_FULL_FLAG;
                                break;
                        }
index 3639eeab60421fb1829c2f70ee7bd7e193267463..1bf19a93eef05f00c68f3ad096dd46273991ef93 100644 (file)
@@ -96,7 +96,7 @@ static int linear_map(struct dm_target *ti, struct bio *bio,
 }
 
 static int linear_status(struct dm_target *ti, status_type_t type,
-                        char *result, unsigned int maxlen)
+                        unsigned status_flags, char *result, unsigned maxlen)
 {
        struct linear_c *lc = (struct linear_c *) ti->private;
 
index 65ebaebf502bdbc6e35f0cec1272589e2e5e000e..627d19186d5a1719f1780aaa21f7406edf6e99fd 100644 (file)
@@ -571,16 +571,6 @@ static void disk_dtr(struct dm_dirty_log *log)
        destroy_log_context(lc);
 }
 
-static int count_bits32(uint32_t *addr, unsigned size)
-{
-       int count = 0, i;
-
-       for (i = 0; i < size; i++) {
-               count += hweight32(*(addr+i));
-       }
-       return count;
-}
-
 static void fail_log_device(struct log_c *lc)
 {
        if (lc->log_dev_failed)
@@ -629,7 +619,8 @@ static int disk_resume(struct dm_dirty_log *log)
 
        /* copy clean across to sync */
        memcpy(lc->sync_bits, lc->clean_bits, size);
-       lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count);
+       lc->sync_count = memweight(lc->clean_bits,
+                               lc->bitset_uint32_count * sizeof(uint32_t));
        lc->sync_search = 0;
 
        /* set the correct number of regions in the header */
index 638dae048b4fada0633f2592538ee16535072b87..d8abb90a6c2fbecae99ae2de09ebc2f3d726731e 100644 (file)
@@ -85,6 +85,7 @@ struct multipath {
        unsigned queue_io:1;            /* Must we queue all I/O? */
        unsigned queue_if_no_path:1;    /* Queue I/O if last path fails? */
        unsigned saved_queue_if_no_path:1; /* Saved state during suspension */
+       unsigned retain_attached_hw_handler:1; /* If there's already a hw_handler present, don't change it. */
 
        unsigned pg_init_retries;       /* Number of times to retry pg_init */
        unsigned pg_init_count;         /* Number of times pg_init called */
@@ -568,6 +569,8 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
        int r;
        struct pgpath *p;
        struct multipath *m = ti->private;
+       struct request_queue *q = NULL;
+       const char *attached_handler_name;
 
        /* we need at least a path arg */
        if (as->argc < 1) {
@@ -586,13 +589,37 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
                goto bad;
        }
 
-       if (m->hw_handler_name) {
-               struct request_queue *q = bdev_get_queue(p->path.dev->bdev);
+       if (m->retain_attached_hw_handler || m->hw_handler_name)
+               q = bdev_get_queue(p->path.dev->bdev);
+
+       if (m->retain_attached_hw_handler) {
+               attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL);
+               if (attached_handler_name) {
+                       /*
+                        * Reset hw_handler_name to match the attached handler
+                        * and clear any hw_handler_params associated with the
+                        * ignored handler.
+                        *
+                        * NB. This modifies the table line to show the actual
+                        * handler instead of the original table passed in.
+                        */
+                       kfree(m->hw_handler_name);
+                       m->hw_handler_name = attached_handler_name;
+
+                       kfree(m->hw_handler_params);
+                       m->hw_handler_params = NULL;
+               }
+       }
 
+       if (m->hw_handler_name) {
+               /*
+                * Increments scsi_dh reference, even when using an
+                * already-attached handler.
+                */
                r = scsi_dh_attach(q, m->hw_handler_name);
                if (r == -EBUSY) {
                        /*
-                        * Already attached to different hw_handler,
+                        * Already attached to different hw_handler:
                         * try to reattach with correct one.
                         */
                        scsi_dh_detach(q);
@@ -760,7 +787,7 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m)
        const char *arg_name;
 
        static struct dm_arg _args[] = {
-               {0, 5, "invalid number of feature args"},
+               {0, 6, "invalid number of feature args"},
                {1, 50, "pg_init_retries must be between 1 and 50"},
                {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"},
        };
@@ -781,6 +808,11 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m)
                        continue;
                }
 
+               if (!strcasecmp(arg_name, "retain_attached_hw_handler")) {
+                       m->retain_attached_hw_handler = 1;
+                       continue;
+               }
+
                if (!strcasecmp(arg_name, "pg_init_retries") &&
                    (argc >= 1)) {
                        r = dm_read_arg(_args + 1, as, &m->pg_init_retries, &ti->error);
@@ -1346,7 +1378,7 @@ static void multipath_resume(struct dm_target *ti)
  *      num_paths num_selector_args [path_dev [selector_args]* ]+ ]+
  */
 static int multipath_status(struct dm_target *ti, status_type_t type,
-                           char *result, unsigned int maxlen)
+                           unsigned status_flags, char *result, unsigned maxlen)
 {
        int sz = 0;
        unsigned long flags;
@@ -1364,13 +1396,16 @@ static int multipath_status(struct dm_target *ti, status_type_t type,
        else {
                DMEMIT("%u ", m->queue_if_no_path +
                              (m->pg_init_retries > 0) * 2 +
-                             (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2);
+                             (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2 +
+                             m->retain_attached_hw_handler);
                if (m->queue_if_no_path)
                        DMEMIT("queue_if_no_path ");
                if (m->pg_init_retries)
                        DMEMIT("pg_init_retries %u ", m->pg_init_retries);
                if (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT)
                        DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs);
+               if (m->retain_attached_hw_handler)
+                       DMEMIT("retain_attached_hw_handler ");
        }
 
        if (!m->hw_handler_name || type == STATUSTYPE_INFO)
@@ -1656,7 +1691,7 @@ out:
  *---------------------------------------------------------------*/
 static struct target_type multipath_target = {
        .name = "multipath",
-       .version = {1, 4, 0},
+       .version = {1, 5, 0},
        .module = THIS_MODULE,
        .ctr = multipath_ctr,
        .dtr = multipath_dtr,
index 017c34d78d61f7ca42cfc0221449b4b55ab40052..f2f29c52654480314c1219e3524a7239821384c4 100644 (file)
@@ -101,20 +101,12 @@ static struct raid_set *context_alloc(struct dm_target *ti, struct raid_type *ra
 {
        unsigned i;
        struct raid_set *rs;
-       sector_t sectors_per_dev;
 
        if (raid_devs <= raid_type->parity_devs) {
                ti->error = "Insufficient number of devices";
                return ERR_PTR(-EINVAL);
        }
 
-       sectors_per_dev = ti->len;
-       if ((raid_type->level > 1) &&
-           sector_div(sectors_per_dev, (raid_devs - raid_type->parity_devs))) {
-               ti->error = "Target length not divisible by number of data devices";
-               return ERR_PTR(-EINVAL);
-       }
-
        rs = kzalloc(sizeof(*rs) + raid_devs * sizeof(rs->dev[0]), GFP_KERNEL);
        if (!rs) {
                ti->error = "Cannot allocate raid context";
@@ -128,7 +120,6 @@ static struct raid_set *context_alloc(struct dm_target *ti, struct raid_type *ra
        rs->md.raid_disks = raid_devs;
        rs->md.level = raid_type->level;
        rs->md.new_level = rs->md.level;
-       rs->md.dev_sectors = sectors_per_dev;
        rs->md.layout = raid_type->algorithm;
        rs->md.new_layout = rs->md.layout;
        rs->md.delta_disks = 0;
@@ -143,6 +134,7 @@ static struct raid_set *context_alloc(struct dm_target *ti, struct raid_type *ra
         *  rs->md.external
         *  rs->md.chunk_sectors
         *  rs->md.new_chunk_sectors
+        *  rs->md.dev_sectors
         */
 
        return rs;
@@ -353,6 +345,8 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
 {
        unsigned i, rebuild_cnt = 0;
        unsigned long value, region_size = 0;
+       sector_t sectors_per_dev = rs->ti->len;
+       sector_t max_io_len;
        char *key;
 
        /*
@@ -429,13 +423,28 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
 
                if (!strcasecmp(key, "rebuild")) {
                        rebuild_cnt++;
-                       if (((rs->raid_type->level != 1) &&
-                            (rebuild_cnt > rs->raid_type->parity_devs)) ||
-                           ((rs->raid_type->level == 1) &&
-                            (rebuild_cnt > (rs->md.raid_disks - 1)))) {
-                               rs->ti->error = "Too many rebuild devices specified for given RAID type";
+
+                       switch (rs->raid_type->level) {
+                       case 1:
+                               if (rebuild_cnt >= rs->md.raid_disks) {
+                                       rs->ti->error = "Too many rebuild devices specified";
+                                       return -EINVAL;
+                               }
+                               break;
+                       case 4:
+                       case 5:
+                       case 6:
+                               if (rebuild_cnt > rs->raid_type->parity_devs) {
+                                       rs->ti->error = "Too many rebuild devices specified for given RAID type";
+                                       return -EINVAL;
+                               }
+                               break;
+                       default:
+                               DMERR("The rebuild parameter is not supported for %s", rs->raid_type->name);
+                               rs->ti->error = "Rebuild not supported for this RAID type";
                                return -EINVAL;
                        }
+
                        if (value > rs->md.raid_disks) {
                                rs->ti->error = "Invalid rebuild index given";
                                return -EINVAL;
@@ -522,14 +531,19 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
                return -EINVAL;
 
        if (rs->md.chunk_sectors)
-               rs->ti->split_io = rs->md.chunk_sectors;
+               max_io_len = rs->md.chunk_sectors;
        else
-               rs->ti->split_io = region_size;
+               max_io_len = region_size;
 
-       if (rs->md.chunk_sectors)
-               rs->ti->split_io = rs->md.chunk_sectors;
-       else
-               rs->ti->split_io = region_size;
+       if (dm_set_target_max_io_len(rs->ti, max_io_len))
+               return -EINVAL;
+
+       if ((rs->raid_type->level > 1) &&
+           sector_div(sectors_per_dev, (rs->md.raid_disks - rs->raid_type->parity_devs))) {
+               rs->ti->error = "Target length not divisible by number of data devices";
+               return -EINVAL;
+       }
+       rs->md.dev_sectors = sectors_per_dev;
 
        /* Assume there are no metadata devices until the drives are parsed */
        rs->md.persistent = 0;
@@ -1067,7 +1081,7 @@ static int raid_map(struct dm_target *ti, struct bio *bio, union map_info *map_c
 }
 
 static int raid_status(struct dm_target *ti, status_type_t type,
-                      char *result, unsigned maxlen)
+                      unsigned status_flags, char *result, unsigned maxlen)
 {
        struct raid_set *rs = ti->private;
        unsigned raid_param_cnt = 1; /* at least 1 for chunksize */
index b58b7a33914abd721e3508835a61afd699221dbf..bc5ddba8045b84a24e996235604a5db24d1d0e58 100644 (file)
@@ -1081,10 +1081,14 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
 
        ti->private = ms;
-       ti->split_io = dm_rh_get_region_size(ms->rh);
+
+       r = dm_set_target_max_io_len(ti, dm_rh_get_region_size(ms->rh));
+       if (r)
+               goto err_free_context;
+
        ti->num_flush_requests = 1;
        ti->num_discard_requests = 1;
-       ti->discard_zeroes_data_unsupported = 1;
+       ti->discard_zeroes_data_unsupported = true;
 
        ms->kmirrord_wq = alloc_workqueue("kmirrord",
                                          WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
@@ -1363,7 +1367,7 @@ static char device_status_char(struct mirror *m)
 
 
 static int mirror_status(struct dm_target *ti, status_type_t type,
-                        char *result, unsigned int maxlen)
+                        unsigned status_flags, char *result, unsigned maxlen)
 {
        unsigned int m, sz = 0;
        struct mirror_set *ms = (struct mirror_set *) ti->private;
index 6f758870fc19cf0e66db3055dab36ab96e038fee..a143921feaf6480119f77d4f8600aefc98c7b583 100644 (file)
@@ -691,7 +691,7 @@ static int dm_add_exception(void *context, chunk_t old, chunk_t new)
  * Return a minimum chunk size of all snapshots that have the specified origin.
  * Return zero if the origin has no snapshots.
  */
-static sector_t __minimum_chunk_size(struct origin *o)
+static uint32_t __minimum_chunk_size(struct origin *o)
 {
        struct dm_snapshot *snap;
        unsigned chunk_size = 0;
@@ -701,7 +701,7 @@ static sector_t __minimum_chunk_size(struct origin *o)
                        chunk_size = min_not_zero(chunk_size,
                                                  snap->store->chunk_size);
 
-       return chunk_size;
+       return (uint32_t) chunk_size;
 }
 
 /*
@@ -1172,7 +1172,10 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                ti->error = "Chunk size not set";
                goto bad_read_metadata;
        }
-       ti->split_io = s->store->chunk_size;
+
+       r = dm_set_target_max_io_len(ti, s->store->chunk_size);
+       if (r)
+               goto bad_read_metadata;
 
        return 0;
 
@@ -1239,7 +1242,7 @@ static void __handover_exceptions(struct dm_snapshot *snap_src,
        snap_dest->store->snap = snap_dest;
        snap_src->store->snap = snap_src;
 
-       snap_dest->ti->split_io = snap_dest->store->chunk_size;
+       snap_dest->ti->max_io_len = snap_dest->store->chunk_size;
        snap_dest->valid = snap_src->valid;
 
        /*
@@ -1817,9 +1820,9 @@ static void snapshot_resume(struct dm_target *ti)
        up_write(&s->lock);
 }
 
-static sector_t get_origin_minimum_chunksize(struct block_device *bdev)
+static uint32_t get_origin_minimum_chunksize(struct block_device *bdev)
 {
-       sector_t min_chunksize;
+       uint32_t min_chunksize;
 
        down_read(&_origins_lock);
        min_chunksize = __minimum_chunk_size(__lookup_origin(bdev));
@@ -1838,15 +1841,15 @@ static void snapshot_merge_resume(struct dm_target *ti)
        snapshot_resume(ti);
 
        /*
-        * snapshot-merge acts as an origin, so set ti->split_io
+        * snapshot-merge acts as an origin, so set ti->max_io_len
         */
-       ti->split_io = get_origin_minimum_chunksize(s->origin->bdev);
+       ti->max_io_len = get_origin_minimum_chunksize(s->origin->bdev);
 
        start_merge(s);
 }
 
 static int snapshot_status(struct dm_target *ti, status_type_t type,
-                          char *result, unsigned int maxlen)
+                          unsigned status_flags, char *result, unsigned maxlen)
 {
        unsigned sz = 0;
        struct dm_snapshot *snap = ti->private;
@@ -2073,12 +2076,12 @@ static int origin_write_extent(struct dm_snapshot *merging_snap,
        struct origin *o;
 
        /*
-        * The origin's __minimum_chunk_size() got stored in split_io
+        * The origin's __minimum_chunk_size() got stored in max_io_len
         * by snapshot_merge_resume().
         */
        down_read(&_origins_lock);
        o = __lookup_origin(merging_snap->origin->bdev);
-       for (n = 0; n < size; n += merging_snap->ti->split_io)
+       for (n = 0; n < size; n += merging_snap->ti->max_io_len)
                if (__origin_write(&o->snapshots, sector + n, NULL) ==
                    DM_MAPIO_SUBMITTED)
                        must_wait = 1;
@@ -2138,18 +2141,18 @@ static int origin_map(struct dm_target *ti, struct bio *bio,
 }
 
 /*
- * Set the target "split_io" field to the minimum of all the snapshots'
+ * Set the target "max_io_len" field to the minimum of all the snapshots'
  * chunk sizes.
  */
 static void origin_resume(struct dm_target *ti)
 {
        struct dm_dev *dev = ti->private;
 
-       ti->split_io = get_origin_minimum_chunksize(dev->bdev);
+       ti->max_io_len = get_origin_minimum_chunksize(dev->bdev);
 }
 
-static int origin_status(struct dm_target *ti, status_type_t type, char *result,
-                        unsigned int maxlen)
+static int origin_status(struct dm_target *ti, status_type_t type,
+                        unsigned status_flags, char *result, unsigned maxlen)
 {
        struct dm_dev *dev = ti->private;
 
@@ -2176,7 +2179,6 @@ static int origin_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
                return max_size;
 
        bvm->bi_bdev = dev->bdev;
-       bvm->bi_sector = bvm->bi_sector;
 
        return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
 }
index 35c94ff24ad5867917ed715a8ce387fbb8d3b150..a087bf2a8d6666bbc699a44af28d003b4d2cfb88 100644 (file)
@@ -26,14 +26,12 @@ struct stripe {
 struct stripe_c {
        uint32_t stripes;
        int stripes_shift;
-       sector_t stripes_mask;
 
        /* The size of this target / num. stripes */
        sector_t stripe_width;
 
-       /* stripe chunk size */
-       uint32_t chunk_shift;
-       sector_t chunk_mask;
+       uint32_t chunk_size;
+       int chunk_size_shift;
 
        /* Needed for handling events */
        struct dm_target *ti;
@@ -91,7 +89,7 @@ static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
 
 /*
  * Construct a striped mapping.
- * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
+ * <number of stripes> <chunk size> [<dev_path> <offset>]+
  */
 static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
@@ -99,7 +97,6 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        sector_t width;
        uint32_t stripes;
        uint32_t chunk_size;
-       char *end;
        int r;
        unsigned int i;
 
@@ -108,34 +105,23 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                return -EINVAL;
        }
 
-       stripes = simple_strtoul(argv[0], &end, 10);
-       if (!stripes || *end) {
+       if (kstrtouint(argv[0], 10, &stripes) || !stripes) {
                ti->error = "Invalid stripe count";
                return -EINVAL;
        }
 
-       chunk_size = simple_strtoul(argv[1], &end, 10);
-       if (*end) {
+       if (kstrtouint(argv[1], 10, &chunk_size) || !chunk_size) {
                ti->error = "Invalid chunk_size";
                return -EINVAL;
        }
 
-       /*
-        * chunk_size is a power of two
-        */
-       if (!is_power_of_2(chunk_size) ||
-           (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) {
-               ti->error = "Invalid chunk size";
-               return -EINVAL;
-       }
-
-       if (ti->len & (chunk_size - 1)) {
+       width = ti->len;
+       if (sector_div(width, chunk_size)) {
                ti->error = "Target length not divisible by "
                    "chunk size";
                return -EINVAL;
        }
 
-       width = ti->len;
        if (sector_div(width, stripes)) {
                ti->error = "Target length not divisible by "
                    "number of stripes";
@@ -167,17 +153,21 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        if (stripes & (stripes - 1))
                sc->stripes_shift = -1;
-       else {
-               sc->stripes_shift = ffs(stripes) - 1;
-               sc->stripes_mask = ((sector_t) stripes) - 1;
-       }
+       else
+               sc->stripes_shift = __ffs(stripes);
+
+       r = dm_set_target_max_io_len(ti, chunk_size);
+       if (r)
+               return r;
 
-       ti->split_io = chunk_size;
        ti->num_flush_requests = stripes;
        ti->num_discard_requests = stripes;
 
-       sc->chunk_shift = ffs(chunk_size) - 1;
-       sc->chunk_mask = ((sector_t) chunk_size) - 1;
+       sc->chunk_size = chunk_size;
+       if (chunk_size & (chunk_size - 1))
+               sc->chunk_size_shift = -1;
+       else
+               sc->chunk_size_shift = __ffs(chunk_size);
 
        /*
         * Get the stripe destinations.
@@ -216,17 +206,29 @@ static void stripe_dtr(struct dm_target *ti)
 static void stripe_map_sector(struct stripe_c *sc, sector_t sector,
                              uint32_t *stripe, sector_t *result)
 {
-       sector_t offset = dm_target_offset(sc->ti, sector);
-       sector_t chunk = offset >> sc->chunk_shift;
+       sector_t chunk = dm_target_offset(sc->ti, sector);
+       sector_t chunk_offset;
+
+       if (sc->chunk_size_shift < 0)
+               chunk_offset = sector_div(chunk, sc->chunk_size);
+       else {
+               chunk_offset = chunk & (sc->chunk_size - 1);
+               chunk >>= sc->chunk_size_shift;
+       }
 
        if (sc->stripes_shift < 0)
                *stripe = sector_div(chunk, sc->stripes);
        else {
-               *stripe = chunk & sc->stripes_mask;
+               *stripe = chunk & (sc->stripes - 1);
                chunk >>= sc->stripes_shift;
        }
 
-       *result = (chunk << sc->chunk_shift) | (offset & sc->chunk_mask);
+       if (sc->chunk_size_shift < 0)
+               chunk *= sc->chunk_size;
+       else
+               chunk <<= sc->chunk_size_shift;
+
+       *result = chunk + chunk_offset;
 }
 
 static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
@@ -237,9 +239,16 @@ static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
        stripe_map_sector(sc, sector, &stripe, result);
        if (stripe == target_stripe)
                return;
-       *result &= ~sc->chunk_mask;                     /* round down */
+
+       /* round down */
+       sector = *result;
+       if (sc->chunk_size_shift < 0)
+               *result -= sector_div(sector, sc->chunk_size);
+       else
+               *result = sector & ~(sector_t)(sc->chunk_size - 1);
+
        if (target_stripe < stripe)
-               *result += sc->chunk_mask + 1;          /* next chunk */
+               *result += sc->chunk_size;              /* next chunk */
 }
 
 static int stripe_map_discard(struct stripe_c *sc, struct bio *bio,
@@ -302,8 +311,8 @@ static int stripe_map(struct dm_target *ti, struct bio *bio,
  *
  */
 
-static int stripe_status(struct dm_target *ti,
-                        status_type_t type, char *result, unsigned int maxlen)
+static int stripe_status(struct dm_target *ti, status_type_t type,
+                        unsigned status_flags, char *result, unsigned maxlen)
 {
        struct stripe_c *sc = (struct stripe_c *) ti->private;
        char buffer[sc->stripes + 1];
@@ -324,7 +333,7 @@ static int stripe_status(struct dm_target *ti,
 
        case STATUSTYPE_TABLE:
                DMEMIT("%d %llu", sc->stripes,
-                       (unsigned long long)sc->chunk_mask + 1);
+                       (unsigned long long)sc->chunk_size);
                for (i = 0; i < sc->stripes; i++)
                        DMEMIT(" %s %llu", sc->stripe[i].dev->name,
                            (unsigned long long)sc->stripe[i].physical_start);
@@ -391,7 +400,7 @@ static void stripe_io_hints(struct dm_target *ti,
                            struct queue_limits *limits)
 {
        struct stripe_c *sc = ti->private;
-       unsigned chunk_size = (sc->chunk_mask + 1) << 9;
+       unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT;
 
        blk_limits_io_min(limits, chunk_size);
        blk_limits_io_opt(limits, chunk_size * sc->stripes);
@@ -419,7 +428,7 @@ static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
 
 static struct target_type stripe_target = {
        .name   = "striped",
-       .version = {1, 4, 0},
+       .version = {1, 5, 0},
        .module = THIS_MODULE,
        .ctr    = stripe_ctr,
        .dtr    = stripe_dtr,
index 2e227fbf1622c075c6fc543f5b2d30fb2bf7dbd7..f90069029aaeed02ab6f4f61814afc92d13db2f0 100644 (file)
@@ -1319,6 +1319,9 @@ static bool dm_table_supports_flush(struct dm_table *t, unsigned flush)
                if (!ti->num_flush_requests)
                        continue;
 
+               if (ti->flush_supported)
+                       return 1;
+
                if (ti->type->iterate_devices &&
                    ti->type->iterate_devices(ti, device_flush_capable, &flush))
                        return 1;
index 3e2907f0bc462e261c05fab97cb0bff272649868..693e149e97271dbe3fa3b646cfac018533892835 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011-2012 Red Hat, Inc.
  *
  * This file is released under the GPL.
  */
 #define THIN_METADATA_CACHE_SIZE 64
 #define SECTOR_TO_BLOCK_SHIFT 3
 
+/*
+ *  3 for btree insert +
+ *  2 for btree lookup used within space map
+ */
+#define THIN_MAX_CONCURRENT_LOCKS 5
+
 /* This should be plenty */
 #define SPACE_MAP_ROOT_SIZE 128
 
@@ -172,13 +178,20 @@ struct dm_pool_metadata {
 
        struct rw_semaphore root_lock;
        uint32_t time;
-       int need_commit;
        dm_block_t root;
        dm_block_t details_root;
        struct list_head thin_devices;
        uint64_t trans_id;
        unsigned long flags;
        sector_t data_block_size;
+       bool read_only:1;
+
+       /*
+        * Set if a transaction has to be aborted but the attempt to roll back
+        * to the previous (good) transaction failed.  The only pool metadata
+        * operation possible in this state is the closing of the device.
+        */
+       bool fail_io:1;
 };
 
 struct dm_thin_device {
@@ -187,7 +200,8 @@ struct dm_thin_device {
        dm_thin_id id;
 
        int open_count;
-       int changed;
+       bool changed:1;
+       bool aborted_with_changes:1;
        uint64_t mapped_blocks;
        uint64_t transaction_id;
        uint32_t creation_time;
@@ -338,7 +352,21 @@ static int subtree_equal(void *context, void *value1_le, void *value2_le)
 
 /*----------------------------------------------------------------*/
 
-static int superblock_all_zeroes(struct dm_block_manager *bm, int *result)
+static int superblock_lock_zero(struct dm_pool_metadata *pmd,
+                               struct dm_block **sblock)
+{
+       return dm_bm_write_lock_zero(pmd->bm, THIN_SUPERBLOCK_LOCATION,
+                                    &sb_validator, sblock);
+}
+
+static int superblock_lock(struct dm_pool_metadata *pmd,
+                          struct dm_block **sblock)
+{
+       return dm_bm_write_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION,
+                               &sb_validator, sblock);
+}
+
+static int __superblock_all_zeroes(struct dm_block_manager *bm, int *result)
 {
        int r;
        unsigned i;
@@ -365,72 +393,9 @@ static int superblock_all_zeroes(struct dm_block_manager *bm, int *result)
        return dm_bm_unlock(b);
 }
 
-static int init_pmd(struct dm_pool_metadata *pmd,
-                   struct dm_block_manager *bm,
-                   dm_block_t nr_blocks, int create)
+static void __setup_btree_details(struct dm_pool_metadata *pmd)
 {
-       int r;
-       struct dm_space_map *sm, *data_sm;
-       struct dm_transaction_manager *tm;
-       struct dm_block *sblock;
-
-       if (create) {
-               r = dm_tm_create_with_sm(bm, THIN_SUPERBLOCK_LOCATION,
-                                        &sb_validator, &tm, &sm, &sblock);
-               if (r < 0) {
-                       DMERR("tm_create_with_sm failed");
-                       return r;
-               }
-
-               data_sm = dm_sm_disk_create(tm, nr_blocks);
-               if (IS_ERR(data_sm)) {
-                       DMERR("sm_disk_create failed");
-                       dm_tm_unlock(tm, sblock);
-                       r = PTR_ERR(data_sm);
-                       goto bad;
-               }
-       } else {
-               struct thin_disk_superblock *disk_super = NULL;
-               size_t space_map_root_offset =
-                       offsetof(struct thin_disk_superblock, metadata_space_map_root);
-
-               r = dm_tm_open_with_sm(bm, THIN_SUPERBLOCK_LOCATION,
-                                      &sb_validator, space_map_root_offset,
-                                      SPACE_MAP_ROOT_SIZE, &tm, &sm, &sblock);
-               if (r < 0) {
-                       DMERR("tm_open_with_sm failed");
-                       return r;
-               }
-
-               disk_super = dm_block_data(sblock);
-               data_sm = dm_sm_disk_open(tm, disk_super->data_space_map_root,
-                                         sizeof(disk_super->data_space_map_root));
-               if (IS_ERR(data_sm)) {
-                       DMERR("sm_disk_open failed");
-                       r = PTR_ERR(data_sm);
-                       goto bad;
-               }
-       }
-
-
-       r = dm_tm_unlock(tm, sblock);
-       if (r < 0) {
-               DMERR("couldn't unlock superblock");
-               goto bad_data_sm;
-       }
-
-       pmd->bm = bm;
-       pmd->metadata_sm = sm;
-       pmd->data_sm = data_sm;
-       pmd->tm = tm;
-       pmd->nb_tm = dm_tm_create_non_blocking_clone(tm);
-       if (!pmd->nb_tm) {
-               DMERR("could not create clone tm");
-               r = -ENOMEM;
-               goto bad_data_sm;
-       }
-
-       pmd->info.tm = tm;
+       pmd->info.tm = pmd->tm;
        pmd->info.levels = 2;
        pmd->info.value_type.context = pmd->data_sm;
        pmd->info.value_type.size = sizeof(__le64);
@@ -441,7 +406,7 @@ static int init_pmd(struct dm_pool_metadata *pmd,
        memcpy(&pmd->nb_info, &pmd->info, sizeof(pmd->nb_info));
        pmd->nb_info.tm = pmd->nb_tm;
 
-       pmd->tl_info.tm = tm;
+       pmd->tl_info.tm = pmd->tm;
        pmd->tl_info.levels = 1;
        pmd->tl_info.value_type.context = &pmd->info;
        pmd->tl_info.value_type.size = sizeof(__le64);
@@ -449,7 +414,7 @@ static int init_pmd(struct dm_pool_metadata *pmd,
        pmd->tl_info.value_type.dec = subtree_dec;
        pmd->tl_info.value_type.equal = subtree_equal;
 
-       pmd->bl_info.tm = tm;
+       pmd->bl_info.tm = pmd->tm;
        pmd->bl_info.levels = 1;
        pmd->bl_info.value_type.context = pmd->data_sm;
        pmd->bl_info.value_type.size = sizeof(__le64);
@@ -457,47 +422,265 @@ static int init_pmd(struct dm_pool_metadata *pmd,
        pmd->bl_info.value_type.dec = data_block_dec;
        pmd->bl_info.value_type.equal = data_block_equal;
 
-       pmd->details_info.tm = tm;
+       pmd->details_info.tm = pmd->tm;
        pmd->details_info.levels = 1;
        pmd->details_info.value_type.context = NULL;
        pmd->details_info.value_type.size = sizeof(struct disk_device_details);
        pmd->details_info.value_type.inc = NULL;
        pmd->details_info.value_type.dec = NULL;
        pmd->details_info.value_type.equal = NULL;
+}
 
-       pmd->root = 0;
+static int __write_initial_superblock(struct dm_pool_metadata *pmd)
+{
+       int r;
+       struct dm_block *sblock;
+       size_t metadata_len, data_len;
+       struct thin_disk_superblock *disk_super;
+       sector_t bdev_size = i_size_read(pmd->bdev->bd_inode) >> SECTOR_SHIFT;
 
-       init_rwsem(&pmd->root_lock);
-       pmd->time = 0;
-       pmd->need_commit = 0;
-       pmd->details_root = 0;
-       pmd->trans_id = 0;
-       pmd->flags = 0;
-       INIT_LIST_HEAD(&pmd->thin_devices);
+       if (bdev_size > THIN_METADATA_MAX_SECTORS)
+               bdev_size = THIN_METADATA_MAX_SECTORS;
+
+       r = dm_sm_root_size(pmd->metadata_sm, &metadata_len);
+       if (r < 0)
+               return r;
+
+       r = dm_sm_root_size(pmd->data_sm, &data_len);
+       if (r < 0)
+               return r;
+
+       r = dm_sm_commit(pmd->data_sm);
+       if (r < 0)
+               return r;
+
+       r = dm_tm_pre_commit(pmd->tm);
+       if (r < 0)
+               return r;
+
+       r = superblock_lock_zero(pmd, &sblock);
+       if (r)
+               return r;
+
+       disk_super = dm_block_data(sblock);
+       disk_super->flags = 0;
+       memset(disk_super->uuid, 0, sizeof(disk_super->uuid));
+       disk_super->magic = cpu_to_le64(THIN_SUPERBLOCK_MAGIC);
+       disk_super->version = cpu_to_le32(THIN_VERSION);
+       disk_super->time = 0;
+       disk_super->trans_id = 0;
+       disk_super->held_root = 0;
+
+       r = dm_sm_copy_root(pmd->metadata_sm, &disk_super->metadata_space_map_root,
+                           metadata_len);
+       if (r < 0)
+               goto bad_locked;
+
+       r = dm_sm_copy_root(pmd->data_sm, &disk_super->data_space_map_root,
+                           data_len);
+       if (r < 0)
+               goto bad_locked;
+
+       disk_super->data_mapping_root = cpu_to_le64(pmd->root);
+       disk_super->device_details_root = cpu_to_le64(pmd->details_root);
+       disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT);
+       disk_super->metadata_nr_blocks = cpu_to_le64(bdev_size >> SECTOR_TO_BLOCK_SHIFT);
+       disk_super->data_block_size = cpu_to_le32(pmd->data_block_size);
+
+       return dm_tm_commit(pmd->tm, sblock);
+
+bad_locked:
+       dm_bm_unlock(sblock);
+       return r;
+}
+
+static int __format_metadata(struct dm_pool_metadata *pmd)
+{
+       int r;
+
+       r = dm_tm_create_with_sm(pmd->bm, THIN_SUPERBLOCK_LOCATION,
+                                &pmd->tm, &pmd->metadata_sm);
+       if (r < 0) {
+               DMERR("tm_create_with_sm failed");
+               return r;
+       }
+
+       pmd->data_sm = dm_sm_disk_create(pmd->tm, 0);
+       if (IS_ERR(pmd->data_sm)) {
+               DMERR("sm_disk_create failed");
+               r = PTR_ERR(pmd->data_sm);
+               goto bad_cleanup_tm;
+       }
+
+       pmd->nb_tm = dm_tm_create_non_blocking_clone(pmd->tm);
+       if (!pmd->nb_tm) {
+               DMERR("could not create non-blocking clone tm");
+               r = -ENOMEM;
+               goto bad_cleanup_data_sm;
+       }
+
+       __setup_btree_details(pmd);
+
+       r = dm_btree_empty(&pmd->info, &pmd->root);
+       if (r < 0)
+               goto bad_cleanup_nb_tm;
+
+       r = dm_btree_empty(&pmd->details_info, &pmd->details_root);
+       if (r < 0) {
+               DMERR("couldn't create devices root");
+               goto bad_cleanup_nb_tm;
+       }
+
+       r = __write_initial_superblock(pmd);
+       if (r)
+               goto bad_cleanup_nb_tm;
 
        return 0;
 
-bad_data_sm:
-       dm_sm_destroy(data_sm);
-bad:
-       dm_tm_destroy(tm);
-       dm_sm_destroy(sm);
+bad_cleanup_nb_tm:
+       dm_tm_destroy(pmd->nb_tm);
+bad_cleanup_data_sm:
+       dm_sm_destroy(pmd->data_sm);
+bad_cleanup_tm:
+       dm_tm_destroy(pmd->tm);
+       dm_sm_destroy(pmd->metadata_sm);
+
+       return r;
+}
+
+static int __check_incompat_features(struct thin_disk_superblock *disk_super,
+                                    struct dm_pool_metadata *pmd)
+{
+       uint32_t features;
+
+       features = le32_to_cpu(disk_super->incompat_flags) & ~THIN_FEATURE_INCOMPAT_SUPP;
+       if (features) {
+               DMERR("could not access metadata due to unsupported optional features (%lx).",
+                     (unsigned long)features);
+               return -EINVAL;
+       }
+
+       /*
+        * Check for read-only metadata to skip the following RDWR checks.
+        */
+       if (get_disk_ro(pmd->bdev->bd_disk))
+               return 0;
+
+       features = le32_to_cpu(disk_super->compat_ro_flags) & ~THIN_FEATURE_COMPAT_RO_SUPP;
+       if (features) {
+               DMERR("could not access metadata RDWR due to unsupported optional features (%lx).",
+                     (unsigned long)features);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int __open_metadata(struct dm_pool_metadata *pmd)
+{
+       int r;
+       struct dm_block *sblock;
+       struct thin_disk_superblock *disk_super;
+
+       r = dm_bm_read_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION,
+                           &sb_validator, &sblock);
+       if (r < 0) {
+               DMERR("couldn't read superblock");
+               return r;
+       }
+
+       disk_super = dm_block_data(sblock);
+
+       r = __check_incompat_features(disk_super, pmd);
+       if (r < 0)
+               goto bad_unlock_sblock;
+
+       r = dm_tm_open_with_sm(pmd->bm, THIN_SUPERBLOCK_LOCATION,
+                              disk_super->metadata_space_map_root,
+                              sizeof(disk_super->metadata_space_map_root),
+                              &pmd->tm, &pmd->metadata_sm);
+       if (r < 0) {
+               DMERR("tm_open_with_sm failed");
+               goto bad_unlock_sblock;
+       }
+
+       pmd->data_sm = dm_sm_disk_open(pmd->tm, disk_super->data_space_map_root,
+                                      sizeof(disk_super->data_space_map_root));
+       if (IS_ERR(pmd->data_sm)) {
+               DMERR("sm_disk_open failed");
+               r = PTR_ERR(pmd->data_sm);
+               goto bad_cleanup_tm;
+       }
+
+       pmd->nb_tm = dm_tm_create_non_blocking_clone(pmd->tm);
+       if (!pmd->nb_tm) {
+               DMERR("could not create non-blocking clone tm");
+               r = -ENOMEM;
+               goto bad_cleanup_data_sm;
+       }
+
+       __setup_btree_details(pmd);
+       return dm_bm_unlock(sblock);
+
+bad_cleanup_data_sm:
+       dm_sm_destroy(pmd->data_sm);
+bad_cleanup_tm:
+       dm_tm_destroy(pmd->tm);
+       dm_sm_destroy(pmd->metadata_sm);
+bad_unlock_sblock:
+       dm_bm_unlock(sblock);
+
+       return r;
+}
+
+static int __open_or_format_metadata(struct dm_pool_metadata *pmd, bool format_device)
+{
+       int r, unformatted;
+
+       r = __superblock_all_zeroes(pmd->bm, &unformatted);
+       if (r)
+               return r;
+
+       if (unformatted)
+               return format_device ? __format_metadata(pmd) : -EPERM;
+
+       return __open_metadata(pmd);
+}
+
+static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool format_device)
+{
+       int r;
+
+       pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE,
+                                         THIN_METADATA_CACHE_SIZE,
+                                         THIN_MAX_CONCURRENT_LOCKS);
+       if (IS_ERR(pmd->bm)) {
+               DMERR("could not create block manager");
+               return PTR_ERR(pmd->bm);
+       }
+
+       r = __open_or_format_metadata(pmd, format_device);
+       if (r)
+               dm_block_manager_destroy(pmd->bm);
 
        return r;
 }
 
+static void __destroy_persistent_data_objects(struct dm_pool_metadata *pmd)
+{
+       dm_sm_destroy(pmd->data_sm);
+       dm_sm_destroy(pmd->metadata_sm);
+       dm_tm_destroy(pmd->nb_tm);
+       dm_tm_destroy(pmd->tm);
+       dm_block_manager_destroy(pmd->bm);
+}
+
 static int __begin_transaction(struct dm_pool_metadata *pmd)
 {
        int r;
-       u32 features;
        struct thin_disk_superblock *disk_super;
        struct dm_block *sblock;
 
-       /*
-        * __maybe_commit_transaction() resets these
-        */
-       WARN_ON(pmd->need_commit);
-
        /*
         * We re-read the superblock every time.  Shouldn't need to do this
         * really.
@@ -515,32 +698,8 @@ static int __begin_transaction(struct dm_pool_metadata *pmd)
        pmd->flags = le32_to_cpu(disk_super->flags);
        pmd->data_block_size = le32_to_cpu(disk_super->data_block_size);
 
-       features = le32_to_cpu(disk_super->incompat_flags) & ~THIN_FEATURE_INCOMPAT_SUPP;
-       if (features) {
-               DMERR("could not access metadata due to "
-                     "unsupported optional features (%lx).",
-                     (unsigned long)features);
-               r = -EINVAL;
-               goto out;
-       }
-
-       /*
-        * Check for read-only metadata to skip the following RDWR checks.
-        */
-       if (get_disk_ro(pmd->bdev->bd_disk))
-               goto out;
-
-       features = le32_to_cpu(disk_super->compat_ro_flags) & ~THIN_FEATURE_COMPAT_RO_SUPP;
-       if (features) {
-               DMERR("could not access metadata RDWR due to "
-                     "unsupported optional features (%lx).",
-                     (unsigned long)features);
-               r = -EINVAL;
-       }
-
-out:
        dm_bm_unlock(sblock);
-       return r;
+       return 0;
 }
 
 static int __write_changed_details(struct dm_pool_metadata *pmd)
@@ -573,8 +732,6 @@ static int __write_changed_details(struct dm_pool_metadata *pmd)
                        list_del(&td->list);
                        kfree(td);
                }
-
-               pmd->need_commit = 1;
        }
 
        return 0;
@@ -582,9 +739,6 @@ static int __write_changed_details(struct dm_pool_metadata *pmd)
 
 static int __commit_transaction(struct dm_pool_metadata *pmd)
 {
-       /*
-        * FIXME: Associated pool should be made read-only on failure.
-        */
        int r;
        size_t metadata_len, data_len;
        struct thin_disk_superblock *disk_super;
@@ -597,31 +751,27 @@ static int __commit_transaction(struct dm_pool_metadata *pmd)
 
        r = __write_changed_details(pmd);
        if (r < 0)
-               goto out;
-
-       if (!pmd->need_commit)
-               goto out;
+               return r;
 
        r = dm_sm_commit(pmd->data_sm);
        if (r < 0)
-               goto out;
+               return r;
 
        r = dm_tm_pre_commit(pmd->tm);
        if (r < 0)
-               goto out;
+               return r;
 
        r = dm_sm_root_size(pmd->metadata_sm, &metadata_len);
        if (r < 0)
-               goto out;
+               return r;
 
        r = dm_sm_root_size(pmd->data_sm, &data_len);
        if (r < 0)
-               goto out;
+               return r;
 
-       r = dm_bm_write_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION,
-                            &sb_validator, &sblock);
+       r = superblock_lock(pmd, &sblock);
        if (r)
-               goto out;
+               return r;
 
        disk_super = dm_block_data(sblock);
        disk_super->time = cpu_to_le32(pmd->time);
@@ -640,12 +790,7 @@ static int __commit_transaction(struct dm_pool_metadata *pmd)
        if (r < 0)
                goto out_locked;
 
-       r = dm_tm_commit(pmd->tm, sblock);
-       if (!r)
-               pmd->need_commit = 0;
-
-out:
-       return r;
+       return dm_tm_commit(pmd->tm, sblock);
 
 out_locked:
        dm_bm_unlock(sblock);
@@ -653,15 +798,11 @@ out_locked:
 }
 
 struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
-                                              sector_t data_block_size)
+                                              sector_t data_block_size,
+                                              bool format_device)
 {
        int r;
-       struct thin_disk_superblock *disk_super;
        struct dm_pool_metadata *pmd;
-       sector_t bdev_size = i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
-       struct dm_block_manager *bm;
-       int create;
-       struct dm_block *sblock;
 
        pmd = kmalloc(sizeof(*pmd), GFP_KERNEL);
        if (!pmd) {
@@ -669,90 +810,28 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
                return ERR_PTR(-ENOMEM);
        }
 
-       /*
-        * Max hex locks:
-        *  3 for btree insert +
-        *  2 for btree lookup used within space map
-        */
-       bm = dm_block_manager_create(bdev, THIN_METADATA_BLOCK_SIZE,
-                                    THIN_METADATA_CACHE_SIZE, 5);
-       if (!bm) {
-               DMERR("could not create block manager");
-               kfree(pmd);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       r = superblock_all_zeroes(bm, &create);
-       if (r) {
-               dm_block_manager_destroy(bm);
-               kfree(pmd);
-               return ERR_PTR(r);
-       }
-
+       init_rwsem(&pmd->root_lock);
+       pmd->time = 0;
+       INIT_LIST_HEAD(&pmd->thin_devices);
+       pmd->read_only = false;
+       pmd->fail_io = false;
+       pmd->bdev = bdev;
+       pmd->data_block_size = data_block_size;
 
-       r = init_pmd(pmd, bm, 0, create);
+       r = __create_persistent_data_objects(pmd, format_device);
        if (r) {
-               dm_block_manager_destroy(bm);
                kfree(pmd);
                return ERR_PTR(r);
        }
-       pmd->bdev = bdev;
-
-       if (!create) {
-               r = __begin_transaction(pmd);
-               if (r < 0)
-                       goto bad;
-               return pmd;
-       }
-
-       /*
-        * Create.
-        */
-       r = dm_bm_write_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION,
-                            &sb_validator, &sblock);
-       if (r)
-               goto bad;
-
-       if (bdev_size > THIN_METADATA_MAX_SECTORS)
-               bdev_size = THIN_METADATA_MAX_SECTORS;
-
-       disk_super = dm_block_data(sblock);
-       disk_super->magic = cpu_to_le64(THIN_SUPERBLOCK_MAGIC);
-       disk_super->version = cpu_to_le32(THIN_VERSION);
-       disk_super->time = 0;
-       disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT);
-       disk_super->metadata_nr_blocks = cpu_to_le64(bdev_size >> SECTOR_TO_BLOCK_SHIFT);
-       disk_super->data_block_size = cpu_to_le32(data_block_size);
-
-       r = dm_bm_unlock(sblock);
-       if (r < 0)
-               goto bad;
-
-       r = dm_btree_empty(&pmd->info, &pmd->root);
-       if (r < 0)
-               goto bad;
-
-       r = dm_btree_empty(&pmd->details_info, &pmd->details_root);
-       if (r < 0) {
-               DMERR("couldn't create devices root");
-               goto bad;
-       }
 
-       pmd->flags = 0;
-       pmd->need_commit = 1;
-       r = dm_pool_commit_metadata(pmd);
+       r = __begin_transaction(pmd);
        if (r < 0) {
-               DMERR("%s: dm_pool_commit_metadata() failed, error = %d",
-                     __func__, r);
-               goto bad;
+               if (dm_pool_metadata_close(pmd) < 0)
+                       DMWARN("%s: dm_pool_metadata_close() failed.", __func__);
+               return ERR_PTR(r);
        }
 
        return pmd;
-
-bad:
-       if (dm_pool_metadata_close(pmd) < 0)
-               DMWARN("%s: dm_pool_metadata_close() failed.", __func__);
-       return ERR_PTR(r);
 }
 
 int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
@@ -778,18 +857,17 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
                return -EBUSY;
        }
 
-       r = __commit_transaction(pmd);
-       if (r < 0)
-               DMWARN("%s: __commit_transaction() failed, error = %d",
-                      __func__, r);
+       if (!pmd->read_only && !pmd->fail_io) {
+               r = __commit_transaction(pmd);
+               if (r < 0)
+                       DMWARN("%s: __commit_transaction() failed, error = %d",
+                              __func__, r);
+       }
 
-       dm_tm_destroy(pmd->tm);
-       dm_tm_destroy(pmd->nb_tm);
-       dm_block_manager_destroy(pmd->bm);
-       dm_sm_destroy(pmd->metadata_sm);
-       dm_sm_destroy(pmd->data_sm);
-       kfree(pmd);
+       if (!pmd->fail_io)
+               __destroy_persistent_data_objects(pmd);
 
+       kfree(pmd);
        return 0;
 }
 
@@ -850,6 +928,7 @@ static int __open_device(struct dm_pool_metadata *pmd,
        (*td)->id = dev;
        (*td)->open_count = 1;
        (*td)->changed = changed;
+       (*td)->aborted_with_changes = false;
        (*td)->mapped_blocks = le64_to_cpu(details_le.mapped_blocks);
        (*td)->transaction_id = le64_to_cpu(details_le.transaction_id);
        (*td)->creation_time = le32_to_cpu(details_le.creation_time);
@@ -911,10 +990,11 @@ static int __create_thin(struct dm_pool_metadata *pmd,
 
 int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_thin_id dev)
 {
-       int r;
+       int r = -EINVAL;
 
        down_write(&pmd->root_lock);
-       r = __create_thin(pmd, dev);
+       if (!pmd->fail_io)
+               r = __create_thin(pmd, dev);
        up_write(&pmd->root_lock);
 
        return r;
@@ -1001,10 +1081,11 @@ int dm_pool_create_snap(struct dm_pool_metadata *pmd,
                                 dm_thin_id dev,
                                 dm_thin_id origin)
 {
-       int r;
+       int r = -EINVAL;
 
        down_write(&pmd->root_lock);
-       r = __create_snap(pmd, dev, origin);
+       if (!pmd->fail_io)
+               r = __create_snap(pmd, dev, origin);
        up_write(&pmd->root_lock);
 
        return r;
@@ -1037,18 +1118,17 @@ static int __delete_device(struct dm_pool_metadata *pmd, dm_thin_id dev)
        if (r)
                return r;
 
-       pmd->need_commit = 1;
-
        return 0;
 }
 
 int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd,
                               dm_thin_id dev)
 {
-       int r;
+       int r = -EINVAL;
 
        down_write(&pmd->root_lock);
-       r = __delete_device(pmd, dev);
+       if (!pmd->fail_io)
+               r = __delete_device(pmd, dev);
        up_write(&pmd->root_lock);
 
        return r;
@@ -1058,28 +1138,40 @@ int dm_pool_set_metadata_transaction_id(struct dm_pool_metadata *pmd,
                                        uint64_t current_id,
                                        uint64_t new_id)
 {
+       int r = -EINVAL;
+
        down_write(&pmd->root_lock);
+
+       if (pmd->fail_io)
+               goto out;
+
        if (pmd->trans_id != current_id) {
-               up_write(&pmd->root_lock);
                DMERR("mismatched transaction id");
-               return -EINVAL;
+               goto out;
        }
 
        pmd->trans_id = new_id;
-       pmd->need_commit = 1;
+       r = 0;
+
+out:
        up_write(&pmd->root_lock);
 
-       return 0;
+       return r;
 }
 
 int dm_pool_get_metadata_transaction_id(struct dm_pool_metadata *pmd,
                                        uint64_t *result)
 {
+       int r = -EINVAL;
+
        down_read(&pmd->root_lock);
-       *result = pmd->trans_id;
+       if (!pmd->fail_io) {
+               *result = pmd->trans_id;
+               r = 0;
+       }
        up_read(&pmd->root_lock);
 
-       return 0;
+       return r;
 }
 
 static int __reserve_metadata_snap(struct dm_pool_metadata *pmd)
@@ -1108,8 +1200,6 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd)
 
                dm_tm_dec(pmd->tm, held_root);
                dm_tm_unlock(pmd->tm, copy);
-               pmd->need_commit = 1;
-
                return -EBUSY;
        }
 
@@ -1131,29 +1221,25 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd)
        /*
         * Write the held root into the superblock.
         */
-       r = dm_bm_write_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION,
-                            &sb_validator, &sblock);
+       r = superblock_lock(pmd, &sblock);
        if (r) {
                dm_tm_dec(pmd->tm, held_root);
-               pmd->need_commit = 1;
                return r;
        }
 
        disk_super = dm_block_data(sblock);
        disk_super->held_root = cpu_to_le64(held_root);
        dm_bm_unlock(sblock);
-
-       pmd->need_commit = 1;
-
        return 0;
 }
 
 int dm_pool_reserve_metadata_snap(struct dm_pool_metadata *pmd)
 {
-       int r;
+       int r = -EINVAL;
 
        down_write(&pmd->root_lock);
-       r = __reserve_metadata_snap(pmd);
+       if (!pmd->fail_io)
+               r = __reserve_metadata_snap(pmd);
        up_write(&pmd->root_lock);
 
        return r;
@@ -1166,15 +1252,13 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd)
        struct dm_block *sblock, *copy;
        dm_block_t held_root;
 
-       r = dm_bm_write_lock(pmd->bm, THIN_SUPERBLOCK_LOCATION,
-                            &sb_validator, &sblock);
+       r = superblock_lock(pmd, &sblock);
        if (r)
                return r;
 
        disk_super = dm_block_data(sblock);
        held_root = le64_to_cpu(disk_super->held_root);
        disk_super->held_root = cpu_to_le64(0);
-       pmd->need_commit = 1;
 
        dm_bm_unlock(sblock);
 
@@ -1197,10 +1281,11 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd)
 
 int dm_pool_release_metadata_snap(struct dm_pool_metadata *pmd)
 {
-       int r;
+       int r = -EINVAL;
 
        down_write(&pmd->root_lock);
-       r = __release_metadata_snap(pmd);
+       if (!pmd->fail_io)
+               r = __release_metadata_snap(pmd);
        up_write(&pmd->root_lock);
 
        return r;
@@ -1227,10 +1312,11 @@ static int __get_metadata_snap(struct dm_pool_metadata *pmd,
 int dm_pool_get_metadata_snap(struct dm_pool_metadata *pmd,
                              dm_block_t *result)
 {
-       int r;
+       int r = -EINVAL;
 
        down_read(&pmd->root_lock);
-       r = __get_metadata_snap(pmd, result);
+       if (!pmd->fail_io)
+               r = __get_metadata_snap(pmd, result);
        up_read(&pmd->root_lock);
 
        return r;
@@ -1239,10 +1325,11 @@ int dm_pool_get_metadata_snap(struct dm_pool_metadata *pmd,
 int dm_pool_open_thin_device(struct dm_pool_metadata *pmd, dm_thin_id dev,
                             struct dm_thin_device **td)
 {
-       int r;
+       int r = -EINVAL;
 
        down_write(&pmd->root_lock);
-       r = __open_device(pmd, dev, 0, td);
+       if (!pmd->fail_io)
+               r = __open_device(pmd, dev, 0, td);
        up_write(&pmd->root_lock);
 
        return r;
@@ -1262,7 +1349,7 @@ dm_thin_id dm_thin_dev_id(struct dm_thin_device *td)
        return td->id;
 }
 
-static int __snapshotted_since(struct dm_thin_device *td, uint32_t time)
+static bool __snapshotted_since(struct dm_thin_device *td, uint32_t time)
 {
        return td->snapshotted_time > time;
 }
@@ -1270,28 +1357,31 @@ static int __snapshotted_since(struct dm_thin_device *td, uint32_t time)
 int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
                       int can_block, struct dm_thin_lookup_result *result)
 {
-       int r;
+       int r = -EINVAL;
        uint64_t block_time = 0;
        __le64 value;
        struct dm_pool_metadata *pmd = td->pmd;
        dm_block_t keys[2] = { td->id, block };
+       struct dm_btree_info *info;
 
        if (can_block) {
                down_read(&pmd->root_lock);
-               r = dm_btree_lookup(&pmd->info, pmd->root, keys, &value);
-               if (!r)
-                       block_time = le64_to_cpu(value);
-               up_read(&pmd->root_lock);
-
-       } else if (down_read_trylock(&pmd->root_lock)) {
-               r = dm_btree_lookup(&pmd->nb_info, pmd->root, keys, &value);
-               if (!r)
-                       block_time = le64_to_cpu(value);
-               up_read(&pmd->root_lock);
-
-       } else
+               info = &pmd->info;
+       } else if (down_read_trylock(&pmd->root_lock))
+               info = &pmd->nb_info;
+       else
                return -EWOULDBLOCK;
 
+       if (pmd->fail_io)
+               goto out;
+
+       r = dm_btree_lookup(info, pmd->root, keys, &value);
+       if (!r)
+               block_time = le64_to_cpu(value);
+
+out:
+       up_read(&pmd->root_lock);
+
        if (!r) {
                dm_block_t exception_block;
                uint32_t exception_time;
@@ -1312,7 +1402,6 @@ static int __insert(struct dm_thin_device *td, dm_block_t block,
        struct dm_pool_metadata *pmd = td->pmd;
        dm_block_t keys[2] = { td->id, block };
 
-       pmd->need_commit = 1;
        value = cpu_to_le64(pack_block_time(data_block, pmd->time));
        __dm_bless_for_disk(&value);
 
@@ -1321,10 +1410,9 @@ static int __insert(struct dm_thin_device *td, dm_block_t block,
        if (r)
                return r;
 
-       if (inserted) {
+       td->changed = 1;
+       if (inserted)
                td->mapped_blocks++;
-               td->changed = 1;
-       }
 
        return 0;
 }
@@ -1332,10 +1420,11 @@ static int __insert(struct dm_thin_device *td, dm_block_t block,
 int dm_thin_insert_block(struct dm_thin_device *td, dm_block_t block,
                         dm_block_t data_block)
 {
-       int r;
+       int r = -EINVAL;
 
        down_write(&td->pmd->root_lock);
-       r = __insert(td, block, data_block);
+       if (!td->pmd->fail_io)
+               r = __insert(td, block, data_block);
        up_write(&td->pmd->root_lock);
 
        return r;
@@ -1353,31 +1442,51 @@ static int __remove(struct dm_thin_device *td, dm_block_t block)
 
        td->mapped_blocks--;
        td->changed = 1;
-       pmd->need_commit = 1;
 
        return 0;
 }
 
 int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block)
 {
-       int r;
+       int r = -EINVAL;
 
        down_write(&td->pmd->root_lock);
-       r = __remove(td, block);
+       if (!td->pmd->fail_io)
+               r = __remove(td, block);
        up_write(&td->pmd->root_lock);
 
        return r;
 }
 
-int dm_pool_alloc_data_block(struct dm_pool_metadata *pmd, dm_block_t *result)
+bool dm_thin_changed_this_transaction(struct dm_thin_device *td)
 {
        int r;
 
-       down_write(&pmd->root_lock);
+       down_read(&td->pmd->root_lock);
+       r = td->changed;
+       up_read(&td->pmd->root_lock);
 
-       r = dm_sm_new_block(pmd->data_sm, result);
-       pmd->need_commit = 1;
+       return r;
+}
+
+bool dm_thin_aborted_changes(struct dm_thin_device *td)
+{
+       bool r;
 
+       down_read(&td->pmd->root_lock);
+       r = td->aborted_with_changes;
+       up_read(&td->pmd->root_lock);
+
+       return r;
+}
+
+int dm_pool_alloc_data_block(struct dm_pool_metadata *pmd, dm_block_t *result)
+{
+       int r = -EINVAL;
+
+       down_write(&pmd->root_lock);
+       if (!pmd->fail_io)
+               r = dm_sm_new_block(pmd->data_sm, result);
        up_write(&pmd->root_lock);
 
        return r;
@@ -1385,9 +1494,11 @@ int dm_pool_alloc_data_block(struct dm_pool_metadata *pmd, dm_block_t *result)
 
 int dm_pool_commit_metadata(struct dm_pool_metadata *pmd)
 {
-       int r;
+       int r = -EINVAL;
 
        down_write(&pmd->root_lock);
+       if (pmd->fail_io)
+               goto out;
 
        r = __commit_transaction(pmd);
        if (r <= 0)
@@ -1402,12 +1513,41 @@ out:
        return r;
 }
 
+static void __set_abort_with_changes_flags(struct dm_pool_metadata *pmd)
+{
+       struct dm_thin_device *td;
+
+       list_for_each_entry(td, &pmd->thin_devices, list)
+               td->aborted_with_changes = td->changed;
+}
+
+int dm_pool_abort_metadata(struct dm_pool_metadata *pmd)
+{
+       int r = -EINVAL;
+
+       down_write(&pmd->root_lock);
+       if (pmd->fail_io)
+               goto out;
+
+       __set_abort_with_changes_flags(pmd);
+       __destroy_persistent_data_objects(pmd);
+       r = __create_persistent_data_objects(pmd, false);
+       if (r)
+               pmd->fail_io = true;
+
+out:
+       up_write(&pmd->root_lock);
+
+       return r;
+}
+
 int dm_pool_get_free_block_count(struct dm_pool_metadata *pmd, dm_block_t *result)
 {
-       int r;
+       int r = -EINVAL;
 
        down_read(&pmd->root_lock);
-       r = dm_sm_get_nr_free(pmd->data_sm, result);
+       if (!pmd->fail_io)
+               r = dm_sm_get_nr_free(pmd->data_sm, result);
        up_read(&pmd->root_lock);
 
        return r;
@@ -1416,10 +1556,11 @@ int dm_pool_get_free_block_count(struct dm_pool_metadata *pmd, dm_block_t *resul
 int dm_pool_get_free_metadata_block_count(struct dm_pool_metadata *pmd,
                                          dm_block_t *result)
 {
-       int r;
+       int r = -EINVAL;
 
        down_read(&pmd->root_lock);
-       r = dm_sm_get_nr_free(pmd->metadata_sm, result);
+       if (!pmd->fail_io)
+               r = dm_sm_get_nr_free(pmd->metadata_sm, result);
        up_read(&pmd->root_lock);
 
        return r;
@@ -1428,10 +1569,11 @@ int dm_pool_get_free_metadata_block_count(struct dm_pool_metadata *pmd,
 int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd,
                                  dm_block_t *result)
 {
-       int r;
+       int r = -EINVAL;
 
        down_read(&pmd->root_lock);
-       r = dm_sm_get_nr_blocks(pmd->metadata_sm, result);
+       if (!pmd->fail_io)
+               r = dm_sm_get_nr_blocks(pmd->metadata_sm, result);
        up_read(&pmd->root_lock);
 
        return r;
@@ -1448,10 +1590,11 @@ int dm_pool_get_data_block_size(struct dm_pool_metadata *pmd, sector_t *result)
 
 int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result)
 {
-       int r;
+       int r = -EINVAL;
 
        down_read(&pmd->root_lock);
-       r = dm_sm_get_nr_blocks(pmd->data_sm, result);
+       if (!pmd->fail_io)
+               r = dm_sm_get_nr_blocks(pmd->data_sm, result);
        up_read(&pmd->root_lock);
 
        return r;
@@ -1459,13 +1602,17 @@ int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result)
 
 int dm_thin_get_mapped_count(struct dm_thin_device *td, dm_block_t *result)
 {
+       int r = -EINVAL;
        struct dm_pool_metadata *pmd = td->pmd;
 
        down_read(&pmd->root_lock);
-       *result = td->mapped_blocks;
+       if (!pmd->fail_io) {
+               *result = td->mapped_blocks;
+               r = 0;
+       }
        up_read(&pmd->root_lock);
 
-       return 0;
+       return r;
 }
 
 static int __highest_block(struct dm_thin_device *td, dm_block_t *result)
@@ -1487,11 +1634,12 @@ static int __highest_block(struct dm_thin_device *td, dm_block_t *result)
 int dm_thin_get_highest_mapped_block(struct dm_thin_device *td,
                                     dm_block_t *result)
 {
-       int r;
+       int r = -EINVAL;
        struct dm_pool_metadata *pmd = td->pmd;
 
        down_read(&pmd->root_lock);
-       r = __highest_block(td, result);
+       if (!pmd->fail_io)
+               r = __highest_block(td, result);
        up_read(&pmd->root_lock);
 
        return r;
@@ -1514,20 +1662,25 @@ static int __resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_count)
                return -EINVAL;
        }
 
-       r = dm_sm_extend(pmd->data_sm, new_count - old_count);
-       if (!r)
-               pmd->need_commit = 1;
-
-       return r;
+       return dm_sm_extend(pmd->data_sm, new_count - old_count);
 }
 
 int dm_pool_resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_count)
 {
-       int r;
+       int r = -EINVAL;
 
        down_write(&pmd->root_lock);
-       r = __resize_data_dev(pmd, new_count);
+       if (!pmd->fail_io)
+               r = __resize_data_dev(pmd, new_count);
        up_write(&pmd->root_lock);
 
        return r;
 }
+
+void dm_pool_metadata_read_only(struct dm_pool_metadata *pmd)
+{
+       down_write(&pmd->root_lock);
+       pmd->read_only = true;
+       dm_bm_set_read_only(pmd->bm);
+       up_write(&pmd->root_lock);
+}
index b88918ccdaf688e3bc5f10478023276893cc3521..0cecc3702885fb57452c013f83679fc437a393ca 100644 (file)
@@ -38,7 +38,8 @@ typedef uint64_t dm_thin_id;
  * Reopens or creates a new, empty metadata volume.
  */
 struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
-                                              sector_t data_block_size);
+                                              sector_t data_block_size,
+                                              bool format_device);
 
 int dm_pool_metadata_close(struct dm_pool_metadata *pmd);
 
@@ -78,6 +79,16 @@ int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd,
  */
 int dm_pool_commit_metadata(struct dm_pool_metadata *pmd);
 
+/*
+ * Discards all uncommitted changes.  Rereads the superblock, rolling back
+ * to the last good transaction.  Thin devices remain open.
+ * dm_thin_aborted_changes() tells you if they had uncommitted changes.
+ *
+ * If this call fails it's only useful to call dm_pool_metadata_close().
+ * All other methods will fail with -EINVAL.
+ */
+int dm_pool_abort_metadata(struct dm_pool_metadata *pmd);
+
 /*
  * Set/get userspace transaction id.
  */
@@ -119,7 +130,7 @@ dm_thin_id dm_thin_dev_id(struct dm_thin_device *td);
 
 struct dm_thin_lookup_result {
        dm_block_t block;
-       int shared;
+       unsigned shared:1;
 };
 
 /*
@@ -147,6 +158,10 @@ int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block);
 /*
  * Queries.
  */
+bool dm_thin_changed_this_transaction(struct dm_thin_device *td);
+
+bool dm_thin_aborted_changes(struct dm_thin_device *td);
+
 int dm_thin_get_highest_mapped_block(struct dm_thin_device *td,
                                     dm_block_t *highest_mapped);
 
@@ -171,6 +186,12 @@ int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result);
  */
 int dm_pool_resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_size);
 
+/*
+ * Flicks the underlying block manager into read only mode, so you know
+ * that nothing is changing.
+ */
+void dm_pool_metadata_read_only(struct dm_pool_metadata *pmd);
+
 /*----------------------------------------------------------------*/
 
 #endif
index 68694da0d21d0566a61649339cb3a4f3a3bbc943..af1fc3b2c2adbb365e247a2d45c1f7a94de9b6dd 100644 (file)
@@ -1,10 +1,11 @@
 /*
- * Copyright (C) 2011 Red Hat UK.
+ * Copyright (C) 2011-2012 Red Hat UK.
  *
  * This file is released under the GPL.
  */
 
 #include "dm-thin-metadata.h"
+#include "dm.h"
 
 #include <linux/device-mapper.h>
 #include <linux/dm-io.h>
@@ -19,7 +20,7 @@
 /*
  * Tunable constants
  */
-#define ENDIO_HOOK_POOL_SIZE 10240
+#define ENDIO_HOOK_POOL_SIZE 1024
 #define DEFERRED_SET_SIZE 64
 #define MAPPING_POOL_SIZE 1024
 #define PRISON_CELLS 1024
@@ -496,12 +497,27 @@ static void build_virtual_key(struct dm_thin_device *td, dm_block_t b,
  */
 struct dm_thin_new_mapping;
 
+/*
+ * The pool runs in 3 modes.  Ordered in degraded order for comparisons.
+ */
+enum pool_mode {
+       PM_WRITE,               /* metadata may be changed */
+       PM_READ_ONLY,           /* metadata may not be changed */
+       PM_FAIL,                /* all I/O fails */
+};
+
 struct pool_features {
+       enum pool_mode mode;
+
        unsigned zero_new_blocks:1;
        unsigned discard_enabled:1;
        unsigned discard_passdown:1;
 };
 
+struct thin_c;
+typedef void (*process_bio_fn)(struct thin_c *tc, struct bio *bio);
+typedef void (*process_mapping_fn)(struct dm_thin_new_mapping *m);
+
 struct pool {
        struct list_head list;
        struct dm_target *ti;   /* Only set if a pool target is bound */
@@ -510,10 +526,9 @@ struct pool {
        struct block_device *md_dev;
        struct dm_pool_metadata *pmd;
 
-       uint32_t sectors_per_block;
-       unsigned block_shift;
-       dm_block_t offset_mask;
        dm_block_t low_water_blocks;
+       uint32_t sectors_per_block;
+       int sectors_per_block_shift;
 
        struct pool_features pf;
        unsigned low_water_triggered:1; /* A dm event has been sent */
@@ -526,8 +541,8 @@ struct pool {
        struct work_struct worker;
        struct delayed_work waker;
 
-       unsigned ref_count;
        unsigned long last_commit_jiffies;
+       unsigned ref_count;
 
        spinlock_t lock;
        struct bio_list deferred_bios;
@@ -543,8 +558,17 @@ struct pool {
        struct dm_thin_new_mapping *next_mapping;
        mempool_t *mapping_pool;
        mempool_t *endio_hook_pool;
+
+       process_bio_fn process_bio;
+       process_bio_fn process_discard;
+
+       process_mapping_fn process_prepared_mapping;
+       process_mapping_fn process_prepared_discard;
 };
 
+static enum pool_mode get_pool_mode(struct pool *pool);
+static void set_pool_mode(struct pool *pool, enum pool_mode mode);
+
 /*
  * Target context for a pool.
  */
@@ -679,16 +703,28 @@ static void requeue_io(struct thin_c *tc)
 
 static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio)
 {
-       return bio->bi_sector >> tc->pool->block_shift;
+       sector_t block_nr = bio->bi_sector;
+
+       if (tc->pool->sectors_per_block_shift < 0)
+               (void) sector_div(block_nr, tc->pool->sectors_per_block);
+       else
+               block_nr >>= tc->pool->sectors_per_block_shift;
+
+       return block_nr;
 }
 
 static void remap(struct thin_c *tc, struct bio *bio, dm_block_t block)
 {
        struct pool *pool = tc->pool;
+       sector_t bi_sector = bio->bi_sector;
 
        bio->bi_bdev = tc->pool_dev->bdev;
-       bio->bi_sector = (block << pool->block_shift) +
-               (bio->bi_sector & pool->offset_mask);
+       if (tc->pool->sectors_per_block_shift < 0)
+               bio->bi_sector = (block * pool->sectors_per_block) +
+                                sector_div(bi_sector, pool->sectors_per_block);
+       else
+               bio->bi_sector = (block << pool->sectors_per_block_shift) |
+                               (bi_sector & (pool->sectors_per_block - 1));
 }
 
 static void remap_to_origin(struct thin_c *tc, struct bio *bio)
@@ -696,21 +732,39 @@ static void remap_to_origin(struct thin_c *tc, struct bio *bio)
        bio->bi_bdev = tc->origin_dev->bdev;
 }
 
+static int bio_triggers_commit(struct thin_c *tc, struct bio *bio)
+{
+       return (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) &&
+               dm_thin_changed_this_transaction(tc->td);
+}
+
 static void issue(struct thin_c *tc, struct bio *bio)
 {
        struct pool *pool = tc->pool;
        unsigned long flags;
 
+       if (!bio_triggers_commit(tc, bio)) {
+               generic_make_request(bio);
+               return;
+       }
+
        /*
-        * Batch together any FUA/FLUSH bios we find and then issue
-        * a single commit for them in process_deferred_bios().
+        * Complete bio with an error if earlier I/O caused changes to
+        * the metadata that can't be committed e.g, due to I/O errors
+        * on the metadata device.
         */
-       if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) {
-               spin_lock_irqsave(&pool->lock, flags);
-               bio_list_add(&pool->deferred_flush_bios, bio);
-               spin_unlock_irqrestore(&pool->lock, flags);
-       } else
-               generic_make_request(bio);
+       if (dm_thin_aborted_changes(tc->td)) {
+               bio_io_error(bio);
+               return;
+       }
+
+       /*
+        * Batch together any bios that trigger commits and then issue a
+        * single commit for them in process_deferred_bios().
+        */
+       spin_lock_irqsave(&pool->lock, flags);
+       bio_list_add(&pool->deferred_flush_bios, bio);
+       spin_unlock_irqrestore(&pool->lock, flags);
 }
 
 static void remap_to_origin_and_issue(struct thin_c *tc, struct bio *bio)
@@ -847,6 +901,14 @@ static void cell_defer_except(struct thin_c *tc, struct dm_bio_prison_cell *cell
        wake_worker(pool);
 }
 
+static void process_prepared_mapping_fail(struct dm_thin_new_mapping *m)
+{
+       if (m->bio)
+               m->bio->bi_end_io = m->saved_bi_end_io;
+       cell_error(m->cell);
+       list_del(&m->list);
+       mempool_free(m, m->tc->pool->mapping_pool);
+}
 static void process_prepared_mapping(struct dm_thin_new_mapping *m)
 {
        struct thin_c *tc = m->tc;
@@ -859,7 +921,7 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
 
        if (m->err) {
                cell_error(m->cell);
-               return;
+               goto out;
        }
 
        /*
@@ -871,7 +933,7 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
        if (r) {
                DMERR("dm_thin_insert_block() failed");
                cell_error(m->cell);
-               return;
+               goto out;
        }
 
        /*
@@ -886,22 +948,25 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
        } else
                cell_defer(tc, m->cell, m->data_block);
 
+out:
        list_del(&m->list);
        mempool_free(m, tc->pool->mapping_pool);
 }
 
-static void process_prepared_discard(struct dm_thin_new_mapping *m)
+static void process_prepared_discard_fail(struct dm_thin_new_mapping *m)
 {
-       int r;
        struct thin_c *tc = m->tc;
 
-       r = dm_thin_remove_block(tc->td, m->virt_block);
-       if (r)
-               DMERR("dm_thin_remove_block() failed");
+       bio_io_error(m->bio);
+       cell_defer_except(tc, m->cell);
+       cell_defer_except(tc, m->cell2);
+       mempool_free(m, tc->pool->mapping_pool);
+}
+
+static void process_prepared_discard_passdown(struct dm_thin_new_mapping *m)
+{
+       struct thin_c *tc = m->tc;
 
-       /*
-        * Pass the discard down to the underlying device?
-        */
        if (m->pass_discard)
                remap_and_issue(tc, m->bio, m->data_block);
        else
@@ -912,8 +977,20 @@ static void process_prepared_discard(struct dm_thin_new_mapping *m)
        mempool_free(m, tc->pool->mapping_pool);
 }
 
+static void process_prepared_discard(struct dm_thin_new_mapping *m)
+{
+       int r;
+       struct thin_c *tc = m->tc;
+
+       r = dm_thin_remove_block(tc->td, m->virt_block);
+       if (r)
+               DMERR("dm_thin_remove_block() failed");
+
+       process_prepared_discard_passdown(m);
+}
+
 static void process_prepared(struct pool *pool, struct list_head *head,
-                            void (*fn)(struct dm_thin_new_mapping *))
+                            process_mapping_fn *fn)
 {
        unsigned long flags;
        struct list_head maps;
@@ -925,7 +1002,7 @@ static void process_prepared(struct pool *pool, struct list_head *head,
        spin_unlock_irqrestore(&pool->lock, flags);
 
        list_for_each_entry_safe(m, tmp, &maps, list)
-               fn(m);
+               (*fn)(m);
 }
 
 /*
@@ -933,9 +1010,7 @@ static void process_prepared(struct pool *pool, struct list_head *head,
  */
 static int io_overlaps_block(struct pool *pool, struct bio *bio)
 {
-       return !(bio->bi_sector & pool->offset_mask) &&
-               (bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT));
-
+       return bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT);
 }
 
 static int io_overwrites_block(struct pool *pool, struct bio *bio)
@@ -1093,6 +1168,35 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
        }
 }
 
+static int commit(struct pool *pool)
+{
+       int r;
+
+       r = dm_pool_commit_metadata(pool->pmd);
+       if (r)
+               DMERR("commit failed, error = %d", r);
+
+       return r;
+}
+
+/*
+ * A non-zero return indicates read_only or fail_io mode.
+ * Many callers don't care about the return value.
+ */
+static int commit_or_fallback(struct pool *pool)
+{
+       int r;
+
+       if (get_pool_mode(pool) != PM_WRITE)
+               return -EINVAL;
+
+       r = commit(pool);
+       if (r)
+               set_pool_mode(pool, PM_READ_ONLY);
+
+       return r;
+}
+
 static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
 {
        int r;
@@ -1121,12 +1225,7 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
                         * Try to commit to see if that will free up some
                         * more space.
                         */
-                       r = dm_pool_commit_metadata(pool->pmd);
-                       if (r) {
-                               DMERR("%s: dm_pool_commit_metadata() failed, error = %d",
-                                     __func__, r);
-                               return r;
-                       }
+                       (void) commit_or_fallback(pool);
 
                        r = dm_pool_get_free_block_count(pool->pmd, &free_blocks);
                        if (r)
@@ -1218,7 +1317,7 @@ static void process_discard(struct thin_c *tc, struct bio *bio)
                         */
                        m = get_next_mapping(pool);
                        m->tc = tc;
-                       m->pass_discard = (!lookup_result.shared) & pool->pf.discard_passdown;
+                       m->pass_discard = (!lookup_result.shared) && pool->pf.discard_passdown;
                        m->virt_block = block;
                        m->data_block = lookup_result.block;
                        m->cell = cell;
@@ -1234,15 +1333,10 @@ static void process_discard(struct thin_c *tc, struct bio *bio)
                        }
                } else {
                        /*
-                        * This path is hit if people are ignoring
-                        * limits->discard_granularity.  It ignores any
-                        * part of the discard that is in a subsequent
-                        * block.
+                        * The DM core makes sure that the discard doesn't span
+                        * a block boundary.  So we submit the discard of a
+                        * partial block appropriately.
                         */
-                       sector_t offset = bio->bi_sector - (block << pool->block_shift);
-                       unsigned remaining = (pool->sectors_per_block - offset) << 9;
-                       bio->bi_size = min(bio->bi_size, remaining);
-
                        cell_release_singleton(cell, bio);
                        cell_release_singleton(cell2, bio);
                        if ((!lookup_result.shared) && pool->pf.discard_passdown)
@@ -1310,7 +1404,7 @@ static void process_shared_bio(struct thin_c *tc, struct bio *bio,
        if (bio_detain(pool->prison, &key, bio, &cell))
                return;
 
-       if (bio_data_dir(bio) == WRITE)
+       if (bio_data_dir(bio) == WRITE && bio->bi_size)
                break_sharing(tc, bio, block, &key, lookup_result, cell);
        else {
                struct dm_thin_endio_hook *h = dm_get_mapinfo(bio)->ptr;
@@ -1362,6 +1456,7 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
 
        default:
                DMERR("%s: alloc_data_block() failed, error = %d", __func__, r);
+               set_pool_mode(tc->pool, PM_READ_ONLY);
                cell_error(cell);
                break;
        }
@@ -1419,6 +1514,49 @@ static void process_bio(struct thin_c *tc, struct bio *bio)
        }
 }
 
+static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
+{
+       int r;
+       int rw = bio_data_dir(bio);
+       dm_block_t block = get_bio_block(tc, bio);
+       struct dm_thin_lookup_result lookup_result;
+
+       r = dm_thin_find_block(tc->td, block, 1, &lookup_result);
+       switch (r) {
+       case 0:
+               if (lookup_result.shared && (rw == WRITE) && bio->bi_size)
+                       bio_io_error(bio);
+               else
+                       remap_and_issue(tc, bio, lookup_result.block);
+               break;
+
+       case -ENODATA:
+               if (rw != READ) {
+                       bio_io_error(bio);
+                       break;
+               }
+
+               if (tc->origin_dev) {
+                       remap_to_origin_and_issue(tc, bio);
+                       break;
+               }
+
+               zero_fill_bio(bio);
+               bio_endio(bio, 0);
+               break;
+
+       default:
+               DMERR("dm_thin_find_block() failed, error = %d", r);
+               bio_io_error(bio);
+               break;
+       }
+}
+
+static void process_bio_fail(struct thin_c *tc, struct bio *bio)
+{
+       bio_io_error(bio);
+}
+
 static int need_commit_due_to_time(struct pool *pool)
 {
        return jiffies < pool->last_commit_jiffies ||
@@ -1430,7 +1568,6 @@ static void process_deferred_bios(struct pool *pool)
        unsigned long flags;
        struct bio *bio;
        struct bio_list bios;
-       int r;
 
        bio_list_init(&bios);
 
@@ -1457,9 +1594,9 @@ static void process_deferred_bios(struct pool *pool)
                }
 
                if (bio->bi_rw & REQ_DISCARD)
-                       process_discard(tc, bio);
+                       pool->process_discard(tc, bio);
                else
-                       process_bio(tc, bio);
+                       pool->process_bio(tc, bio);
        }
 
        /*
@@ -1475,10 +1612,7 @@ static void process_deferred_bios(struct pool *pool)
        if (bio_list_empty(&bios) && !need_commit_due_to_time(pool))
                return;
 
-       r = dm_pool_commit_metadata(pool->pmd);
-       if (r) {
-               DMERR("%s: dm_pool_commit_metadata() failed, error = %d",
-                     __func__, r);
+       if (commit_or_fallback(pool)) {
                while ((bio = bio_list_pop(&bios)))
                        bio_io_error(bio);
                return;
@@ -1493,8 +1627,8 @@ static void do_worker(struct work_struct *ws)
 {
        struct pool *pool = container_of(ws, struct pool, worker);
 
-       process_prepared(pool, &pool->prepared_mappings, process_prepared_mapping);
-       process_prepared(pool, &pool->prepared_discards, process_prepared_discard);
+       process_prepared(pool, &pool->prepared_mappings, &pool->process_prepared_mapping);
+       process_prepared(pool, &pool->prepared_discards, &pool->process_prepared_discard);
        process_deferred_bios(pool);
 }
 
@@ -1511,6 +1645,52 @@ static void do_waker(struct work_struct *ws)
 
 /*----------------------------------------------------------------*/
 
+static enum pool_mode get_pool_mode(struct pool *pool)
+{
+       return pool->pf.mode;
+}
+
+static void set_pool_mode(struct pool *pool, enum pool_mode mode)
+{
+       int r;
+
+       pool->pf.mode = mode;
+
+       switch (mode) {
+       case PM_FAIL:
+               DMERR("switching pool to failure mode");
+               pool->process_bio = process_bio_fail;
+               pool->process_discard = process_bio_fail;
+               pool->process_prepared_mapping = process_prepared_mapping_fail;
+               pool->process_prepared_discard = process_prepared_discard_fail;
+               break;
+
+       case PM_READ_ONLY:
+               DMERR("switching pool to read-only mode");
+               r = dm_pool_abort_metadata(pool->pmd);
+               if (r) {
+                       DMERR("aborting transaction failed");
+                       set_pool_mode(pool, PM_FAIL);
+               } else {
+                       dm_pool_metadata_read_only(pool->pmd);
+                       pool->process_bio = process_bio_read_only;
+                       pool->process_discard = process_discard;
+                       pool->process_prepared_mapping = process_prepared_mapping_fail;
+                       pool->process_prepared_discard = process_prepared_discard_passdown;
+               }
+               break;
+
+       case PM_WRITE:
+               pool->process_bio = process_bio;
+               pool->process_discard = process_discard;
+               pool->process_prepared_mapping = process_prepared_mapping;
+               pool->process_prepared_discard = process_prepared_discard;
+               break;
+       }
+}
+
+/*----------------------------------------------------------------*/
+
 /*
  * Mapping functions.
  */
@@ -1556,6 +1736,12 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio,
        struct dm_thin_lookup_result result;
 
        map_context->ptr = thin_hook_bio(tc, bio);
+
+       if (get_pool_mode(tc->pool) == PM_FAIL) {
+               bio_io_error(bio);
+               return DM_MAPIO_SUBMITTED;
+       }
+
        if (bio->bi_rw & (REQ_DISCARD | REQ_FLUSH | REQ_FUA)) {
                thin_defer_bio(tc, bio);
                return DM_MAPIO_SUBMITTED;
@@ -1592,14 +1778,35 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio,
                break;
 
        case -ENODATA:
+               if (get_pool_mode(tc->pool) == PM_READ_ONLY) {
+                       /*
+                        * This block isn't provisioned, and we have no way
+                        * of doing so.  Just error it.
+                        */
+                       bio_io_error(bio);
+                       r = DM_MAPIO_SUBMITTED;
+                       break;
+               }
+               /* fall through */
+
+       case -EWOULDBLOCK:
                /*
                 * In future, the failed dm_thin_find_block above could
                 * provide the hint to load the metadata into cache.
                 */
-       case -EWOULDBLOCK:
                thin_defer_bio(tc, bio);
                r = DM_MAPIO_SUBMITTED;
                break;
+
+       default:
+               /*
+                * Must always call bio_io_error on failure.
+                * dm_thin_find_block can fail with -EINVAL if the
+                * pool is switched to fail-io mode.
+                */
+               bio_io_error(bio);
+               r = DM_MAPIO_SUBMITTED;
+               break;
        }
 
        return r;
@@ -1636,15 +1843,26 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
 {
        struct pool_c *pt = ti->private;
 
+       /*
+        * We want to make sure that degraded pools are never upgraded.
+        */
+       enum pool_mode old_mode = pool->pf.mode;
+       enum pool_mode new_mode = pt->pf.mode;
+
+       if (old_mode > new_mode)
+               new_mode = old_mode;
+
        pool->ti = ti;
        pool->low_water_blocks = pt->low_water_blocks;
        pool->pf = pt->pf;
+       set_pool_mode(pool, new_mode);
 
        /*
         * If discard_passdown was enabled verify that the data device
         * supports discards.  Disable discard_passdown if not; otherwise
         * -EOPNOTSUPP will be returned.
         */
+       /* FIXME: pull this out into a sep fn. */
        if (pt->pf.discard_passdown) {
                struct request_queue *q = bdev_get_queue(pt->data_dev->bdev);
                if (!q || !blk_queue_discard(q)) {
@@ -1670,6 +1888,7 @@ static void unbind_control_target(struct pool *pool, struct dm_target *ti)
 /* Initialize pool features. */
 static void pool_features_init(struct pool_features *pf)
 {
+       pf->mode = PM_WRITE;
        pf->zero_new_blocks = 1;
        pf->discard_enabled = 1;
        pf->discard_passdown = 1;
@@ -1700,14 +1919,16 @@ static struct kmem_cache *_endio_hook_cache;
 
 static struct pool *pool_create(struct mapped_device *pool_md,
                                struct block_device *metadata_dev,
-                               unsigned long block_size, char **error)
+                               unsigned long block_size,
+                               int read_only, char **error)
 {
        int r;
        void *err_p;
        struct pool *pool;
        struct dm_pool_metadata *pmd;
+       bool format_device = read_only ? false : true;
 
-       pmd = dm_pool_metadata_open(metadata_dev, block_size);
+       pmd = dm_pool_metadata_open(metadata_dev, block_size, format_device);
        if (IS_ERR(pmd)) {
                *error = "Error creating metadata object";
                return (struct pool *)pmd;
@@ -1722,8 +1943,10 @@ static struct pool *pool_create(struct mapped_device *pool_md,
 
        pool->pmd = pmd;
        pool->sectors_per_block = block_size;
-       pool->block_shift = ffs(block_size) - 1;
-       pool->offset_mask = block_size - 1;
+       if (block_size & (block_size - 1))
+               pool->sectors_per_block_shift = -1;
+       else
+               pool->sectors_per_block_shift = __ffs(block_size);
        pool->low_water_blocks = 0;
        pool_features_init(&pool->pf);
        pool->prison = prison_create(PRISON_CELLS);
@@ -1822,25 +2045,29 @@ static void __pool_dec(struct pool *pool)
 
 static struct pool *__pool_find(struct mapped_device *pool_md,
                                struct block_device *metadata_dev,
-                               unsigned long block_size, char **error,
-                               int *created)
+                               unsigned long block_size, int read_only,
+                               char **error, int *created)
 {
        struct pool *pool = __pool_table_lookup_metadata_dev(metadata_dev);
 
        if (pool) {
-               if (pool->pool_md != pool_md)
+               if (pool->pool_md != pool_md) {
+                       *error = "metadata device already in use by a pool";
                        return ERR_PTR(-EBUSY);
+               }
                __pool_inc(pool);
 
        } else {
                pool = __pool_table_lookup(pool_md);
                if (pool) {
-                       if (pool->md_dev != metadata_dev)
+                       if (pool->md_dev != metadata_dev) {
+                               *error = "different pool cannot replace a pool";
                                return ERR_PTR(-EINVAL);
+                       }
                        __pool_inc(pool);
 
                } else {
-                       pool = pool_create(pool_md, metadata_dev, block_size, error);
+                       pool = pool_create(pool_md, metadata_dev, block_size, read_only, error);
                        *created = 1;
                }
        }
@@ -1891,19 +2118,23 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
                arg_name = dm_shift_arg(as);
                argc--;
 
-               if (!strcasecmp(arg_name, "skip_block_zeroing")) {
+               if (!strcasecmp(arg_name, "skip_block_zeroing"))
                        pf->zero_new_blocks = 0;
-                       continue;
-               } else if (!strcasecmp(arg_name, "ignore_discard")) {
+
+               else if (!strcasecmp(arg_name, "ignore_discard"))
                        pf->discard_enabled = 0;
-                       continue;
-               } else if (!strcasecmp(arg_name, "no_discard_passdown")) {
+
+               else if (!strcasecmp(arg_name, "no_discard_passdown"))
                        pf->discard_passdown = 0;
-                       continue;
-               }
 
-               ti->error = "Unrecognised pool feature requested";
-               r = -EINVAL;
+               else if (!strcasecmp(arg_name, "read_only"))
+                       pf->mode = PM_READ_ONLY;
+
+               else {
+                       ti->error = "Unrecognised pool feature requested";
+                       r = -EINVAL;
+                       break;
+               }
        }
 
        return r;
@@ -1967,7 +2198,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
        if (kstrtoul(argv[2], 10, &block_size) || !block_size ||
            block_size < DATA_DEV_BLOCK_SIZE_MIN_SECTORS ||
            block_size > DATA_DEV_BLOCK_SIZE_MAX_SECTORS ||
-           !is_power_of_2(block_size)) {
+           block_size & (DATA_DEV_BLOCK_SIZE_MIN_SECTORS - 1)) {
                ti->error = "Invalid block size";
                r = -EINVAL;
                goto out;
@@ -1996,7 +2227,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
        }
 
        pool = __pool_find(dm_table_get_md(ti->table), metadata_dev->bdev,
-                          block_size, &ti->error, &pool_created);
+                          block_size, pf.mode == PM_READ_ONLY, &ti->error, &pool_created);
        if (IS_ERR(pool)) {
                r = PTR_ERR(pool);
                goto out_free_pt;
@@ -2014,6 +2245,15 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
                goto out_flags_changed;
        }
 
+       /*
+        * The block layer requires discard_granularity to be a power of 2.
+        */
+       if (pf.discard_enabled && !is_power_of_2(block_size)) {
+               ti->error = "Discard support must be disabled when the block size is not a power of 2";
+               r = -EINVAL;
+               goto out_flags_changed;
+       }
+
        pt->pool = pool;
        pt->ti = ti;
        pt->metadata_dev = metadata_dev;
@@ -2033,7 +2273,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
                 * stacking of discard limits (this keeps the pool and
                 * thin devices' discard limits consistent).
                 */
-               ti->discards_supported = 1;
+               ti->discards_supported = true;
        }
        ti->private = pt;
 
@@ -2093,7 +2333,8 @@ static int pool_preresume(struct dm_target *ti)
        int r;
        struct pool_c *pt = ti->private;
        struct pool *pool = pt->pool;
-       dm_block_t data_size, sb_data_size;
+       sector_t data_size = ti->len;
+       dm_block_t sb_data_size;
 
        /*
         * Take control of the pool object.
@@ -2102,7 +2343,8 @@ static int pool_preresume(struct dm_target *ti)
        if (r)
                return r;
 
-       data_size = ti->len >> pool->block_shift;
+       (void) sector_div(data_size, pool->sectors_per_block);
+
        r = dm_pool_get_data_dev_size(pool->pmd, &sb_data_size);
        if (r) {
                DMERR("failed to retrieve data device size");
@@ -2111,22 +2353,19 @@ static int pool_preresume(struct dm_target *ti)
 
        if (data_size < sb_data_size) {
                DMERR("pool target too small, is %llu blocks (expected %llu)",
-                     data_size, sb_data_size);
+                     (unsigned long long)data_size, sb_data_size);
                return -EINVAL;
 
        } else if (data_size > sb_data_size) {
                r = dm_pool_resize_data_dev(pool->pmd, data_size);
                if (r) {
                        DMERR("failed to resize data device");
+                       /* FIXME Stricter than necessary: Rollback transaction instead here */
+                       set_pool_mode(pool, PM_READ_ONLY);
                        return r;
                }
 
-               r = dm_pool_commit_metadata(pool->pmd);
-               if (r) {
-                       DMERR("%s: dm_pool_commit_metadata() failed, error = %d",
-                             __func__, r);
-                       return r;
-               }
+               (void) commit_or_fallback(pool);
        }
 
        return 0;
@@ -2149,19 +2388,12 @@ static void pool_resume(struct dm_target *ti)
 
 static void pool_postsuspend(struct dm_target *ti)
 {
-       int r;
        struct pool_c *pt = ti->private;
        struct pool *pool = pt->pool;
 
        cancel_delayed_work(&pool->waker);
        flush_workqueue(pool->wq);
-
-       r = dm_pool_commit_metadata(pool->pmd);
-       if (r < 0) {
-               DMERR("%s: dm_pool_commit_metadata() failed, error = %d",
-                     __func__, r);
-               /* FIXME: invalidate device? error the next FUA or FLUSH bio ?*/
-       }
+       (void) commit_or_fallback(pool);
 }
 
 static int check_arg_count(unsigned argc, unsigned args_required)
@@ -2295,12 +2527,7 @@ static int process_reserve_metadata_snap_mesg(unsigned argc, char **argv, struct
        if (r)
                return r;
 
-       r = dm_pool_commit_metadata(pool->pmd);
-       if (r) {
-               DMERR("%s: dm_pool_commit_metadata() failed, error = %d",
-                     __func__, r);
-               return r;
-       }
+       (void) commit_or_fallback(pool);
 
        r = dm_pool_reserve_metadata_snap(pool->pmd);
        if (r)
@@ -2361,25 +2588,41 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv)
        else
                DMWARN("Unrecognised thin pool target message received: %s", argv[0]);
 
-       if (!r) {
-               r = dm_pool_commit_metadata(pool->pmd);
-               if (r)
-                       DMERR("%s message: dm_pool_commit_metadata() failed, error = %d",
-                             argv[0], r);
-       }
+       if (!r)
+               (void) commit_or_fallback(pool);
 
        return r;
 }
 
+static void emit_flags(struct pool_features *pf, char *result,
+                      unsigned sz, unsigned maxlen)
+{
+       unsigned count = !pf->zero_new_blocks + !pf->discard_enabled +
+               !pf->discard_passdown + (pf->mode == PM_READ_ONLY);
+       DMEMIT("%u ", count);
+
+       if (!pf->zero_new_blocks)
+               DMEMIT("skip_block_zeroing ");
+
+       if (!pf->discard_enabled)
+               DMEMIT("ignore_discard ");
+
+       if (!pf->discard_passdown)
+               DMEMIT("no_discard_passdown ");
+
+       if (pf->mode == PM_READ_ONLY)
+               DMEMIT("read_only ");
+}
+
 /*
  * Status line is:
  *    <transaction id> <used metadata sectors>/<total metadata sectors>
  *    <used data sectors>/<total data sectors> <held metadata root>
  */
 static int pool_status(struct dm_target *ti, status_type_t type,
-                      char *result, unsigned maxlen)
+                      unsigned status_flags, char *result, unsigned maxlen)
 {
-       int r, count;
+       int r;
        unsigned sz = 0;
        uint64_t transaction_id;
        dm_block_t nr_free_blocks_data;
@@ -2394,6 +2637,15 @@ static int pool_status(struct dm_target *ti, status_type_t type,
 
        switch (type) {
        case STATUSTYPE_INFO:
+               if (get_pool_mode(pool) == PM_FAIL) {
+                       DMEMIT("Fail");
+                       break;
+               }
+
+               /* Commit to ensure statistics aren't out-of-date */
+               if (!(status_flags & DM_STATUS_NOFLUSH_FLAG) && !dm_suspended(ti))
+                       (void) commit_or_fallback(pool);
+
                r = dm_pool_get_metadata_transaction_id(pool->pmd,
                                                        &transaction_id);
                if (r)
@@ -2429,9 +2681,19 @@ static int pool_status(struct dm_target *ti, status_type_t type,
                       (unsigned long long)nr_blocks_data);
 
                if (held_root)
-                       DMEMIT("%llu", held_root);
+                       DMEMIT("%llu ", held_root);
+               else
+                       DMEMIT("- ");
+
+               if (pool->pf.mode == PM_READ_ONLY)
+                       DMEMIT("ro ");
+               else
+                       DMEMIT("rw ");
+
+               if (pool->pf.discard_enabled && pool->pf.discard_passdown)
+                       DMEMIT("discard_passdown");
                else
-                       DMEMIT("-");
+                       DMEMIT("no_discard_passdown");
 
                break;
 
@@ -2441,20 +2703,7 @@ static int pool_status(struct dm_target *ti, status_type_t type,
                       format_dev_t(buf2, pt->data_dev->bdev->bd_dev),
                       (unsigned long)pool->sectors_per_block,
                       (unsigned long long)pt->low_water_blocks);
-
-               count = !pool->pf.zero_new_blocks + !pool->pf.discard_enabled +
-                       !pt->pf.discard_passdown;
-               DMEMIT("%u ", count);
-
-               if (!pool->pf.zero_new_blocks)
-                       DMEMIT("skip_block_zeroing ");
-
-               if (!pool->pf.discard_enabled)
-                       DMEMIT("ignore_discard ");
-
-               if (!pt->pf.discard_passdown)
-                       DMEMIT("no_discard_passdown ");
-
+               emit_flags(&pt->pf, result, sz, maxlen);
                break;
        }
 
@@ -2492,7 +2741,8 @@ static void set_discard_limits(struct pool *pool, struct queue_limits *limits)
 
        /*
         * This is just a hint, and not enforced.  We have to cope with
-        * bios that overlap 2 blocks.
+        * bios that cover a block partially.  A discard that spans a block
+        * boundary is not sent to this target.
         */
        limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT;
        limits->discard_zeroes_data = pool->pf.zero_new_blocks;
@@ -2513,7 +2763,7 @@ static struct target_type pool_target = {
        .name = "thin-pool",
        .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
                    DM_TARGET_IMMUTABLE,
-       .version = {1, 2, 0},
+       .version = {1, 3, 0},
        .module = THIS_MODULE,
        .ctr = pool_ctr,
        .dtr = pool_dtr,
@@ -2618,20 +2868,31 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
        }
        __pool_inc(tc->pool);
 
+       if (get_pool_mode(tc->pool) == PM_FAIL) {
+               ti->error = "Couldn't open thin device, Pool is in fail mode";
+               goto bad_thin_open;
+       }
+
        r = dm_pool_open_thin_device(tc->pool->pmd, tc->dev_id, &tc->td);
        if (r) {
                ti->error = "Couldn't open thin internal device";
                goto bad_thin_open;
        }
 
-       ti->split_io = tc->pool->sectors_per_block;
+       r = dm_set_target_max_io_len(ti, tc->pool->sectors_per_block);
+       if (r)
+               goto bad_thin_open;
+
        ti->num_flush_requests = 1;
+       ti->flush_supported = true;
 
        /* In case the pool supports discards, pass them on. */
        if (tc->pool->pf.discard_enabled) {
-               ti->discards_supported = 1;
+               ti->discards_supported = true;
                ti->num_discard_requests = 1;
-               ti->discard_zeroes_data_unsupported = 1;
+               ti->discard_zeroes_data_unsupported = true;
+               /* Discard requests must be split on a block boundary */
+               ti->split_discard_requests = true;
        }
 
        dm_put(pool_md);
@@ -2712,7 +2973,7 @@ static void thin_postsuspend(struct dm_target *ti)
  * <nr mapped sectors> <highest mapped sector>
  */
 static int thin_status(struct dm_target *ti, status_type_t type,
-                      char *result, unsigned maxlen)
+                      unsigned status_flags, char *result, unsigned maxlen)
 {
        int r;
        ssize_t sz = 0;
@@ -2720,6 +2981,11 @@ static int thin_status(struct dm_target *ti, status_type_t type,
        char buf[BDEVNAME_SIZE];
        struct thin_c *tc = ti->private;
 
+       if (get_pool_mode(tc->pool) == PM_FAIL) {
+               DMEMIT("Fail");
+               return 0;
+       }
+
        if (!tc->td)
                DMEMIT("-");
        else {
@@ -2757,19 +3023,21 @@ static int thin_status(struct dm_target *ti, status_type_t type,
 static int thin_iterate_devices(struct dm_target *ti,
                                iterate_devices_callout_fn fn, void *data)
 {
-       dm_block_t blocks;
+       sector_t blocks;
        struct thin_c *tc = ti->private;
+       struct pool *pool = tc->pool;
 
        /*
         * We can't call dm_pool_get_data_dev_size() since that blocks.  So
         * we follow a more convoluted path through to the pool's target.
         */
-       if (!tc->pool->ti)
+       if (!pool->ti)
                return 0;       /* nothing is bound */
 
-       blocks = tc->pool->ti->len >> tc->pool->block_shift;
+       blocks = pool->ti->len;
+       (void) sector_div(blocks, pool->sectors_per_block);
        if (blocks)
-               return fn(ti, tc->pool_dev, 0, tc->pool->sectors_per_block * blocks, data);
+               return fn(ti, tc->pool_dev, 0, pool->sectors_per_block * blocks, data);
 
        return 0;
 }
@@ -2786,7 +3054,7 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
 static struct target_type thin_target = {
        .name = "thin",
-       .version = {1, 1, 0},
+       .version = {1, 3, 0},
        .module = THIS_MODULE,
        .ctr = thin_ctr,
        .dtr = thin_dtr,
index fa365d39b61281b887d456ddbb8c9141352c8acf..254d19268ad2fa0c7102014c997b75294450ba42 100644 (file)
@@ -515,7 +515,7 @@ static int verity_map(struct dm_target *ti, struct bio *bio,
  * Status: V (valid) or C (corruption found)
  */
 static int verity_status(struct dm_target *ti, status_type_t type,
-                        char *result, unsigned maxlen)
+                        unsigned status_flags, char *result, unsigned maxlen)
 {
        struct dm_verity *v = ti->private;
        unsigned sz = 0;
index e24143cc2040b7f3f8f90a63c3b1b2cfe2b21c24..4e09b6ff5b493403d4e51be0b4fee2d99643e276 100644 (file)
@@ -968,22 +968,41 @@ static sector_t max_io_len_target_boundary(sector_t sector, struct dm_target *ti
 static sector_t max_io_len(sector_t sector, struct dm_target *ti)
 {
        sector_t len = max_io_len_target_boundary(sector, ti);
+       sector_t offset, max_len;
 
        /*
-        * Does the target need to split even further ?
+        * Does the target need to split even further?
         */
-       if (ti->split_io) {
-               sector_t boundary;
-               sector_t offset = dm_target_offset(ti, sector);
-               boundary = ((offset + ti->split_io) & ~(ti->split_io - 1))
-                          - offset;
-               if (len > boundary)
-                       len = boundary;
+       if (ti->max_io_len) {
+               offset = dm_target_offset(ti, sector);
+               if (unlikely(ti->max_io_len & (ti->max_io_len - 1)))
+                       max_len = sector_div(offset, ti->max_io_len);
+               else
+                       max_len = offset & (ti->max_io_len - 1);
+               max_len = ti->max_io_len - max_len;
+
+               if (len > max_len)
+                       len = max_len;
        }
 
        return len;
 }
 
+int dm_set_target_max_io_len(struct dm_target *ti, sector_t len)
+{
+       if (len > UINT_MAX) {
+               DMERR("Specified maximum size of target IO (%llu) exceeds limit (%u)",
+                     (unsigned long long)len, UINT_MAX);
+               ti->error = "Maximum size of target IO is too large";
+               return -EINVAL;
+       }
+
+       ti->max_io_len = (uint32_t) len;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dm_set_target_max_io_len);
+
 static void __map_bio(struct dm_target *ti, struct bio *clone,
                      struct dm_target_io *tio)
 {
@@ -1196,7 +1215,10 @@ static int __clone_and_map_discard(struct clone_info *ci)
                if (!ti->num_discard_requests)
                        return -EOPNOTSUPP;
 
-               len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti));
+               if (!ti->split_discard_requests)
+                       len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti));
+               else
+                       len = min(ci->sector_count, max_io_len(ci->sector, ti));
 
                __issue_target_requests(ci, ti, ti->num_discard_requests, len);
 
index b7dacd59d8d7534fbc73584609b5644a20ed4d84..52eef493d2669290eaa3f2a22e46717dac9aa1eb 100644 (file)
 #define DM_SUSPEND_LOCKFS_FLAG         (1 << 0)
 #define DM_SUSPEND_NOFLUSH_FLAG                (1 << 1)
 
+/*
+ * Status feature flags
+ */
+#define DM_STATUS_NOFLUSH_FLAG         (1 << 0)
+
 /*
  * Type of table and mapped_device's mempool
  */
index cfa95f6622300ccbe7fcb953bbf2e811f171d527..d8e7cb767c1e608dc82d89b42ffa63fe445b8164 100644 (file)
@@ -1,7 +1,6 @@
 obj-$(CONFIG_DM_PERSISTENT_DATA) += dm-persistent-data.o
 dm-persistent-data-objs := \
        dm-block-manager.o \
-       dm-space-map-checker.o \
        dm-space-map-common.o \
        dm-space-map-disk.o \
        dm-space-map-metadata.o \
index 0317ecdc6e5399aff5e6430acc796c37dc025568..5ba277768d9914c3dd6364f3d990feef55b67c92 100644 (file)
@@ -325,11 +325,6 @@ static struct dm_buffer *to_buffer(struct dm_block *b)
        return (struct dm_buffer *) b;
 }
 
-static struct dm_bufio_client *to_bufio(struct dm_block_manager *bm)
-{
-       return (struct dm_bufio_client *) bm;
-}
-
 dm_block_t dm_block_location(struct dm_block *b)
 {
        return dm_bufio_get_block_number(to_buffer(b));
@@ -367,34 +362,60 @@ static void dm_block_manager_write_callback(struct dm_buffer *buf)
 /*----------------------------------------------------------------
  * Public interface
  *--------------------------------------------------------------*/
+struct dm_block_manager {
+       struct dm_bufio_client *bufio;
+       bool read_only:1;
+};
+
 struct dm_block_manager *dm_block_manager_create(struct block_device *bdev,
                                                 unsigned block_size,
                                                 unsigned cache_size,
                                                 unsigned max_held_per_thread)
 {
-       return (struct dm_block_manager *)
-               dm_bufio_client_create(bdev, block_size, max_held_per_thread,
-                                      sizeof(struct buffer_aux),
-                                      dm_block_manager_alloc_callback,
-                                      dm_block_manager_write_callback);
+       int r;
+       struct dm_block_manager *bm;
+
+       bm = kmalloc(sizeof(*bm), GFP_KERNEL);
+       if (!bm) {
+               r = -ENOMEM;
+               goto bad;
+       }
+
+       bm->bufio = dm_bufio_client_create(bdev, block_size, max_held_per_thread,
+                                          sizeof(struct buffer_aux),
+                                          dm_block_manager_alloc_callback,
+                                          dm_block_manager_write_callback);
+       if (IS_ERR(bm->bufio)) {
+               r = PTR_ERR(bm->bufio);
+               kfree(bm);
+               goto bad;
+       }
+
+       bm->read_only = false;
+
+       return bm;
+
+bad:
+       return ERR_PTR(r);
 }
 EXPORT_SYMBOL_GPL(dm_block_manager_create);
 
 void dm_block_manager_destroy(struct dm_block_manager *bm)
 {
-       return dm_bufio_client_destroy(to_bufio(bm));
+       dm_bufio_client_destroy(bm->bufio);
+       kfree(bm);
 }
 EXPORT_SYMBOL_GPL(dm_block_manager_destroy);
 
 unsigned dm_bm_block_size(struct dm_block_manager *bm)
 {
-       return dm_bufio_get_block_size(to_bufio(bm));
+       return dm_bufio_get_block_size(bm->bufio);
 }
 EXPORT_SYMBOL_GPL(dm_bm_block_size);
 
 dm_block_t dm_bm_nr_blocks(struct dm_block_manager *bm)
 {
-       return dm_bufio_get_device_size(to_bufio(bm));
+       return dm_bufio_get_device_size(bm->bufio);
 }
 
 static int dm_bm_validate_buffer(struct dm_block_manager *bm,
@@ -406,7 +427,7 @@ static int dm_bm_validate_buffer(struct dm_block_manager *bm,
                int r;
                if (!v)
                        return 0;
-               r = v->check(v, (struct dm_block *) buf, dm_bufio_get_block_size(to_bufio(bm)));
+               r = v->check(v, (struct dm_block *) buf, dm_bufio_get_block_size(bm->bufio));
                if (unlikely(r))
                        return r;
                aux->validator = v;
@@ -430,7 +451,7 @@ int dm_bm_read_lock(struct dm_block_manager *bm, dm_block_t b,
        void *p;
        int r;
 
-       p = dm_bufio_read(to_bufio(bm), b, (struct dm_buffer **) result);
+       p = dm_bufio_read(bm->bufio, b, (struct dm_buffer **) result);
        if (unlikely(IS_ERR(p)))
                return PTR_ERR(p);
 
@@ -463,7 +484,10 @@ int dm_bm_write_lock(struct dm_block_manager *bm,
        void *p;
        int r;
 
-       p = dm_bufio_read(to_bufio(bm), b, (struct dm_buffer **) result);
+       if (bm->read_only)
+               return -EPERM;
+
+       p = dm_bufio_read(bm->bufio, b, (struct dm_buffer **) result);
        if (unlikely(IS_ERR(p)))
                return PTR_ERR(p);
 
@@ -496,7 +520,7 @@ int dm_bm_read_try_lock(struct dm_block_manager *bm,
        void *p;
        int r;
 
-       p = dm_bufio_get(to_bufio(bm), b, (struct dm_buffer **) result);
+       p = dm_bufio_get(bm->bufio, b, (struct dm_buffer **) result);
        if (unlikely(IS_ERR(p)))
                return PTR_ERR(p);
        if (unlikely(!p))
@@ -529,7 +553,10 @@ int dm_bm_write_lock_zero(struct dm_block_manager *bm,
        struct buffer_aux *aux;
        void *p;
 
-       p = dm_bufio_new(to_bufio(bm), b, (struct dm_buffer **) result);
+       if (bm->read_only)
+               return -EPERM;
+
+       p = dm_bufio_new(bm->bufio, b, (struct dm_buffer **) result);
        if (unlikely(IS_ERR(p)))
                return PTR_ERR(p);
 
@@ -547,6 +574,7 @@ int dm_bm_write_lock_zero(struct dm_block_manager *bm,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(dm_bm_write_lock_zero);
 
 int dm_bm_unlock(struct dm_block *b)
 {
@@ -565,45 +593,30 @@ int dm_bm_unlock(struct dm_block *b)
 }
 EXPORT_SYMBOL_GPL(dm_bm_unlock);
 
-int dm_bm_unlock_move(struct dm_block *b, dm_block_t n)
-{
-       struct buffer_aux *aux;
-
-       aux = dm_bufio_get_aux_data(to_buffer(b));
-
-       if (aux->write_locked) {
-               dm_bufio_mark_buffer_dirty(to_buffer(b));
-               bl_up_write(&aux->lock);
-       } else
-               bl_up_read(&aux->lock);
-
-       dm_bufio_release_move(to_buffer(b), n);
-       return 0;
-}
-
 int dm_bm_flush_and_unlock(struct dm_block_manager *bm,
                           struct dm_block *superblock)
 {
        int r;
 
-       r = dm_bufio_write_dirty_buffers(to_bufio(bm));
-       if (unlikely(r))
-               return r;
-       r = dm_bufio_issue_flush(to_bufio(bm));
-       if (unlikely(r))
+       if (bm->read_only)
+               return -EPERM;
+
+       r = dm_bufio_write_dirty_buffers(bm->bufio);
+       if (unlikely(r)) {
+               dm_bm_unlock(superblock);
                return r;
+       }
 
        dm_bm_unlock(superblock);
 
-       r = dm_bufio_write_dirty_buffers(to_bufio(bm));
-       if (unlikely(r))
-               return r;
-       r = dm_bufio_issue_flush(to_bufio(bm));
-       if (unlikely(r))
-               return r;
+       return dm_bufio_write_dirty_buffers(bm->bufio);
+}
 
-       return 0;
+void dm_bm_set_read_only(struct dm_block_manager *bm)
+{
+       bm->read_only = true;
 }
+EXPORT_SYMBOL_GPL(dm_bm_set_read_only);
 
 u32 dm_bm_checksum(const void *data, size_t len, u32 init_xor)
 {
index 924833d2dfa69f13944628eb220733a5500cd807..be5bff61be280562932906b1b182ef1d3775ea55 100644 (file)
@@ -96,14 +96,6 @@ int dm_bm_write_lock_zero(struct dm_block_manager *bm, dm_block_t b,
 
 int dm_bm_unlock(struct dm_block *b);
 
-/*
- * An optimisation; we often want to copy a block's contents to a new
- * block.  eg, as part of the shadowing operation.  It's far better for
- * bufio to do this move behind the scenes than hold 2 locks and memcpy the
- * data.
- */
-int dm_bm_unlock_move(struct dm_block *b, dm_block_t n);
-
 /*
  * It's a common idiom to have a superblock that should be committed last.
  *
@@ -116,6 +108,19 @@ int dm_bm_unlock_move(struct dm_block *b, dm_block_t n);
 int dm_bm_flush_and_unlock(struct dm_block_manager *bm,
                           struct dm_block *superblock);
 
+/*
+ * Switches the bm to a read only mode.  Once read-only mode
+ * has been entered the following functions will return -EPERM.
+ *
+ *   dm_bm_write_lock
+ *   dm_bm_write_lock_zero
+ *   dm_bm_flush_and_unlock
+ *
+ * Additionally you should not use dm_bm_unlock_move, however no error will
+ * be returned if you do.
+ */
+void dm_bm_set_read_only(struct dm_block_manager *bm);
+
 u32 dm_bm_checksum(const void *data, size_t len, u32 init_xor);
 
 /*----------------------------------------------------------------*/
diff --git a/drivers/md/persistent-data/dm-space-map-checker.c b/drivers/md/persistent-data/dm-space-map-checker.c
deleted file mode 100644 (file)
index fc90c11..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright (C) 2011 Red Hat, Inc.
- *
- * This file is released under the GPL.
- */
-
-#include "dm-space-map-checker.h"
-
-#include <linux/device-mapper.h>
-#include <linux/export.h>
-#include <linux/vmalloc.h>
-
-#ifdef CONFIG_DM_DEBUG_SPACE_MAPS
-
-#define DM_MSG_PREFIX "space map checker"
-
-/*----------------------------------------------------------------*/
-
-struct count_array {
-       dm_block_t nr;
-       dm_block_t nr_free;
-
-       uint32_t *counts;
-};
-
-static int ca_get_count(struct count_array *ca, dm_block_t b, uint32_t *count)
-{
-       if (b >= ca->nr)
-               return -EINVAL;
-
-       *count = ca->counts[b];
-       return 0;
-}
-
-static int ca_count_more_than_one(struct count_array *ca, dm_block_t b, int *r)
-{
-       if (b >= ca->nr)
-               return -EINVAL;
-
-       *r = ca->counts[b] > 1;
-       return 0;
-}
-
-static int ca_set_count(struct count_array *ca, dm_block_t b, uint32_t count)
-{
-       uint32_t old_count;
-
-       if (b >= ca->nr)
-               return -EINVAL;
-
-       old_count = ca->counts[b];
-
-       if (!count && old_count)
-               ca->nr_free++;
-
-       else if (count && !old_count)
-               ca->nr_free--;
-
-       ca->counts[b] = count;
-       return 0;
-}
-
-static int ca_inc_block(struct count_array *ca, dm_block_t b)
-{
-       if (b >= ca->nr)
-               return -EINVAL;
-
-       ca_set_count(ca, b, ca->counts[b] + 1);
-       return 0;
-}
-
-static int ca_dec_block(struct count_array *ca, dm_block_t b)
-{
-       if (b >= ca->nr)
-               return -EINVAL;
-
-       BUG_ON(ca->counts[b] == 0);
-       ca_set_count(ca, b, ca->counts[b] - 1);
-       return 0;
-}
-
-static int ca_create(struct count_array *ca, struct dm_space_map *sm)
-{
-       int r;
-       dm_block_t nr_blocks;
-
-       r = dm_sm_get_nr_blocks(sm, &nr_blocks);
-       if (r)
-               return r;
-
-       ca->nr = nr_blocks;
-       ca->nr_free = nr_blocks;
-
-       if (!nr_blocks)
-               ca->counts = NULL;
-       else {
-               ca->counts = vzalloc(sizeof(*ca->counts) * nr_blocks);
-               if (!ca->counts)
-                       return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void ca_destroy(struct count_array *ca)
-{
-       vfree(ca->counts);
-}
-
-static int ca_load(struct count_array *ca, struct dm_space_map *sm)
-{
-       int r;
-       uint32_t count;
-       dm_block_t nr_blocks, i;
-
-       r = dm_sm_get_nr_blocks(sm, &nr_blocks);
-       if (r)
-               return r;
-
-       BUG_ON(ca->nr != nr_blocks);
-
-       DMWARN("Loading debug space map from disk.  This may take some time");
-       for (i = 0; i < nr_blocks; i++) {
-               r = dm_sm_get_count(sm, i, &count);
-               if (r) {
-                       DMERR("load failed");
-                       return r;
-               }
-
-               ca_set_count(ca, i, count);
-       }
-       DMWARN("Load complete");
-
-       return 0;
-}
-
-static int ca_extend(struct count_array *ca, dm_block_t extra_blocks)
-{
-       dm_block_t nr_blocks = ca->nr + extra_blocks;
-       uint32_t *counts = vzalloc(sizeof(*counts) * nr_blocks);
-       if (!counts)
-               return -ENOMEM;
-
-       if (ca->counts) {
-               memcpy(counts, ca->counts, sizeof(*counts) * ca->nr);
-               ca_destroy(ca);
-       }
-       ca->nr = nr_blocks;
-       ca->nr_free += extra_blocks;
-       ca->counts = counts;
-       return 0;
-}
-
-static int ca_commit(struct count_array *old, struct count_array *new)
-{
-       if (old->nr != new->nr) {
-               BUG_ON(old->nr > new->nr);
-               ca_extend(old, new->nr - old->nr);
-       }
-
-       BUG_ON(old->nr != new->nr);
-       old->nr_free = new->nr_free;
-       memcpy(old->counts, new->counts, sizeof(*old->counts) * old->nr);
-       return 0;
-}
-
-/*----------------------------------------------------------------*/
-
-struct sm_checker {
-       struct dm_space_map sm;
-
-       struct count_array old_counts;
-       struct count_array counts;
-
-       struct dm_space_map *real_sm;
-};
-
-static void sm_checker_destroy(struct dm_space_map *sm)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-
-       dm_sm_destroy(smc->real_sm);
-       ca_destroy(&smc->old_counts);
-       ca_destroy(&smc->counts);
-       kfree(smc);
-}
-
-static int sm_checker_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-       int r = dm_sm_get_nr_blocks(smc->real_sm, count);
-       if (!r)
-               BUG_ON(smc->old_counts.nr != *count);
-       return r;
-}
-
-static int sm_checker_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-       int r = dm_sm_get_nr_free(smc->real_sm, count);
-       if (!r) {
-               /*
-                * Slow, but we know it's correct.
-                */
-               dm_block_t b, n = 0;
-               for (b = 0; b < smc->old_counts.nr; b++)
-                       if (smc->old_counts.counts[b] == 0 &&
-                           smc->counts.counts[b] == 0)
-                               n++;
-
-               if (n != *count)
-                       DMERR("free block counts differ, checker %u, sm-disk:%u",
-                             (unsigned) n, (unsigned) *count);
-       }
-       return r;
-}
-
-static int sm_checker_new_block(struct dm_space_map *sm, dm_block_t *b)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-       int r = dm_sm_new_block(smc->real_sm, b);
-
-       if (!r) {
-               BUG_ON(*b >= smc->old_counts.nr);
-               BUG_ON(smc->old_counts.counts[*b] != 0);
-               BUG_ON(*b >= smc->counts.nr);
-               BUG_ON(smc->counts.counts[*b] != 0);
-               ca_set_count(&smc->counts, *b, 1);
-       }
-
-       return r;
-}
-
-static int sm_checker_inc_block(struct dm_space_map *sm, dm_block_t b)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-       int r = dm_sm_inc_block(smc->real_sm, b);
-       int r2 = ca_inc_block(&smc->counts, b);
-       BUG_ON(r != r2);
-       return r;
-}
-
-static int sm_checker_dec_block(struct dm_space_map *sm, dm_block_t b)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-       int r = dm_sm_dec_block(smc->real_sm, b);
-       int r2 = ca_dec_block(&smc->counts, b);
-       BUG_ON(r != r2);
-       return r;
-}
-
-static int sm_checker_get_count(struct dm_space_map *sm, dm_block_t b, uint32_t *result)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-       uint32_t result2 = 0;
-       int r = dm_sm_get_count(smc->real_sm, b, result);
-       int r2 = ca_get_count(&smc->counts, b, &result2);
-
-       BUG_ON(r != r2);
-       if (!r)
-               BUG_ON(*result != result2);
-       return r;
-}
-
-static int sm_checker_count_more_than_one(struct dm_space_map *sm, dm_block_t b, int *result)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-       int result2 = 0;
-       int r = dm_sm_count_is_more_than_one(smc->real_sm, b, result);
-       int r2 = ca_count_more_than_one(&smc->counts, b, &result2);
-
-       BUG_ON(r != r2);
-       if (!r)
-               BUG_ON(!(*result) && result2);
-       return r;
-}
-
-static int sm_checker_set_count(struct dm_space_map *sm, dm_block_t b, uint32_t count)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-       uint32_t old_rc;
-       int r = dm_sm_set_count(smc->real_sm, b, count);
-       int r2;
-
-       BUG_ON(b >= smc->counts.nr);
-       old_rc = smc->counts.counts[b];
-       r2 = ca_set_count(&smc->counts, b, count);
-       BUG_ON(r != r2);
-
-       return r;
-}
-
-static int sm_checker_commit(struct dm_space_map *sm)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-       int r;
-
-       r = dm_sm_commit(smc->real_sm);
-       if (r)
-               return r;
-
-       r = ca_commit(&smc->old_counts, &smc->counts);
-       if (r)
-               return r;
-
-       return 0;
-}
-
-static int sm_checker_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-       int r = dm_sm_extend(smc->real_sm, extra_blocks);
-       if (r)
-               return r;
-
-       return ca_extend(&smc->counts, extra_blocks);
-}
-
-static int sm_checker_root_size(struct dm_space_map *sm, size_t *result)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-       return dm_sm_root_size(smc->real_sm, result);
-}
-
-static int sm_checker_copy_root(struct dm_space_map *sm, void *copy_to_here_le, size_t len)
-{
-       struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
-       return dm_sm_copy_root(smc->real_sm, copy_to_here_le, len);
-}
-
-/*----------------------------------------------------------------*/
-
-static struct dm_space_map ops_ = {
-       .destroy = sm_checker_destroy,
-       .get_nr_blocks = sm_checker_get_nr_blocks,
-       .get_nr_free = sm_checker_get_nr_free,
-       .inc_block = sm_checker_inc_block,
-       .dec_block = sm_checker_dec_block,
-       .new_block = sm_checker_new_block,
-       .get_count = sm_checker_get_count,
-       .count_is_more_than_one = sm_checker_count_more_than_one,
-       .set_count = sm_checker_set_count,
-       .commit = sm_checker_commit,
-       .extend = sm_checker_extend,
-       .root_size = sm_checker_root_size,
-       .copy_root = sm_checker_copy_root
-};
-
-struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm)
-{
-       int r;
-       struct sm_checker *smc;
-
-       if (IS_ERR_OR_NULL(sm))
-               return ERR_PTR(-EINVAL);
-
-       smc = kmalloc(sizeof(*smc), GFP_KERNEL);
-       if (!smc)
-               return ERR_PTR(-ENOMEM);
-
-       memcpy(&smc->sm, &ops_, sizeof(smc->sm));
-       r = ca_create(&smc->old_counts, sm);
-       if (r) {
-               kfree(smc);
-               return ERR_PTR(r);
-       }
-
-       r = ca_create(&smc->counts, sm);
-       if (r) {
-               ca_destroy(&smc->old_counts);
-               kfree(smc);
-               return ERR_PTR(r);
-       }
-
-       smc->real_sm = sm;
-
-       r = ca_load(&smc->counts, sm);
-       if (r) {
-               ca_destroy(&smc->counts);
-               ca_destroy(&smc->old_counts);
-               kfree(smc);
-               return ERR_PTR(r);
-       }
-
-       r = ca_commit(&smc->old_counts, &smc->counts);
-       if (r) {
-               ca_destroy(&smc->counts);
-               ca_destroy(&smc->old_counts);
-               kfree(smc);
-               return ERR_PTR(r);
-       }
-
-       return &smc->sm;
-}
-EXPORT_SYMBOL_GPL(dm_sm_checker_create);
-
-struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm)
-{
-       int r;
-       struct sm_checker *smc;
-
-       if (IS_ERR_OR_NULL(sm))
-               return ERR_PTR(-EINVAL);
-
-       smc = kmalloc(sizeof(*smc), GFP_KERNEL);
-       if (!smc)
-               return ERR_PTR(-ENOMEM);
-
-       memcpy(&smc->sm, &ops_, sizeof(smc->sm));
-       r = ca_create(&smc->old_counts, sm);
-       if (r) {
-               kfree(smc);
-               return ERR_PTR(r);
-       }
-
-       r = ca_create(&smc->counts, sm);
-       if (r) {
-               ca_destroy(&smc->old_counts);
-               kfree(smc);
-               return ERR_PTR(r);
-       }
-
-       smc->real_sm = sm;
-       return &smc->sm;
-}
-EXPORT_SYMBOL_GPL(dm_sm_checker_create_fresh);
-
-/*----------------------------------------------------------------*/
-
-#else
-
-struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm)
-{
-       return sm;
-}
-EXPORT_SYMBOL_GPL(dm_sm_checker_create);
-
-struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm)
-{
-       return sm;
-}
-EXPORT_SYMBOL_GPL(dm_sm_checker_create_fresh);
-
-/*----------------------------------------------------------------*/
-
-#endif
diff --git a/drivers/md/persistent-data/dm-space-map-checker.h b/drivers/md/persistent-data/dm-space-map-checker.h
deleted file mode 100644 (file)
index 444dccf..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2011 Red Hat, Inc.
- *
- * This file is released under the GPL.
- */
-
-#ifndef SNAPSHOTS_SPACE_MAP_CHECKER_H
-#define SNAPSHOTS_SPACE_MAP_CHECKER_H
-
-#include "dm-space-map.h"
-
-/*----------------------------------------------------------------*/
-
-/*
- * This space map wraps a real on-disk space map, and verifies all of its
- * operations.  It uses a lot of memory, so only use if you have a specific
- * problem that you're debugging.
- *
- * Ownership of @sm passes.
- */
-struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm);
-struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm);
-
-/*----------------------------------------------------------------*/
-
-#endif
index ff3beed6ad2d93769e475539ecd60d29ffdfaf22..d77602d63c83f8b98e341dd07c1dd50c397986e4 100644 (file)
@@ -224,6 +224,7 @@ static int sm_ll_init(struct ll_disk *ll, struct dm_transaction_manager *tm)
        ll->nr_blocks = 0;
        ll->bitmap_root = 0;
        ll->ref_count_root = 0;
+       ll->bitmap_index_changed = false;
 
        return 0;
 }
@@ -476,7 +477,15 @@ int sm_ll_dec(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev)
 
 int sm_ll_commit(struct ll_disk *ll)
 {
-       return ll->commit(ll);
+       int r = 0;
+
+       if (ll->bitmap_index_changed) {
+               r = ll->commit(ll);
+               if (!r)
+                       ll->bitmap_index_changed = false;
+       }
+
+       return r;
 }
 
 /*----------------------------------------------------------------*/
@@ -491,6 +500,7 @@ static int metadata_ll_load_ie(struct ll_disk *ll, dm_block_t index,
 static int metadata_ll_save_ie(struct ll_disk *ll, dm_block_t index,
                               struct disk_index_entry *ie)
 {
+       ll->bitmap_index_changed = true;
        memcpy(ll->mi_le.index + index, ie, sizeof(*ie));
        return 0;
 }
index 8f220821a9a9a336a175c1f748f20399abf7a14b..b3078d5eda0c335c2986b84128d3e5bde01e8b8e 100644 (file)
@@ -78,6 +78,7 @@ struct ll_disk {
        open_index_fn open_index;
        max_index_entries_fn max_entries;
        commit_fn commit;
+       bool bitmap_index_changed:1;
 };
 
 struct disk_sm_root {
index 3d0ed53328831627ab6ec79cb85946f36b0fe7a4..f6d29e614ab728c521b0ebc1f8a7f320e5099deb 100644 (file)
@@ -4,7 +4,6 @@
  * This file is released under the GPL.
  */
 
-#include "dm-space-map-checker.h"
 #include "dm-space-map-common.h"
 #include "dm-space-map-disk.h"
 #include "dm-space-map.h"
@@ -252,9 +251,8 @@ static struct dm_space_map ops = {
        .copy_root = sm_disk_copy_root
 };
 
-static struct dm_space_map *dm_sm_disk_create_real(
-       struct dm_transaction_manager *tm,
-       dm_block_t nr_blocks)
+struct dm_space_map *dm_sm_disk_create(struct dm_transaction_manager *tm,
+                                      dm_block_t nr_blocks)
 {
        int r;
        struct sm_disk *smd;
@@ -285,27 +283,10 @@ bad:
        kfree(smd);
        return ERR_PTR(r);
 }
-
-struct dm_space_map *dm_sm_disk_create(struct dm_transaction_manager *tm,
-                                      dm_block_t nr_blocks)
-{
-       struct dm_space_map *sm = dm_sm_disk_create_real(tm, nr_blocks);
-       struct dm_space_map *smc;
-
-       if (IS_ERR_OR_NULL(sm))
-               return sm;
-
-       smc = dm_sm_checker_create_fresh(sm);
-       if (IS_ERR(smc))
-               dm_sm_destroy(sm);
-
-       return smc;
-}
 EXPORT_SYMBOL_GPL(dm_sm_disk_create);
 
-static struct dm_space_map *dm_sm_disk_open_real(
-       struct dm_transaction_manager *tm,
-       void *root_le, size_t len)
+struct dm_space_map *dm_sm_disk_open(struct dm_transaction_manager *tm,
+                                    void *root_le, size_t len)
 {
        int r;
        struct sm_disk *smd;
@@ -332,13 +313,6 @@ bad:
        kfree(smd);
        return ERR_PTR(r);
 }
-
-struct dm_space_map *dm_sm_disk_open(struct dm_transaction_manager *tm,
-                                    void *root_le, size_t len)
-{
-       return dm_sm_checker_create(
-               dm_sm_disk_open_real(tm, root_le, len));
-}
 EXPORT_SYMBOL_GPL(dm_sm_disk_open);
 
 /*----------------------------------------------------------------*/
index e5604b32d91ff0017a5a625cfd8106fca92bfe19..d247a35da3c63030bca417b89482bb8fdf371cd0 100644 (file)
@@ -5,7 +5,6 @@
  */
 #include "dm-transaction-manager.h"
 #include "dm-space-map.h"
-#include "dm-space-map-checker.h"
 #include "dm-space-map-disk.h"
 #include "dm-space-map-metadata.h"
 #include "dm-persistent-data-internal.h"
@@ -220,13 +219,24 @@ static int __shadow_block(struct dm_transaction_manager *tm, dm_block_t orig,
        if (r < 0)
                return r;
 
-       r = dm_bm_unlock_move(orig_block, new);
-       if (r < 0) {
+       /*
+        * It would be tempting to use dm_bm_unlock_move here, but some
+        * code, such as the space maps, keeps using the old data structures
+        * secure in the knowledge they won't be changed until the next
+        * transaction.  Using unlock_move would force a synchronous read
+        * since the old block would no longer be in the cache.
+        */
+       r = dm_bm_write_lock_zero(tm->bm, new, v, result);
+       if (r) {
                dm_bm_unlock(orig_block);
                return r;
        }
 
-       return dm_bm_write_lock(tm->bm, new, v, result);
+       memcpy(dm_block_data(*result), dm_block_data(orig_block),
+              dm_bm_block_size(tm->bm));
+
+       dm_bm_unlock(orig_block);
+       return r;
 }
 
 int dm_tm_shadow_block(struct dm_transaction_manager *tm, dm_block_t orig,
@@ -311,98 +321,61 @@ struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm)
 
 static int dm_tm_create_internal(struct dm_block_manager *bm,
                                 dm_block_t sb_location,
-                                struct dm_block_validator *sb_validator,
-                                size_t root_offset, size_t root_max_len,
                                 struct dm_transaction_manager **tm,
                                 struct dm_space_map **sm,
-                                struct dm_block **sblock,
-                                int create)
+                                int create,
+                                void *sm_root, size_t sm_len)
 {
        int r;
-       struct dm_space_map *inner;
 
-       inner = dm_sm_metadata_init();
-       if (IS_ERR(inner))
-               return PTR_ERR(inner);
+       *sm = dm_sm_metadata_init();
+       if (IS_ERR(*sm))
+               return PTR_ERR(*sm);
 
-       *tm = dm_tm_create(bm, inner);
+       *tm = dm_tm_create(bm, *sm);
        if (IS_ERR(*tm)) {
-               dm_sm_destroy(inner);
+               dm_sm_destroy(*sm);
                return PTR_ERR(*tm);
        }
 
        if (create) {
-               r = dm_bm_write_lock_zero(dm_tm_get_bm(*tm), sb_location,
-                                         sb_validator, sblock);
-               if (r < 0) {
-                       DMERR("couldn't lock superblock");
-                       goto bad1;
-               }
-
-               r = dm_sm_metadata_create(inner, *tm, dm_bm_nr_blocks(bm),
+               r = dm_sm_metadata_create(*sm, *tm, dm_bm_nr_blocks(bm),
                                          sb_location);
                if (r) {
                        DMERR("couldn't create metadata space map");
-                       goto bad2;
-               }
-
-               *sm = dm_sm_checker_create(inner);
-               if (IS_ERR(*sm)) {
-                       r = PTR_ERR(*sm);
-                       goto bad2;
+                       goto bad;
                }
 
        } else {
-               r = dm_bm_write_lock(dm_tm_get_bm(*tm), sb_location,
-                                    sb_validator, sblock);
-               if (r < 0) {
-                       DMERR("couldn't lock superblock");
-                       goto bad1;
-               }
-
-               r = dm_sm_metadata_open(inner, *tm,
-                                       dm_block_data(*sblock) + root_offset,
-                                       root_max_len);
+               r = dm_sm_metadata_open(*sm, *tm, sm_root, sm_len);
                if (r) {
                        DMERR("couldn't open metadata space map");
-                       goto bad2;
-               }
-
-               *sm = dm_sm_checker_create(inner);
-               if (IS_ERR(*sm)) {
-                       r = PTR_ERR(*sm);
-                       goto bad2;
+                       goto bad;
                }
        }
 
        return 0;
 
-bad2:
-       dm_tm_unlock(*tm, *sblock);
-bad1:
+bad:
        dm_tm_destroy(*tm);
-       dm_sm_destroy(inner);
+       dm_sm_destroy(*sm);
        return r;
 }
 
 int dm_tm_create_with_sm(struct dm_block_manager *bm, dm_block_t sb_location,
-                        struct dm_block_validator *sb_validator,
                         struct dm_transaction_manager **tm,
-                        struct dm_space_map **sm, struct dm_block **sblock)
+                        struct dm_space_map **sm)
 {
-       return dm_tm_create_internal(bm, sb_location, sb_validator,
-                                    0, 0, tm, sm, sblock, 1);
+       return dm_tm_create_internal(bm, sb_location, tm, sm, 1, NULL, 0);
 }
 EXPORT_SYMBOL_GPL(dm_tm_create_with_sm);
 
 int dm_tm_open_with_sm(struct dm_block_manager *bm, dm_block_t sb_location,
-                      struct dm_block_validator *sb_validator,
-                      size_t root_offset, size_t root_max_len,
+                      void *sm_root, size_t root_len,
                       struct dm_transaction_manager **tm,
-                      struct dm_space_map **sm, struct dm_block **sblock)
+                      struct dm_space_map **sm)
 {
-       return dm_tm_create_internal(bm, sb_location, sb_validator, root_offset,
-                                    root_max_len, tm, sm, sblock, 0);
+       return dm_tm_create_internal(bm, sb_location, tm, sm, 0, sm_root, root_len);
 }
 EXPORT_SYMBOL_GPL(dm_tm_open_with_sm);
 
index 6da784871db45edc452dbcc8ba5dd59b61cb8440..b5b139076ca58034b38e80f06c4e5ac9f177f47d 100644 (file)
@@ -115,16 +115,17 @@ struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm);
  *
  * Returns a tm that has an open transaction to write the new disk sm.
  * Caller should store the new sm root and commit.
+ *
+ * The superblock location is passed so the metadata space map knows it
+ * shouldn't be used.
  */
 int dm_tm_create_with_sm(struct dm_block_manager *bm, dm_block_t sb_location,
-                        struct dm_block_validator *sb_validator,
                         struct dm_transaction_manager **tm,
-                        struct dm_space_map **sm, struct dm_block **sblock);
+                        struct dm_space_map **sm);
 
 int dm_tm_open_with_sm(struct dm_block_manager *bm, dm_block_t sb_location,
-                      struct dm_block_validator *sb_validator,
-                      size_t root_offset, size_t root_max_len,
+                      void *sm_root, size_t root_len,
                       struct dm_transaction_manager **tm,
-                      struct dm_space_map **sm, struct dm_block **sblock);
+                      struct dm_space_map **sm);
 
 #endif /* _LINUX_DM_TRANSACTION_MANAGER_H */
index 9575db429df46648c25007a6de5395ef22e080f8..d941581ab92169c935a85754c6fc28d2bc2dd79a 100644 (file)
@@ -6,20 +6,82 @@ menuconfig MEDIA_SUPPORT
        tristate "Multimedia support"
        depends on HAS_IOMEM
        help
-         If you want to use Video for Linux, DVB for Linux, or DAB adapters,
+         If you want to use Webcams, Video grabber devices and/or TV devices
          enable this option and other options below.
+         Additional info and docs are available on the web at
+         <http://linuxtv.org>
 
 if MEDIA_SUPPORT
 
 comment "Multimedia core support"
 
+#
+# Multimedia support - automatically enable V4L2 and DVB core
+#
+config MEDIA_CAMERA_SUPPORT
+       bool "Cameras/video grabbers support"
+       ---help---
+         Enable support for webcams and video grabbers.
+
+         Say Y when you have a webcam or a video capture grabber board.
+
+config MEDIA_ANALOG_TV_SUPPORT
+       bool "Analog TV support"
+       ---help---
+         Enable analog TV support.
+
+         Say Y when you have a TV board with analog support or with a
+         hybrid analog/digital TV chipset.
+
+         Note: There are several DVB cards that are based on chips that
+               support both analog and digital TV. Disabling this option
+               will disable support for them.
+
+config MEDIA_DIGITAL_TV_SUPPORT
+       bool "Digital TV support"
+       ---help---
+         Enable digital TV support.
+
+         Say Y when you have a board with digital support or a board with
+         hybrid digital TV and analog TV.
+
+config MEDIA_RADIO_SUPPORT
+       bool "AM/FM radio receivers/transmitters support"
+       ---help---
+         Enable AM/FM radio support.
+
+         Additional info and docs are available on the web at
+         <http://linuxtv.org>
+
+         Say Y when you have a board with radio support.
+
+         Note: There are several TV cards that are based on chips that
+               support radio reception. Disabling this option will
+               disable support for them.
+
+config MEDIA_RC_SUPPORT
+       bool "Remote Controller support"
+       depends on INPUT
+       ---help---
+         Enable support for Remote Controllers on Linux. This is
+         needed in order to support several video capture adapters,
+         standalone IR receivers/transmitters, and RF receivers.
+
+         Enable this option if you have a video capture board even
+         if you don't need IR, as otherwise, you may not be able to
+         compile the driver for your adapter.
+
+         Say Y when you have a TV or an IR device.
+
 #
 # Media controller
+#      Selectable only for webcam/grabbers, as other drivers don't use it
 #
 
 config MEDIA_CONTROLLER
        bool "Media Controller API (EXPERIMENTAL)"
        depends on EXPERIMENTAL
+       depends on MEDIA_CAMERA_SUPPORT
        ---help---
          Enable the media controller API used to query media devices internal
          topology and configure it dynamically.
@@ -27,26 +89,15 @@ config MEDIA_CONTROLLER
          This API is mostly used by camera interfaces in embedded platforms.
 
 #
-# V4L core and enabled API's
+# Video4Linux support
+#      Only enables if one of the V4L2 types (ATV, webcam, radio) is selected
 #
 
 config VIDEO_DEV
-       tristate "Video For Linux"
-       ---help---
-         V4L core support for video capture and overlay devices, webcams and
-         AM/FM radio cards.
-
-         This kernel includes support for the new Video for Linux Two API,
-         (V4L2).
-
-         Additional info and docs are available on the web at
-         <http://linuxtv.org>
-
-         Documentation for V4L2 is also available on the web at
-         <http://bytesex.org/v4l/>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called videodev.
+       tristate
+       depends on MEDIA_SUPPORT
+       depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT
+       default y
 
 config VIDEO_V4L2_COMMON
        tristate
@@ -64,25 +115,15 @@ config VIDEO_V4L2_SUBDEV_API
 
 #
 # DVB Core
+#      Only enables if one of DTV is selected
 #
 
 config DVB_CORE
-       tristate "DVB for Linux"
+       tristate
+       depends on MEDIA_SUPPORT
+       depends on MEDIA_DIGITAL_TV_SUPPORT
+       default y
        select CRC32
-       help
-         DVB core utility functions for device handling, software fallbacks etc.
-
-         Enable this if you own a DVB/ATSC adapter and want to use it or if
-         you compile Linux for a digital SetTopBox.
-
-         Say Y when you have a DVB or an ATSC card and want to use it.
-
-         API specs and user tools are available from <http://www.linuxtv.org/>.
-
-         Please report problems regarding this support to the LinuxDVB
-         mailing list.
-
-         If unsure say N.
 
 config DVB_NET
        bool "DVB Network Support"
@@ -97,12 +138,7 @@ config DVB_NET
          You may want to disable the network support on embedded devices. If
          unsure say Y.
 
-config VIDEO_MEDIA
-       tristate
-       default (DVB_CORE && (VIDEO_DEV = n)) || (VIDEO_DEV && (DVB_CORE = n)) || (DVB_CORE && VIDEO_DEV)
-
-comment "Multimedia drivers"
-
+comment "Media drivers"
 source "drivers/media/common/Kconfig"
 source "drivers/media/rc/Kconfig"
 
index bbf4945149a9e043c6b995810e7221ebb2828ea0..94c6ff7a5da3ad20bf8f10c5bc08b919153e45e5 100644 (file)
@@ -1,7 +1,8 @@
 config MEDIA_ATTACH
        bool "Load and attach frontend and tuner driver modules as needed"
-       depends on VIDEO_MEDIA
+       depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
        depends on MODULES
+       default y if !EXPERT
        help
          Remove the static dependency of DVB card drivers on all
          frontend modules for all possible card variants. Instead,
@@ -19,15 +20,15 @@ config MEDIA_ATTACH
 
 config MEDIA_TUNER
        tristate
-       default VIDEO_MEDIA && I2C
-       depends on VIDEO_MEDIA && I2C
+       depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT) && I2C
+       default y
        select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
-       select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && EXPERIMENTAL
-       select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT && EXPERIMENTAL
+       select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT
        select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
@@ -47,10 +48,11 @@ config MEDIA_TUNER_CUSTOMISE
 
 menu "Customize TV tuners"
        visible if MEDIA_TUNER_CUSTOMISE
+       depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
 
 config MEDIA_TUNER_SIMPLE
        tristate "Simple tuner support"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        select MEDIA_TUNER_TDA9887
        default m if MEDIA_TUNER_CUSTOMISE
        help
@@ -58,7 +60,7 @@ config MEDIA_TUNER_SIMPLE
 
 config MEDIA_TUNER_TDA8290
        tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        select MEDIA_TUNER_TDA827X
        select MEDIA_TUNER_TDA18271
        default m if MEDIA_TUNER_CUSTOMISE
@@ -67,21 +69,21 @@ config MEDIA_TUNER_TDA8290
 
 config MEDIA_TUNER_TDA827X
        tristate "Philips TDA827X silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A DVB-T silicon tuner module. Say Y when you want to support this tuner.
 
 config MEDIA_TUNER_TDA18271
        tristate "NXP TDA18271 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A silicon tuner module. Say Y when you want to support this tuner.
 
 config MEDIA_TUNER_TDA9887
        tristate "TDA 9885/6/7 analog IF demodulator"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to include support for Philips TDA9885/6/7
@@ -89,7 +91,7 @@ config MEDIA_TUNER_TDA9887
 
 config MEDIA_TUNER_TEA5761
        tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        depends on EXPERIMENTAL
        default m if MEDIA_TUNER_CUSTOMISE
        help
@@ -97,63 +99,63 @@ config MEDIA_TUNER_TEA5761
 
 config MEDIA_TUNER_TEA5767
        tristate "TEA 5767 radio tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to include support for the Philips TEA5767 radio tuner.
 
 config MEDIA_TUNER_MT20XX
        tristate "Microtune 2032 / 2050 tuners"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to include support for the MT2032 / MT2050 tuner.
 
 config MEDIA_TUNER_MT2060
        tristate "Microtune MT2060 silicon IF tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon IF tuner MT2060 from Microtune.
 
 config MEDIA_TUNER_MT2063
        tristate "Microtune MT2063 silicon IF tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon IF tuner MT2063 from Microtune.
 
 config MEDIA_TUNER_MT2266
        tristate "Microtune MT2266 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon baseband tuner MT2266 from Microtune.
 
 config MEDIA_TUNER_MT2131
        tristate "Microtune MT2131 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon baseband tuner MT2131 from Microtune.
 
 config MEDIA_TUNER_QT1010
        tristate "Quantek QT1010 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon tuner QT1010 from Quantek.
 
 config MEDIA_TUNER_XC2028
        tristate "XCeive xc2028/xc3028 tuners"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to include support for the xc2028/xc3028 tuners.
 
 config MEDIA_TUNER_XC5000
        tristate "Xceive XC5000 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon tuner XC5000 from Xceive.
@@ -162,7 +164,7 @@ config MEDIA_TUNER_XC5000
 
 config MEDIA_TUNER_XC4000
        tristate "Xceive XC4000 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon tuner XC4000 from Xceive.
@@ -171,70 +173,70 @@ config MEDIA_TUNER_XC4000
 
 config MEDIA_TUNER_MXL5005S
        tristate "MaxLinear MSL5005S silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon tuner MXL5005S from MaxLinear.
 
 config MEDIA_TUNER_MXL5007T
        tristate "MaxLinear MxL5007T silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon tuner MxL5007T from MaxLinear.
 
 config MEDIA_TUNER_MC44S803
        tristate "Freescale MC44S803 Low Power CMOS Broadband tuners"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the Freescale MC44S803 based tuners
 
 config MEDIA_TUNER_MAX2165
        tristate "Maxim MAX2165 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          A driver for the silicon tuner MAX2165 from Maxim.
 
 config MEDIA_TUNER_TDA18218
        tristate "NXP TDA18218 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          NXP TDA18218 silicon tuner driver.
 
 config MEDIA_TUNER_FC0011
        tristate "Fitipower FC0011 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          Fitipower FC0011 silicon tuner driver.
 
 config MEDIA_TUNER_FC0012
        tristate "Fitipower FC0012 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          Fitipower FC0012 silicon tuner driver.
 
 config MEDIA_TUNER_FC0013
        tristate "Fitipower FC0013 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          Fitipower FC0013 silicon tuner driver.
 
 config MEDIA_TUNER_TDA18212
        tristate "NXP TDA18212 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          NXP TDA18212 silicon tuner driver.
 
 config MEDIA_TUNER_TUA9001
        tristate "Infineon TUA 9001 silicon tuner"
-       depends on VIDEO_MEDIA && I2C
+       depends on MEDIA_SUPPORT && I2C
        default m if MEDIA_TUNER_CUSTOMISE
        help
          Infineon TUA 9001 silicon tuner driver.
index b5ee3ebfcfca03e2f9fd5973cd5d72b52d1c5f53..f88f948efee2e51fd39f2e98d74d696f08924f5b 100644 (file)
@@ -90,11 +90,22 @@ struct firmware_properties {
        int             scode_nr;
 };
 
+enum xc2028_state {
+       XC2028_NO_FIRMWARE = 0,
+       XC2028_WAITING_FIRMWARE,
+       XC2028_ACTIVE,
+       XC2028_SLEEP,
+       XC2028_NODEV,
+};
+
 struct xc2028_data {
        struct list_head        hybrid_tuner_instance_list;
        struct tuner_i2c_props  i2c_props;
        __u32                   frequency;
 
+       enum xc2028_state       state;
+       const char              *fname;
+
        struct firmware_description *firm;
        int                     firm_size;
        __u16                   firm_version;
@@ -255,6 +266,21 @@ static  v4l2_std_id parse_audio_std_option(void)
        return 0;
 }
 
+static int check_device_status(struct xc2028_data *priv)
+{
+       switch (priv->state) {
+       case XC2028_NO_FIRMWARE:
+       case XC2028_WAITING_FIRMWARE:
+               return -EAGAIN;
+       case XC2028_ACTIVE:
+       case XC2028_SLEEP:
+               return 0;
+       case XC2028_NODEV:
+               return -ENODEV;
+       }
+       return 0;
+}
+
 static void free_firmware(struct xc2028_data *priv)
 {
        int i;
@@ -270,45 +296,28 @@ static void free_firmware(struct xc2028_data *priv)
 
        priv->firm = NULL;
        priv->firm_size = 0;
+       priv->state = XC2028_NO_FIRMWARE;
 
        memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
 }
 
-static int load_all_firmwares(struct dvb_frontend *fe)
+static int load_all_firmwares(struct dvb_frontend *fe,
+                             const struct firmware *fw)
 {
        struct xc2028_data    *priv = fe->tuner_priv;
-       const struct firmware *fw   = NULL;
        const unsigned char   *p, *endp;
        int                   rc = 0;
        int                   n, n_array;
        char                  name[33];
-       char                  *fname;
 
        tuner_dbg("%s called\n", __func__);
 
-       if (!firmware_name[0])
-               fname = priv->ctrl.fname;
-       else
-               fname = firmware_name;
-
-       tuner_dbg("Reading firmware %s\n", fname);
-       rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
-       if (rc < 0) {
-               if (rc == -ENOENT)
-                       tuner_err("Error: firmware %s not found.\n",
-                                  fname);
-               else
-                       tuner_err("Error %d while requesting firmware %s \n",
-                                  rc, fname);
-
-               return rc;
-       }
        p = fw->data;
        endp = p + fw->size;
 
        if (fw->size < sizeof(name) - 1 + 2 + 2) {
                tuner_err("Error: firmware file %s has invalid size!\n",
-                         fname);
+                         priv->fname);
                goto corrupt;
        }
 
@@ -323,7 +332,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
        p += 2;
 
        tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
-                  n_array, fname, name,
+                  n_array, priv->fname, name,
                   priv->firm_version >> 8, priv->firm_version & 0xff);
 
        priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
@@ -417,9 +426,10 @@ err:
        free_firmware(priv);
 
 done:
-       release_firmware(fw);
        if (rc == 0)
                tuner_dbg("Firmware files loaded.\n");
+       else
+               priv->state = XC2028_NODEV;
 
        return rc;
 }
@@ -707,22 +717,15 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type,
 {
        struct xc2028_data         *priv = fe->tuner_priv;
        struct firmware_properties new_fw;
-       int                        rc = 0, retry_count = 0;
+       int                        rc, retry_count = 0;
        u16                        version, hwmodel;
        v4l2_std_id                std0;
 
        tuner_dbg("%s called\n", __func__);
 
-       if (!priv->firm) {
-               if (!priv->ctrl.fname) {
-                       tuner_info("xc2028/3028 firmware name not set!\n");
-                       return -EINVAL;
-               }
-
-               rc = load_all_firmwares(fe);
-               if (rc < 0)
-                       return rc;
-       }
+       rc = check_device_status(priv);
+       if (rc < 0)
+               return rc;
 
        if (priv->ctrl.mts && !(type & FM))
                type |= MTS;
@@ -749,9 +752,13 @@ retry:
                printk("scode_nr %d\n", new_fw.scode_nr);
        }
 
-       /* No need to reload base firmware if it matches */
-       if (((BASE | new_fw.type) & BASE_TYPES) ==
-           (priv->cur_fw.type & BASE_TYPES)) {
+       /*
+        * No need to reload base firmware if it matches and if the tuner
+        * is not at sleep mode
+        */
+       if ((priv->state = XC2028_ACTIVE) &&
+           (((BASE | new_fw.type) & BASE_TYPES) ==
+           (priv->cur_fw.type & BASE_TYPES))) {
                tuner_dbg("BASE firmware not changed.\n");
                goto skip_base;
        }
@@ -872,10 +879,13 @@ read_not_reliable:
         * 2. Tell whether BASE firmware was just changed the next time through.
         */
        priv->cur_fw.type |= BASE;
+       priv->state = XC2028_ACTIVE;
 
        return 0;
 
 fail:
+       priv->state = XC2028_SLEEP;
+
        memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
        if (retry_count < 8) {
                msleep(50);
@@ -893,28 +903,39 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
 {
        struct xc2028_data *priv = fe->tuner_priv;
        u16                 frq_lock, signal = 0;
-       int                 rc;
+       int                 rc, i;
 
        tuner_dbg("%s called\n", __func__);
 
+       rc = check_device_status(priv);
+       if (rc < 0)
+               return rc;
+
        mutex_lock(&priv->lock);
 
        /* Sync Lock Indicator */
-       rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
-       if (rc < 0)
-               goto ret;
+       for (i = 0; i < 3; i++) {
+               rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
+               if (rc < 0)
+                       goto ret;
 
-       /* Frequency is locked */
-       if (frq_lock == 1)
-               signal = 1 << 11;
+               if (frq_lock)
+                       break;
+               msleep(6);
+       }
+
+       /* Frequency didn't lock */
+       if (frq_lock == 2)
+               goto ret;
 
        /* Get SNR of the video signal */
        rc = xc2028_get_reg(priv, XREG_SNR, &signal);
        if (rc < 0)
                goto ret;
 
-       /* Use both frq_lock and signal to generate the result */
-       signal = signal || ((signal & 0x07) << 12);
+       /* Signal level is 3 bits only */
+
+       signal = ((1 << 12) - 1) | ((signal & 0x07) << 12);
 
 ret:
        mutex_unlock(&priv->lock);
@@ -926,6 +947,49 @@ ret:
        return rc;
 }
 
+static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       int i, rc;
+       u16 frq_lock = 0;
+       s16 afc_reg = 0;
+
+       rc = check_device_status(priv);
+       if (rc < 0)
+               return rc;
+
+       mutex_lock(&priv->lock);
+
+       /* Sync Lock Indicator */
+       for (i = 0; i < 3; i++) {
+               rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
+               if (rc < 0)
+                       goto ret;
+
+               if (frq_lock)
+                       break;
+               msleep(6);
+       }
+
+       /* Frequency didn't lock */
+       if (frq_lock == 2)
+               goto ret;
+
+       /* Get AFC */
+       rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg);
+       if (rc < 0)
+               return rc;
+
+       *afc = afc_reg * 15625; /* Hz */
+
+       tuner_dbg("AFC is %d Hz\n", *afc);
+
+ret:
+       mutex_unlock(&priv->lock);
+
+       return rc;
+}
+
 #define DIV 15625
 
 static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
@@ -1111,11 +1175,16 @@ static int xc2028_set_params(struct dvb_frontend *fe)
        u32 delsys = c->delivery_system;
        u32 bw = c->bandwidth_hz;
        struct xc2028_data *priv = fe->tuner_priv;
-       unsigned int       type=0;
+       int rc;
+       unsigned int       type = 0;
        u16                demod = 0;
 
        tuner_dbg("%s called\n", __func__);
 
+       rc = check_device_status(priv);
+       if (rc < 0)
+               return rc;
+
        switch (delsys) {
        case SYS_DVBT:
        case SYS_DVBT2:
@@ -1201,7 +1270,11 @@ static int xc2028_set_params(struct dvb_frontend *fe)
 static int xc2028_sleep(struct dvb_frontend *fe)
 {
        struct xc2028_data *priv = fe->tuner_priv;
-       int rc = 0;
+       int rc;
+
+       rc = check_device_status(priv);
+       if (rc < 0)
+               return rc;
 
        /* Avoid firmware reload on slow devices or if PM disabled */
        if (no_poweroff || priv->ctrl.disable_power_mgmt)
@@ -1220,7 +1293,7 @@ static int xc2028_sleep(struct dvb_frontend *fe)
        else
                rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00});
 
-       priv->cur_fw.type = 0;  /* need firmware reload */
+       priv->state = XC2028_SLEEP;
 
        mutex_unlock(&priv->lock);
 
@@ -1237,8 +1310,9 @@ static int xc2028_dvb_release(struct dvb_frontend *fe)
 
        /* only perform final cleanup if this is the last instance */
        if (hybrid_tuner_report_instance_count(priv) == 1) {
-               kfree(priv->ctrl.fname);
                free_firmware(priv);
+               kfree(priv->ctrl.fname);
+               priv->ctrl.fname = NULL;
        }
 
        if (priv)
@@ -1254,14 +1328,42 @@ static int xc2028_dvb_release(struct dvb_frontend *fe)
 static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
        struct xc2028_data *priv = fe->tuner_priv;
+       int rc;
 
        tuner_dbg("%s called\n", __func__);
 
+       rc = check_device_status(priv);
+       if (rc < 0)
+               return rc;
+
        *frequency = priv->frequency;
 
        return 0;
 }
 
+static void load_firmware_cb(const struct firmware *fw,
+                            void *context)
+{
+       struct dvb_frontend *fe = context;
+       struct xc2028_data *priv = fe->tuner_priv;
+       int rc;
+
+       tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error");
+       if (!fw) {
+               tuner_err("Could not load firmware %s.\n", priv->fname);
+               priv->state = XC2028_NODEV;
+               return;
+       }
+
+       rc = load_all_firmwares(fe, fw);
+
+       release_firmware(fw);
+
+       if (rc < 0)
+               return;
+       priv->state = XC2028_SLEEP;
+}
+
 static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
 {
        struct xc2028_data *priv = fe->tuner_priv;
@@ -1272,21 +1374,49 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
 
        mutex_lock(&priv->lock);
 
+       /*
+        * Copy the config data.
+        * For the firmware name, keep a local copy of the string,
+        * in order to avoid troubles during device release.
+        */
+       if (priv->ctrl.fname)
+               kfree(priv->ctrl.fname);
        memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
-       if (priv->ctrl.max_len < 9)
-               priv->ctrl.max_len = 13;
-
        if (p->fname) {
-               if (priv->ctrl.fname && strcmp(p->fname, priv->ctrl.fname)) {
-                       kfree(priv->ctrl.fname);
-                       free_firmware(priv);
-               }
-
                priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
                if (priv->ctrl.fname == NULL)
                        rc = -ENOMEM;
        }
 
+       /*
+        * If firmware name changed, frees firmware. As free_firmware will
+        * reset the status to NO_FIRMWARE, this forces a new request_firmware
+        */
+       if (!firmware_name[0] && p->fname &&
+           priv->fname && strcmp(p->fname, priv->fname))
+               free_firmware(priv);
+
+       if (priv->ctrl.max_len < 9)
+               priv->ctrl.max_len = 13;
+
+       if (priv->state == XC2028_NO_FIRMWARE) {
+               if (!firmware_name[0])
+                       priv->fname = priv->ctrl.fname;
+               else
+                       priv->fname = firmware_name;
+
+               rc = request_firmware_nowait(THIS_MODULE, 1,
+                                            priv->fname,
+                                            priv->i2c_props.adap->dev.parent,
+                                            GFP_KERNEL,
+                                            fe, load_firmware_cb);
+               if (rc < 0) {
+                       tuner_err("Failed to request firmware %s\n",
+                                 priv->fname);
+                       priv->state = XC2028_NODEV;
+               }
+               priv->state = XC2028_WAITING_FIRMWARE;
+       }
        mutex_unlock(&priv->lock);
 
        return rc;
@@ -1305,6 +1435,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
        .release           = xc2028_dvb_release,
        .get_frequency     = xc2028_get_frequency,
        .get_rf_strength   = xc2028_signal,
+       .get_afc           = xc2028_get_afc,
        .set_params        = xc2028_set_params,
        .sleep             = xc2028_sleep,
 };
@@ -1375,3 +1506,5 @@ MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
 MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE);
+MODULE_FIRMWARE(XC3028L_DEFAULT_FIRMWARE);
index dcca42ca57bef312cb84fb059f88a315da385092..bac8009e1d4979680211fddcd8a06e7c71a4e23c 100644 (file)
@@ -717,6 +717,12 @@ static int xc5000_set_params(struct dvb_frontend *fe)
                priv->freq_hz = freq - 1750000;
                priv->video_standard = DTV6;
                break;
+       case SYS_ISDBT:
+               /* All ISDB-T are currently for 6 MHz bw */
+               if (!bw)
+                       bw = 6000000;
+               /* fall to OFDM handling */
+       case SYS_DMBTH:
        case SYS_DVBT:
        case SYS_DVBT2:
                dprintk(1, "%s() OFDM\n", __func__);
index 131b938e9e8178384ab90fa206165c2d20861582..ebf3f05839d2c5416488b77df70c825dc01ae467 100644 (file)
@@ -578,6 +578,7 @@ static int demod_attach_drxk(struct ddb_input *input)
 
        memset(&config, 0, sizeof(config));
        config.microcode_name = "drxk_a3.mc";
+       config.qam_demod_parameter_count = 4;
        config.adr = 0x29 + (input->nr & 1);
 
        fe = input->fe = dvb_attach(drxk_attach, &config, i2c);
index e929d5697b8799bb8597d09dd620dc510dd282dc..7c64c09103a94d1e15f7b57c32ae21da4720e716 100644 (file)
@@ -220,6 +220,7 @@ struct dvb_tuner_ops {
 #define TUNER_STATUS_STEREO 2
        int (*get_status)(struct dvb_frontend *fe, u32 *status);
        int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
+       int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
 
        /** These are provided separately from set_params in order to facilitate silicon
         * tuners which require sophisticated tuning loops, controlling each parameter separately. */
index a26949336b3d310e1b78b48ada7e902f2f84e7fb..c2161565023a4682d0ba77a5e5b681491b8a31c4 100644 (file)
@@ -418,9 +418,12 @@ config DVB_USB_RTL28XXU
        tristate "Realtek RTL28xxU DVB USB support"
        depends on DVB_USB && EXPERIMENTAL
        select DVB_RTL2830
+       select DVB_RTL2832
        select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_FC0013 if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the Realtek RTL28xxU DVB USB receiver.
 
index 4008b9c50fbdfa3a9b61853d2a1a7bf86be90ae6..8ffcad000ad3fb146eb7a1e5292dc902a4745a28 100644 (file)
@@ -593,9 +593,7 @@ static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
        memcpy(mac, st->data, sizeof(mac));
 
        if (ret > 0)
-               deb_info("%s: mac is %02x:%02x:%02x:%02x:%02x:%02x\n",
-                        __func__, mac[0], mac[1], mac[2],
-                        mac[3], mac[4], mac[5]);
+               deb_info("%s: mac is %pM\n", __func__, mac);
 
        return ret;
 }
index 7a6160bf54baeaf652aa86b8156d48fc326279ee..26c44818a5abf23d96f344fd0e83de75b20a47b4 100644 (file)
 #define USB_PID_CONCEPTRONIC_CTVDIGRCU                 0xe397
 #define USB_PID_CONEXANT_D680_DMB                      0x86d6
 #define USB_PID_CREATIX_CTX1921                                0x1921
+#define USB_PID_DELOCK_USB2_DVBT                       0xb803
 #define USB_PID_DIBCOM_HOOK_DEFAULT                    0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM             0x0065
 #define USB_PID_DIBCOM_MOD3000_COLD                    0x0bb8
 #define USB_PID_TERRATEC_CINERGY_T_STICK               0x0093
 #define USB_PID_TERRATEC_CINERGY_T_STICK_RC            0x0097
 #define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC       0x0099
+#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1    0x00a9
 #define USB_PID_TWINHAN_VP7041_COLD                    0x3201
 #define USB_PID_TWINHAN_VP7041_WARM                    0x3202
 #define USB_PID_TWINHAN_VP7020_COLD                    0x3203
 #define USB_PID_TERRATEC_H7_2                          0x10a3
 #define USB_PID_TERRATEC_T3                            0x10a0
 #define USB_PID_TERRATEC_T5                            0x10a1
+#define USB_PID_NOXON_DAB_STICK                                0x00b3
 #define USB_PID_PINNACLE_EXPRESSCARD_320CX             0x022e
 #define USB_PID_PINNACLE_PCTV2000E                     0x022c
 #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH              0x0228
index 41e1f5537f44b5b67d31140f52fec2f9cc25224b..6bd0bd792437d38c2fd769470ddaa3a943f49016 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
  * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.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
 #include "rtl28xxu.h"
 
 #include "rtl2830.h"
+#include "rtl2832.h"
 
 #include "qt1010.h"
 #include "mt2060.h"
 #include "mxl5005s.h"
+#include "fc0012.h"
+#include "fc0013.h"
 
 /* debug */
 static int dvb_usb_rtl28xxu_debug;
@@ -80,7 +84,7 @@ err:
        return ret;
 }
 
-static int rtl2831_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
+static int rtl28xx_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
 {
        struct rtl28xxu_req req;
 
@@ -116,12 +120,12 @@ static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
        return rtl28xxu_ctrl_msg(d, &req);
 }
 
-static int rtl2831_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
+static int rtl28xx_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
 {
-       return rtl2831_wr_regs(d, reg, &val, 1);
+       return rtl28xx_wr_regs(d, reg, &val, 1);
 }
 
-static int rtl2831_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
+static int rtl28xx_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
 {
        return rtl2831_rd_regs(d, reg, val, 1);
 }
@@ -308,12 +312,12 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
         */
 
        /* GPIO direction */
-       ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
+       ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
        if (ret)
                goto err;
 
        /* enable as output GPIO0, GPIO2, GPIO4 */
-       ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
+       ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
        if (ret)
                goto err;
 
@@ -381,34 +385,159 @@ err:
        return ret;
 }
 
+static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
+       .i2c_addr = 0x10, /* 0x20 */
+       .xtal = 28800000,
+       .if_dvbt = 0,
+       .tuner = TUNER_RTL2832_FC0012
+};
+
+static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
+       .i2c_addr = 0x10, /* 0x20 */
+       .xtal = 28800000,
+       .if_dvbt = 0,
+       .tuner = TUNER_RTL2832_FC0013
+};
+
+static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
+               int cmd, int arg)
+{
+       int ret;
+       u8 val;
+
+       deb_info("%s cmd=%d arg=%d\n", __func__, cmd, arg);
+       switch (cmd) {
+       case FC_FE_CALLBACK_VHF_ENABLE:
+               /* set output values */
+               ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+               if (ret)
+                       goto err;
+
+               if (arg)
+                       val &= 0xbf; /* set GPIO6 low */
+               else
+                       val |= 0x40; /* set GPIO6 high */
+
+
+               ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+               if (ret)
+                       goto err;
+               break;
+       default:
+               ret = -EINVAL;
+               goto err;
+       }
+       return 0;
+
+err:
+       err("%s: failed=%d\n", __func__, ret);
+
+       return ret;
+}
+
+
+static int rtl2832u_fc0013_tuner_callback(struct dvb_usb_device *d,
+               int cmd, int arg)
+{
+       /* TODO implement*/
+       return 0;
+}
+
+static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
+{
+       struct rtl28xxu_priv *priv = d->priv;
+
+       switch (priv->tuner) {
+       case TUNER_RTL2832_FC0012:
+               return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
+
+       case TUNER_RTL2832_FC0013:
+               return rtl2832u_fc0013_tuner_callback(d, cmd, arg);
+       default:
+               break;
+       }
+
+       return -ENODEV;
+}
+
+static int rtl2832u_frontend_callback(void *adapter_priv, int component,
+                                   int cmd, int arg)
+{
+       struct i2c_adapter *adap = adapter_priv;
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+
+       switch (component) {
+       case DVB_FRONTEND_COMPONENT_TUNER:
+               return rtl2832u_tuner_callback(d, cmd, arg);
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+
+
+
 static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
 {
        int ret;
        struct rtl28xxu_priv *priv = adap->dev->priv;
-       u8 buf[1];
+       struct rtl2832_config *rtl2832_config;
+
+       u8 buf[2], val;
        /* open RTL2832U/RTL2832 I2C gate */
        struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
        /* close RTL2832U/RTL2832 I2C gate */
        struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
+       /* for FC0012 tuner probe */
+       struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
+       /* for FC0013 tuner probe */
+       struct rtl28xxu_req req_fc0013 = {0x00c6, CMD_I2C_RD, 1, buf};
+       /* for MT2266 tuner probe */
+       struct rtl28xxu_req req_mt2266 = {0x00c0, CMD_I2C_RD, 1, buf};
        /* for FC2580 tuner probe */
        struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
+       /* for MT2063 tuner probe */
+       struct rtl28xxu_req req_mt2063 = {0x00c0, CMD_I2C_RD, 1, buf};
+       /* for MAX3543 tuner probe */
+       struct rtl28xxu_req req_max3543 = {0x00c0, CMD_I2C_RD, 1, buf};
+       /* for TUA9001 tuner probe */
+       struct rtl28xxu_req req_tua9001 = {0x7ec0, CMD_I2C_RD, 2, buf};
+       /* for MXL5007T tuner probe */
+       struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf};
+       /* for E4000 tuner probe */
+       struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
+       /* for TDA18272 tuner probe */
+       struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
 
        deb_info("%s:\n", __func__);
 
-       /* GPIO direction */
-       ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
+
+       ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_DIR, &val);
        if (ret)
                goto err;
 
-       /* enable as output GPIO0, GPIO2, GPIO4 */
-       ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
+       val &= 0xbf;
+
+       ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_DIR, val);
        if (ret)
                goto err;
 
-       ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8);
+
+       /* enable as output GPIO3 and GPIO6*/
+       ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_OUT_EN, &val);
        if (ret)
                goto err;
 
+       val |= 0x48;
+
+       ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_EN, val);
+       if (ret)
+               goto err;
+
+
+
        /*
         * Probe used tuner. We need to know used tuner before demod attach
         * since there is some demod params needed to set according to tuner.
@@ -419,25 +548,108 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
        if (ret)
                goto err;
 
+       priv->tuner = TUNER_NONE;
+
+       /* check FC0012 ID register; reg=00 val=a1 */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0012);
+       if (ret == 0 && buf[0] == 0xa1) {
+               priv->tuner = TUNER_RTL2832_FC0012;
+               rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
+               info("%s: FC0012 tuner found", __func__);
+               goto found;
+       }
+
+       /* check FC0013 ID register; reg=00 val=a3 */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0013);
+       if (ret == 0 && buf[0] == 0xa3) {
+               priv->tuner = TUNER_RTL2832_FC0013;
+               rtl2832_config = &rtl28xxu_rtl2832_fc0013_config;
+               info("%s: FC0013 tuner found", __func__);
+               goto found;
+       }
+
+       /* check MT2266 ID register; reg=00 val=85 */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2266);
+       if (ret == 0 && buf[0] == 0x85) {
+               priv->tuner = TUNER_RTL2832_MT2266;
+               /* TODO implement tuner */
+               info("%s: MT2266 tuner found", __func__);
+               goto unsupported;
+       }
+
        /* check FC2580 ID register; reg=01 val=56 */
        ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580);
        if (ret == 0 && buf[0] == 0x56) {
                priv->tuner = TUNER_RTL2832_FC2580;
-               deb_info("%s: FC2580\n", __func__);
-               goto found;
-       } else {
-               deb_info("%s: FC2580 probe failed=%d - %02x\n",
-                       __func__, ret, buf[0]);
+               /* TODO implement tuner */
+               info("%s: FC2580 tuner found", __func__);
+               goto unsupported;
        }
 
+       /* check MT2063 ID register; reg=00 val=9e || 9c */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2063);
+       if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) {
+               priv->tuner = TUNER_RTL2832_MT2063;
+               /* TODO implement tuner */
+               info("%s: MT2063 tuner found", __func__);
+               goto unsupported;
+       }
+
+       /* check MAX3543 ID register; reg=00 val=38 */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_max3543);
+       if (ret == 0 && buf[0] == 0x38) {
+               priv->tuner = TUNER_RTL2832_MAX3543;
+               /* TODO implement tuner */
+               info("%s: MAX3534 tuner found", __func__);
+               goto unsupported;
+       }
+
+       /* check TUA9001 ID register; reg=7e val=2328 */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_tua9001);
+       if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) {
+               priv->tuner = TUNER_RTL2832_TUA9001;
+               /* TODO implement tuner */
+               info("%s: TUA9001 tuner found", __func__);
+               goto unsupported;
+       }
+
+       /* check MXL5007R ID register; reg=d9 val=14 */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_mxl5007t);
+       if (ret == 0 && buf[0] == 0x14) {
+               priv->tuner = TUNER_RTL2832_MXL5007T;
+               /* TODO implement tuner */
+               info("%s: MXL5007T tuner found", __func__);
+               goto unsupported;
+       }
+
+       /* check E4000 ID register; reg=02 val=40 */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_e4000);
+       if (ret == 0 && buf[0] == 0x40) {
+               priv->tuner = TUNER_RTL2832_E4000;
+               /* TODO implement tuner */
+               info("%s: E4000 tuner found", __func__);
+               goto unsupported;
+       }
+
+       /* check TDA18272 ID register; reg=00 val=c760  */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_tda18272);
+       if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) {
+               priv->tuner = TUNER_RTL2832_TDA18272;
+               /* TODO implement tuner */
+               info("%s: TDA18272 tuner found", __func__);
+               goto unsupported;
+       }
+
+unsupported:
        /* close demod I2C gate */
        ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
        if (ret)
                goto err;
 
        /* tuner not found */
+       deb_info("No compatible tuner found");
        ret = -ENODEV;
-       goto err;
+       return ret;
 
 found:
        /* close demod I2C gate */
@@ -446,9 +658,18 @@ found:
                goto err;
 
        /* attach demodulator */
-       /* TODO: */
+       adap->fe_adap[0].fe = dvb_attach(rtl2832_attach, rtl2832_config,
+               &adap->dev->i2c_adap);
+               if (adap->fe_adap[0].fe == NULL) {
+                       ret = -ENODEV;
+                       goto err;
+               }
+
+       /* set fe callbacks */
+       adap->fe_adap[0].fe->callback = rtl2832u_frontend_callback;
 
        return ret;
+
 err:
        deb_info("%s: failed=%d\n", __func__, ret);
        return ret;
@@ -531,10 +752,24 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
        deb_info("%s:\n", __func__);
 
        switch (priv->tuner) {
-       case TUNER_RTL2832_FC2580:
-               /* TODO: */
-               fe = NULL;
+       case TUNER_RTL2832_FC0012:
+               fe = dvb_attach(fc0012_attach, adap->fe_adap[0].fe,
+                       &adap->dev->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
+
+               /* since fc0012 includs reading the signal strength delegate
+                * that to the tuner driver */
+               adap->fe_adap[0].fe->ops.read_signal_strength = adap->fe_adap[0].
+                               fe->ops.tuner_ops.get_rf_strength;
+               return 0;
                break;
+       case TUNER_RTL2832_FC0013:
+               fe = dvb_attach(fc0013_attach, adap->fe_adap[0].fe,
+                       &adap->dev->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
+
+               /* fc0013 also supports signal strength reading */
+               adap->fe_adap[0].fe->ops.read_signal_strength = adap->fe_adap[0]
+                       .fe->ops.tuner_ops.get_rf_strength;
+               return 0;
        default:
                fe = NULL;
                err("unknown tuner=%d", priv->tuner);
@@ -551,14 +786,14 @@ err:
        return ret;
 }
 
-static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
+static int rtl2831u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
 {
        int ret;
        u8 buf[2], gpio;
 
        deb_info("%s: onoff=%d\n", __func__, onoff);
 
-       ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio);
+       ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio);
        if (ret)
                goto err;
 
@@ -572,11 +807,37 @@ static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
                gpio &= (~0x04); /* LED off */
        }
 
-       ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio);
+       ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio);
        if (ret)
                goto err;
 
-       ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
+       ret = rtl28xx_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
+       if (ret)
+               goto err;
+
+       return ret;
+err:
+       deb_info("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int rtl2832u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
+{
+       int ret;
+       u8 buf[2];
+
+       deb_info("%s: onoff=%d\n", __func__, onoff);
+
+
+       if (onoff) {
+               buf[0] = 0x00;
+               buf[1] = 0x00;
+       } else {
+               buf[0] = 0x10; /* stall EPA */
+               buf[1] = 0x02; /* reset EPA */
+       }
+
+       ret = rtl28xx_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
        if (ret)
                goto err;
 
@@ -586,7 +847,7 @@ err:
        return ret;
 }
 
-static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
+static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
        int ret;
        u8 gpio, sys0;
@@ -594,12 +855,12 @@ static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
        deb_info("%s: onoff=%d\n", __func__, onoff);
 
        /* demod adc */
-       ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0);
+       ret = rtl28xx_rd_reg(d, SYS_SYS0, &sys0);
        if (ret)
                goto err;
 
        /* tuner power, read GPIOs */
-       ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio);
+       ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio);
        if (ret)
                goto err;
 
@@ -619,12 +880,12 @@ static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
        deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
 
        /* demod adc */
-       ret = rtl2831_wr_reg(d, SYS_SYS0, sys0);
+       ret = rtl28xx_wr_reg(d, SYS_SYS0, sys0);
        if (ret)
                goto err;
 
        /* tuner power, write GPIOs */
-       ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, gpio);
+       ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, gpio);
        if (ret)
                goto err;
 
@@ -634,6 +895,128 @@ err:
        return ret;
 }
 
+static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       int ret;
+       u8 val;
+
+       deb_info("%s: onoff=%d\n", __func__, onoff);
+
+       if (onoff) {
+               /* set output values */
+               ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+               if (ret)
+                       goto err;
+
+               val |= 0x08;
+               val &= 0xef;
+
+               ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+               if (ret)
+                       goto err;
+
+               /* demod_ctl_1 */
+               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
+               if (ret)
+                       goto err;
+
+               val &= 0xef;
+
+               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
+               if (ret)
+                       goto err;
+
+               /* demod control */
+               /* PLL enable */
+               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+               if (ret)
+                       goto err;
+
+               /* bit 7 to 1 */
+               val |= 0x80;
+
+               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+               if (ret)
+                       goto err;
+
+               /* demod HW reset */
+               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+               if (ret)
+                       goto err;
+               /* bit 5 to 0 */
+               val &= 0xdf;
+
+               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+               if (ret)
+                       goto err;
+
+               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+               if (ret)
+                       goto err;
+
+               val |= 0x20;
+
+               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+               if (ret)
+                       goto err;
+
+               mdelay(5);
+
+               /*enable ADC_Q and ADC_I */
+               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+               if (ret)
+                       goto err;
+
+               val |= 0x48;
+
+               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+               if (ret)
+                       goto err;
+
+
+       } else {
+               /* demod_ctl_1 */
+               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
+               if (ret)
+                       goto err;
+
+               val |= 0x0c;
+
+               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
+               if (ret)
+                       goto err;
+
+               /* set output values */
+               ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+               if (ret)
+                               goto err;
+
+               val |= 0x10;
+
+               ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+               if (ret)
+                       goto err;
+
+               /* demod control */
+               ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val);
+               if (ret)
+                       goto err;
+
+               val &= 0x37;
+
+               ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val);
+               if (ret)
+                       goto err;
+
+       }
+
+       return ret;
+err:
+       deb_info("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+
 static int rtl2831u_rc_query(struct dvb_usb_device *d)
 {
        int ret, i;
@@ -660,7 +1043,7 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
        /* init remote controller */
        if (!priv->rc_active) {
                for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
-                       ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg,
+                       ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg,
                                        rc_nec_tab[i].val);
                        if (ret)
                                goto err;
@@ -690,12 +1073,12 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
 
                rc_keydown(d->rc_dev, rc_code, 0);
 
-               ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1);
+               ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
                if (ret)
                        goto err;
 
                /* repeated intentionally to avoid extra keypress */
-               ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1);
+               ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
                if (ret)
                        goto err;
        }
@@ -732,7 +1115,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
        /* init remote controller */
        if (!priv->rc_active) {
                for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
-                       ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg,
+                       ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg,
                                        rc_nec_tab[i].val);
                        if (ret)
                                goto err;
@@ -740,14 +1123,14 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
                priv->rc_active = true;
        }
 
-       ret = rtl2831_rd_reg(d, IR_RX_IF, &buf[0]);
+       ret = rtl28xx_rd_reg(d, IR_RX_IF, &buf[0]);
        if (ret)
                goto err;
 
        if (buf[0] != 0x83)
                goto exit;
 
-       ret = rtl2831_rd_reg(d, IR_RX_BC, &buf[0]);
+       ret = rtl28xx_rd_reg(d, IR_RX_BC, &buf[0]);
        if (ret)
                goto err;
 
@@ -756,9 +1139,9 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
 
        /* TODO: pass raw IR to Kernel IR decoder */
 
-       ret = rtl2831_wr_reg(d, IR_RX_IF, 0x03);
-       ret = rtl2831_wr_reg(d, IR_RX_BUF_CTRL, 0x80);
-       ret = rtl2831_wr_reg(d, IR_RX_CTRL, 0x80);
+       ret = rtl28xx_wr_reg(d, IR_RX_IF, 0x03);
+       ret = rtl28xx_wr_reg(d, IR_RX_BUF_CTRL, 0x80);
+       ret = rtl28xx_wr_reg(d, IR_RX_CTRL, 0x80);
 
 exit:
        return ret;
@@ -771,6 +1154,9 @@ enum rtl28xxu_usb_table_entry {
        RTL2831U_0BDA_2831,
        RTL2831U_14AA_0160,
        RTL2831U_14AA_0161,
+       RTL2832U_0CCD_00A9,
+       RTL2832U_1F4D_B803,
+       RTL2832U_0CCD_00B3,
 };
 
 static struct usb_device_id rtl28xxu_table[] = {
@@ -783,6 +1169,12 @@ static struct usb_device_id rtl28xxu_table[] = {
                USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)},
 
        /* RTL2832U */
+       [RTL2832U_0CCD_00A9] = {
+               USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1)},
+       [RTL2832U_1F4D_B803] = {
+               USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT)},
+       [RTL2832U_0CCD_00B3] = {
+               USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK)},
        {} /* terminating entry */
 };
 
@@ -805,7 +1197,7 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
                                        {
                                                .frontend_attach = rtl2831u_frontend_attach,
                                                .tuner_attach    = rtl2831u_tuner_attach,
-                                               .streaming_ctrl  = rtl28xxu_streaming_ctrl,
+                                               .streaming_ctrl  = rtl2831u_streaming_ctrl,
                                                .stream = {
                                                        .type = USB_BULK,
                                                        .count = 6,
@@ -821,7 +1213,7 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
                        }
                },
 
-               .power_ctrl = rtl28xxu_power_ctrl,
+               .power_ctrl = rtl2831u_power_ctrl,
 
                .rc.core = {
                        .protocol       = RC_TYPE_NEC,
@@ -867,7 +1259,7 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
                                        {
                                                .frontend_attach = rtl2832u_frontend_attach,
                                                .tuner_attach    = rtl2832u_tuner_attach,
-                                               .streaming_ctrl  = rtl28xxu_streaming_ctrl,
+                                               .streaming_ctrl  = rtl2832u_streaming_ctrl,
                                                .stream = {
                                                        .type = USB_BULK,
                                                        .count = 6,
@@ -883,7 +1275,7 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
                        }
                },
 
-               .power_ctrl = rtl28xxu_power_ctrl,
+               .power_ctrl = rtl2832u_power_ctrl,
 
                .rc.core = {
                        .protocol       = RC_TYPE_NEC,
@@ -896,10 +1288,25 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
 
                .i2c_algo = &rtl28xxu_i2c_algo,
 
-               .num_device_descs = 0, /* disabled as no support for RTL2832 */
+               .num_device_descs = 3,
                .devices = {
                        {
-                               .name = "Realtek RTL2832U reference design",
+                               .name = "Terratec Cinergy T Stick Black",
+                               .warm_ids = {
+                                       &rtl28xxu_table[RTL2832U_0CCD_00A9],
+                               },
+                       },
+                       {
+                               .name = "G-Tek Electronics Group Lifeview LV5TDLX DVB-T",
+                               .warm_ids = {
+                                       &rtl28xxu_table[RTL2832U_1F4D_B803],
+                               },
+                       },
+                       {
+                               .name = "NOXON DAB/DAB+ USB dongle",
+                               .warm_ids = {
+                                       &rtl28xxu_table[RTL2832U_0CCD_00B3],
+                               },
                        },
                }
        },
@@ -910,6 +1317,7 @@ static int rtl28xxu_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
        int ret, i;
+       u8 val;
        int properties_count = ARRAY_SIZE(rtl28xxu_properties);
        struct dvb_usb_device *d;
        struct usb_device *udev;
@@ -954,16 +1362,25 @@ static int rtl28xxu_probe(struct usb_interface *intf,
        if (ret)
                goto err;
 
+
        /* init USB endpoints */
-       ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09);
+       ret = rtl28xx_rd_reg(d, USB_SYSCTL_0, &val);
+       if (ret)
+                       goto err;
+
+       /* enable DMA and Full Packet Mode*/
+       val |= 0x09;
+       ret = rtl28xx_wr_reg(d, USB_SYSCTL_0, val);
        if (ret)
                goto err;
 
-       ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
+       /* set EPA maximum packet size to 0x0200 */
+       ret = rtl28xx_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
        if (ret)
                goto err;
 
-       ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
+       /* change EPA FIFO length */
+       ret = rtl28xx_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
        if (ret)
                goto err;
 
@@ -1007,4 +1424,5 @@ module_exit(rtl28xxu_module_exit);
 
 MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_AUTHOR("Thomas Mair <thomas.mair86@googlemail.com>");
 MODULE_LICENSE("GPL");
index b98ebb264e2967feef670656392fd0b3e1afb996..a08c2152d0eeb98c591278731f140a02cc244b03 100644 (file)
@@ -1,6 +1,7 @@
 config DVB_FE_CUSTOMISE
        bool "Customise the frontend modules to build"
        depends on DVB_CORE
+       depends on EXPERT
        default y if EXPERT
        help
          This allows the user to select/deselect frontend drivers for their
@@ -432,6 +433,13 @@ config DVB_RTL2830
        help
          Say Y when you want to support this frontend.
 
+config DVB_RTL2832
+       tristate "Realtek RTL2832 DVB-T"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         Say Y when you want to support this frontend.
+
 comment "DVB-C (cable) frontends"
        depends on DVB_CORE
 
index cd1ac2fd577447b46a2d6b35440014175af70cb7..185bb8b51952ec0190aa4a35c2c0bd0cbfbef42e 100644 (file)
@@ -99,6 +99,7 @@ obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o
 obj-$(CONFIG_DVB_A8293) += a8293.o
 obj-$(CONFIG_DVB_TDA10071) += tda10071.o
 obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
+obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
 obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
 obj-$(CONFIG_DVB_AF9033) += af9033.o
 
index bb56497e940a543ff0c710e65e1b6bee496b29d6..cff44a389b404c1c492fe7e25d7925a29b076d05 100644 (file)
 #include "dvb_frontend.h"
 #include "a8293.h"
 
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-#define LOG_PREFIX "a8293"
-
-#undef dbg
-#define dbg(f, arg...) \
-       if (debug) \
-               printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
-#undef err
-#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
-#undef info
-#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
-#undef warn
-#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
-
-
 struct a8293_priv {
        struct i2c_adapter *i2c;
        const struct a8293_config *cfg;
@@ -65,7 +47,8 @@ static int a8293_i2c(struct a8293_priv *priv, u8 *val, int len, bool rd)
        if (ret == 1) {
                ret = 0;
        } else {
-               warn("i2c failed=%d rd=%d", ret, rd);
+               dev_warn(&priv->i2c->dev, "%s: i2c failed=%d rd=%d\n",
+                               KBUILD_MODNAME, ret, rd);
                ret = -EREMOTEIO;
        }
 
@@ -88,7 +71,8 @@ static int a8293_set_voltage(struct dvb_frontend *fe,
        struct a8293_priv *priv = fe->sec_priv;
        int ret;
 
-       dbg("%s: fe_sec_voltage=%d", __func__, fe_sec_voltage);
+       dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__,
+                       fe_sec_voltage);
 
        switch (fe_sec_voltage) {
        case SEC_VOLTAGE_OFF:
@@ -114,14 +98,12 @@ static int a8293_set_voltage(struct dvb_frontend *fe,
 
        return ret;
 err:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
 static void a8293_release_sec(struct dvb_frontend *fe)
 {
-       dbg("%s:", __func__);
-
        a8293_set_voltage(fe, SEC_VOLTAGE_OFF);
 
        kfree(fe->sec_priv);
@@ -154,7 +136,7 @@ struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
 
        /* ENB=0 */
        priv->reg[0] = 0x10;
-       ret = a8293_wr(priv, &priv->reg[1], 1);
+       ret = a8293_wr(priv, &priv->reg[0], 1);
        if (ret)
                goto err;
 
@@ -164,16 +146,17 @@ struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
        if (ret)
                goto err;
 
-       info("Allegro A8293 SEC attached.");
-
        fe->ops.release_sec = a8293_release_sec;
 
        /* override frontend ops */
        fe->ops.set_voltage = a8293_set_voltage;
 
+       dev_info(&priv->i2c->dev, "%s: Allegro A8293 SEC attached\n",
+                       KBUILD_MODNAME);
+
        return fe;
 err:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
        kfree(priv);
        return NULL;
 }
index 9d64e4fea066818969ad54a39a7eff03a6e368c2..d615d7d055a29dfba39b3fd6e9879830cd96a080 100644 (file)
  *                     means that 1=DVBC, 0 = DVBT. Zero means the opposite.
  * @mpeg_out_clk_strength: DRXK Mpeg output clock drive strength.
  * @microcode_name:    Name of the firmware file with the microcode
+ * @qam_demod_parameter_count: The number of parameters used for the command
+ *                             to set the demodulator parameters. All
+ *                             firmwares are using the 2-parameter commmand.
+ *                             An exception is the "drxk_a3.mc" firmware,
+ *                             which uses the 4-parameter command.
+ *                             A value of 0 (default) or lower indicates that
+ *                             the correct number of parameters will be
+ *                             automatically detected.
  *
  * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is
  * UIO-3.
@@ -38,7 +46,8 @@ struct drxk_config {
        u8      mpeg_out_clk_strength;
        int     chunk_size;
 
-       const char *microcode_name;
+       const char      *microcode_name;
+       int              qam_demod_parameter_count;
 };
 
 #if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \
index 60b868faeacfaf372f617ae31885727f701faa32..1ab8154542daebc056912efbdb7866bedae7304d 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/i2c.h>
+#include <linux/hardirq.h>
 #include <asm/div64.h>
 
 #include "dvb_frontend.h"
@@ -308,16 +309,42 @@ static u32 Log10Times100(u32 x)
 /* I2C **********************************************************************/
 /****************************************************************************/
 
-static int i2c_read1(struct i2c_adapter *adapter, u8 adr, u8 *val)
+static int drxk_i2c_lock(struct drxk_state *state)
+{
+       i2c_lock_adapter(state->i2c);
+       state->drxk_i2c_exclusive_lock = true;
+
+       return 0;
+}
+
+static void drxk_i2c_unlock(struct drxk_state *state)
+{
+       if (!state->drxk_i2c_exclusive_lock)
+               return;
+
+       i2c_unlock_adapter(state->i2c);
+       state->drxk_i2c_exclusive_lock = false;
+}
+
+static int drxk_i2c_transfer(struct drxk_state *state, struct i2c_msg *msgs,
+                            unsigned len)
+{
+       if (state->drxk_i2c_exclusive_lock)
+               return __i2c_transfer(state->i2c, msgs, len);
+       else
+               return i2c_transfer(state->i2c, msgs, len);
+}
+
+static int i2c_read1(struct drxk_state *state, u8 adr, u8 *val)
 {
        struct i2c_msg msgs[1] = { {.addr = adr, .flags = I2C_M_RD,
                                    .buf = val, .len = 1}
        };
 
-       return i2c_transfer(adapter, msgs, 1);
+       return drxk_i2c_transfer(state, msgs, 1);
 }
 
-static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
+static int i2c_write(struct drxk_state *state, u8 adr, u8 *data, int len)
 {
        int status;
        struct i2c_msg msg = {
@@ -330,7 +357,7 @@ static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
                        printk(KERN_CONT " %02x", data[i]);
                printk(KERN_CONT "\n");
        }
-       status = i2c_transfer(adap, &msg, 1);
+       status = drxk_i2c_transfer(state, &msg, 1);
        if (status >= 0 && status != 1)
                status = -EIO;
 
@@ -340,7 +367,7 @@ static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
        return status;
 }
 
-static int i2c_read(struct i2c_adapter *adap,
+static int i2c_read(struct drxk_state *state,
                    u8 adr, u8 *msg, int len, u8 *answ, int alen)
 {
        int status;
@@ -351,7 +378,7 @@ static int i2c_read(struct i2c_adapter *adap,
                 .buf = answ, .len = alen}
        };
 
-       status = i2c_transfer(adap, msgs, 2);
+       status = drxk_i2c_transfer(state, msgs, 2);
        if (status != 2) {
                if (debug > 2)
                        printk(KERN_CONT ": ERROR!\n");
@@ -394,7 +421,7 @@ static int read16_flags(struct drxk_state *state, u32 reg, u16 *data, u8 flags)
                len = 2;
        }
        dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
-       status = i2c_read(state->i2c, adr, mm1, len, mm2, 2);
+       status = i2c_read(state, adr, mm1, len, mm2, 2);
        if (status < 0)
                return status;
        if (data)
@@ -428,7 +455,7 @@ static int read32_flags(struct drxk_state *state, u32 reg, u32 *data, u8 flags)
                len = 2;
        }
        dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
-       status = i2c_read(state->i2c, adr, mm1, len, mm2, 4);
+       status = i2c_read(state, adr, mm1, len, mm2, 4);
        if (status < 0)
                return status;
        if (data)
@@ -464,7 +491,7 @@ static int write16_flags(struct drxk_state *state, u32 reg, u16 data, u8 flags)
        mm[len + 1] = (data >> 8) & 0xff;
 
        dprintk(2, "(0x%08x, 0x%04x, 0x%02x)\n", reg, data, flags);
-       return i2c_write(state->i2c, adr, mm, len + 2);
+       return i2c_write(state, adr, mm, len + 2);
 }
 
 static int write16(struct drxk_state *state, u32 reg, u16 data)
@@ -495,7 +522,7 @@ static int write32_flags(struct drxk_state *state, u32 reg, u32 data, u8 flags)
        mm[len + 3] = (data >> 24) & 0xff;
        dprintk(2, "(0x%08x, 0x%08x, 0x%02x)\n", reg, data, flags);
 
-       return i2c_write(state->i2c, adr, mm, len + 4);
+       return i2c_write(state, adr, mm, len + 4);
 }
 
 static int write32(struct drxk_state *state, u32 reg, u32 data)
@@ -542,7 +569,7 @@ static int write_block(struct drxk_state *state, u32 Address,
                                        printk(KERN_CONT " %02x", pBlock[i]);
                        printk(KERN_CONT "\n");
                }
-               status = i2c_write(state->i2c, state->demod_address,
+               status = i2c_write(state, state->demod_address,
                                   &state->Chunk[0], Chunk + AdrLength);
                if (status < 0) {
                        printk(KERN_ERR "drxk: %s: i2c write error at addr 0x%02x\n",
@@ -568,17 +595,17 @@ int PowerUpDevice(struct drxk_state *state)
 
        dprintk(1, "\n");
 
-       status = i2c_read1(state->i2c, state->demod_address, &data);
+       status = i2c_read1(state, state->demod_address, &data);
        if (status < 0) {
                do {
                        data = 0;
-                       status = i2c_write(state->i2c, state->demod_address,
+                       status = i2c_write(state, state->demod_address,
                                           &data, 1);
                        msleep(10);
                        retryCount++;
                        if (status < 0)
                                continue;
-                       status = i2c_read1(state->i2c, state->demod_address,
+                       status = i2c_read1(state, state->demod_address,
                                           &data);
                } while (status < 0 &&
                         (retryCount < DRXK_MAX_RETRIES_POWERUP));
@@ -932,7 +959,7 @@ static int GetDeviceCapabilities(struct drxk_state *state)
        if (status < 0)
                goto error;
 
-printk(KERN_ERR "drxk: status = 0x%08x\n", sioTopJtagidLo);
+       printk(KERN_INFO "drxk: status = 0x%08x\n", sioTopJtagidLo);
 
        /* driver 0.9.0 */
        switch ((sioTopJtagidLo >> 29) & 0xF) {
@@ -2824,7 +2851,7 @@ static int ConfigureI2CBridge(struct drxk_state *state, bool bEnableBridge)
        dprintk(1, "\n");
 
        if (state->m_DrxkState == DRXK_UNINITIALIZED)
-               goto error;
+               return 0;
        if (state->m_DrxkState == DRXK_POWERED_DOWN)
                goto error;
 
@@ -2977,7 +3004,7 @@ static int ADCSynchronization(struct drxk_state *state)
                status = read16(state, IQM_AF_CLKNEG__A, &clkNeg);
                if (status < 0)
                        goto error;
-               if ((clkNeg | IQM_AF_CLKNEG_CLKNEGDATA__M) ==
+               if ((clkNeg & IQM_AF_CLKNEG_CLKNEGDATA__M) ==
                        IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS) {
                        clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
                        clkNeg |=
@@ -5361,7 +5388,7 @@ static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus)
                        SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK, 0, NULL, 2,
                        Result);
        if (status < 0)
-               printk(KERN_ERR "drxk: %s status = %08x\n", __func__, status);
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
 
        if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED) {
                /* 0x0000 NOT LOCKED */
@@ -5388,12 +5415,67 @@ static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus)
 #define QAM_LOCKRANGE__M      0x10
 #define QAM_LOCKRANGE_NORMAL  0x10
 
+static int QAMDemodulatorCommand(struct drxk_state *state,
+                                int numberOfParameters)
+{
+       int status;
+       u16 cmdResult;
+       u16 setParamParameters[4] = { 0, 0, 0, 0 };
+
+       setParamParameters[0] = state->m_Constellation; /* modulation     */
+       setParamParameters[1] = DRXK_QAM_I12_J17;       /* interleave mode   */
+
+       if (numberOfParameters == 2) {
+               u16 setEnvParameters[1] = { 0 };
+
+               if (state->m_OperationMode == OM_QAM_ITU_C)
+                       setEnvParameters[0] = QAM_TOP_ANNEX_C;
+               else
+                       setEnvParameters[0] = QAM_TOP_ANNEX_A;
+
+               status = scu_command(state,
+                                    SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV,
+                                    1, setEnvParameters, 1, &cmdResult);
+               if (status < 0)
+                       goto error;
+
+               status = scu_command(state,
+                                    SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
+                                    numberOfParameters, setParamParameters,
+                                    1, &cmdResult);
+       } else if (numberOfParameters == 4) {
+               if (state->m_OperationMode == OM_QAM_ITU_C)
+                       setParamParameters[2] = QAM_TOP_ANNEX_C;
+               else
+                       setParamParameters[2] = QAM_TOP_ANNEX_A;
+
+               setParamParameters[3] |= (QAM_MIRROR_AUTO_ON);
+               /* Env parameters */
+               /* check for LOCKRANGE Extented */
+               /* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */
+
+               status = scu_command(state,
+                                    SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM,
+                                    numberOfParameters, setParamParameters,
+                                    1, &cmdResult);
+       } else {
+               printk(KERN_WARNING "drxk: Unknown QAM demodulator parameter "
+                       "count %d\n", numberOfParameters);
+       }
+
+error:
+       if (status < 0)
+               printk(KERN_WARNING "drxk: Warning %d on %s\n",
+                      status, __func__);
+       return status;
+}
+
 static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
                  s32 tunerFreqOffset)
 {
        int status;
-       u16 setParamParameters[4] = { 0, 0, 0, 0 };
        u16 cmdResult;
+       int qamDemodParamCount = state->qam_demod_parameter_count;
 
        dprintk(1, "\n");
        /*
@@ -5445,34 +5527,42 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
        }
        if (status < 0)
                goto error;
-       setParamParameters[0] = state->m_Constellation; /* modulation     */
-       setParamParameters[1] = DRXK_QAM_I12_J17;       /* interleave mode   */
-       if (state->m_OperationMode == OM_QAM_ITU_C)
-               setParamParameters[2] = QAM_TOP_ANNEX_C;
-       else
-               setParamParameters[2] = QAM_TOP_ANNEX_A;
-       setParamParameters[3] |= (QAM_MIRROR_AUTO_ON);
-       /* Env parameters */
-       /* check for LOCKRANGE Extented */
-       /* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */
 
-       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 4, setParamParameters, 1, &cmdResult);
-       if (status < 0) {
-               /* Fall-back to the simpler call */
-               if (state->m_OperationMode == OM_QAM_ITU_C)
-                       setParamParameters[0] = QAM_TOP_ANNEX_C;
-               else
-                       setParamParameters[0] = QAM_TOP_ANNEX_A;
-               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 1, setParamParameters, 1, &cmdResult);
-               if (status < 0)
-                       goto error;
+       /* Use the 4-parameter if it's requested or we're probing for
+        * the correct command. */
+       if (state->qam_demod_parameter_count == 4
+               || !state->qam_demod_parameter_count) {
+               qamDemodParamCount = 4;
+               status = QAMDemodulatorCommand(state, qamDemodParamCount);
+       }
 
-               setParamParameters[0] = state->m_Constellation; /* modulation     */
-               setParamParameters[1] = DRXK_QAM_I12_J17;       /* interleave mode   */
-               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 2, setParamParameters, 1, &cmdResult);
+       /* Use the 2-parameter command if it was requested or if we're
+        * probing for the correct command and the 4-parameter command
+        * failed. */
+       if (state->qam_demod_parameter_count == 2
+               || (!state->qam_demod_parameter_count && status < 0)) {
+               qamDemodParamCount = 2;
+               status = QAMDemodulatorCommand(state, qamDemodParamCount);
        }
-       if (status < 0)
+
+       if (status < 0) {
+               dprintk(1, "Could not set demodulator parameters. Make "
+                       "sure qam_demod_parameter_count (%d) is correct for "
+                       "your firmware (%s).\n",
+                       state->qam_demod_parameter_count,
+                       state->microcode_name);
                goto error;
+       } else if (!state->qam_demod_parameter_count) {
+               dprintk(1, "Auto-probing the correct QAM demodulator command "
+                       "parameters was successful - using %d parameters.\n",
+                       qamDemodParamCount);
+
+               /*
+                * One of our commands was successful. We don't need to
+                * auto-probe anymore, now that we got the correct command.
+                */
+               state->qam_demod_parameter_count = qamDemodParamCount;
+       }
 
        /*
         * STEP 3: enable the system in a mode where the ADC provides valid
@@ -5968,34 +6058,15 @@ error:
        return status;
 }
 
-static int load_microcode(struct drxk_state *state, const char *mc_name)
-{
-       const struct firmware *fw = NULL;
-       int err = 0;
-
-       dprintk(1, "\n");
-
-       err = request_firmware(&fw, mc_name, state->i2c->dev.parent);
-       if (err < 0) {
-               printk(KERN_ERR
-                      "drxk: Could not load firmware file %s.\n", mc_name);
-               printk(KERN_INFO
-                      "drxk: Copy %s to your hotplug directory!\n", mc_name);
-               return err;
-       }
-       err = DownloadMicrocode(state, fw->data, fw->size);
-       release_firmware(fw);
-       return err;
-}
-
 static int init_drxk(struct drxk_state *state)
 {
-       int status = 0;
+       int status = 0, n = 0;
        enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
        u16 driverVersion;
 
        dprintk(1, "\n");
        if ((state->m_DrxkState == DRXK_UNINITIALIZED)) {
+               drxk_i2c_lock(state);
                status = PowerUpDevice(state);
                if (status < 0)
                        goto error;
@@ -6073,8 +6144,12 @@ static int init_drxk(struct drxk_state *state)
                if (status < 0)
                        goto error;
 
-               if (state->microcode_name)
-                       load_microcode(state, state->microcode_name);
+               if (state->fw) {
+                       status = DownloadMicrocode(state, state->fw->data,
+                                                  state->fw->size);
+                       if (status < 0)
+                               goto error;
+               }
 
                /* disable token-ring bus through OFDM block for possible ucode upload */
                status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_OFF);
@@ -6167,19 +6242,71 @@ static int init_drxk(struct drxk_state *state)
                        state->m_DrxkState = DRXK_POWERED_DOWN;
                } else
                        state->m_DrxkState = DRXK_STOPPED;
+
+               /* Initialize the supported delivery systems */
+               n = 0;
+               if (state->m_hasDVBC) {
+                       state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
+                       state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C;
+                       strlcat(state->frontend.ops.info.name, " DVB-C",
+                               sizeof(state->frontend.ops.info.name));
+               }
+               if (state->m_hasDVBT) {
+                       state->frontend.ops.delsys[n++] = SYS_DVBT;
+                       strlcat(state->frontend.ops.info.name, " DVB-T",
+                               sizeof(state->frontend.ops.info.name));
+               }
+               drxk_i2c_unlock(state);
        }
 error:
-       if (status < 0)
+       if (status < 0) {
+               state->m_DrxkState = DRXK_NO_DEV;
+               drxk_i2c_unlock(state);
                printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       }
 
        return status;
 }
 
+static void load_firmware_cb(const struct firmware *fw,
+                            void *context)
+{
+       struct drxk_state *state = context;
+
+       dprintk(1, ": %s\n", fw ? "firmware loaded" : "firmware not loaded");
+       if (!fw) {
+               printk(KERN_ERR
+                      "drxk: Could not load firmware file %s.\n",
+                       state->microcode_name);
+               printk(KERN_INFO
+                      "drxk: Copy %s to your hotplug directory!\n",
+                       state->microcode_name);
+               state->microcode_name = NULL;
+
+               /*
+                * As firmware is now load asynchronous, it is not possible
+                * anymore to fail at frontend attach. We might silently
+                * return here, and hope that the driver won't crash.
+                * We might also change all DVB callbacks to return -ENODEV
+                * if the device is not initialized.
+                * As the DRX-K devices have their own internal firmware,
+                * let's just hope that it will match a firmware revision
+                * compatible with this driver and proceed.
+                */
+       }
+       state->fw = fw;
+
+       init_drxk(state);
+}
+
 static void drxk_release(struct dvb_frontend *fe)
 {
        struct drxk_state *state = fe->demodulator_priv;
 
        dprintk(1, "\n");
+       if (state->fw)
+               release_firmware(state->fw);
+
        kfree(state);
 }
 
@@ -6188,6 +6315,12 @@ static int drxk_sleep(struct dvb_frontend *fe)
        struct drxk_state *state = fe->demodulator_priv;
 
        dprintk(1, "\n");
+
+       if (state->m_DrxkState == DRXK_NO_DEV)
+               return -ENODEV;
+       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+               return 0;
+
        ShutDown(state);
        return 0;
 }
@@ -6196,7 +6329,11 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
        struct drxk_state *state = fe->demodulator_priv;
 
-       dprintk(1, "%s\n", enable ? "enable" : "disable");
+       dprintk(1, ": %s\n", enable ? "enable" : "disable");
+
+       if (state->m_DrxkState == DRXK_NO_DEV)
+               return -ENODEV;
+
        return ConfigureI2CBridge(state, enable ? true : false);
 }
 
@@ -6209,6 +6346,12 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
 
        dprintk(1, "\n");
 
+       if (state->m_DrxkState == DRXK_NO_DEV)
+               return -ENODEV;
+
+       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+               return -EAGAIN;
+
        if (!fe->ops.tuner_ops.get_if_frequency) {
                printk(KERN_ERR
                       "drxk: Error: get_if_frequency() not defined at tuner. Can't work without it!\n");
@@ -6262,6 +6405,12 @@ static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
        u32 stat;
 
        dprintk(1, "\n");
+
+       if (state->m_DrxkState == DRXK_NO_DEV)
+               return -ENODEV;
+       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+               return -EAGAIN;
+
        *status = 0;
        GetLockStatus(state, &stat, 0);
        if (stat == MPEG_LOCK)
@@ -6275,8 +6424,15 @@ static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
 static int drxk_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
+       struct drxk_state *state = fe->demodulator_priv;
+
        dprintk(1, "\n");
 
+       if (state->m_DrxkState == DRXK_NO_DEV)
+               return -ENODEV;
+       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+               return -EAGAIN;
+
        *ber = 0;
        return 0;
 }
@@ -6288,6 +6444,12 @@ static int drxk_read_signal_strength(struct dvb_frontend *fe,
        u32 val = 0;
 
        dprintk(1, "\n");
+
+       if (state->m_DrxkState == DRXK_NO_DEV)
+               return -ENODEV;
+       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+               return -EAGAIN;
+
        ReadIFAgc(state, &val);
        *strength = val & 0xffff;
        return 0;
@@ -6299,6 +6461,12 @@ static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr)
        s32 snr2;
 
        dprintk(1, "\n");
+
+       if (state->m_DrxkState == DRXK_NO_DEV)
+               return -ENODEV;
+       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+               return -EAGAIN;
+
        GetSignalToNoise(state, &snr2);
        *snr = snr2 & 0xffff;
        return 0;
@@ -6310,6 +6478,12 @@ static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
        u16 err;
 
        dprintk(1, "\n");
+
+       if (state->m_DrxkState == DRXK_NO_DEV)
+               return -ENODEV;
+       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+               return -EAGAIN;
+
        DVBTQAMGetAccPktErr(state, &err);
        *ucblocks = (u32) err;
        return 0;
@@ -6318,9 +6492,16 @@ static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings
                                    *sets)
 {
+       struct drxk_state *state = fe->demodulator_priv;
        struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 
        dprintk(1, "\n");
+
+       if (state->m_DrxkState == DRXK_NO_DEV)
+               return -ENODEV;
+       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+               return -EAGAIN;
+
        switch (p->delivery_system) {
        case SYS_DVBC_ANNEX_A:
        case SYS_DVBC_ANNEX_C:
@@ -6371,10 +6552,9 @@ static struct dvb_frontend_ops drxk_ops = {
 struct dvb_frontend *drxk_attach(const struct drxk_config *config,
                                 struct i2c_adapter *i2c)
 {
-       int n;
-
        struct drxk_state *state = NULL;
        u8 adr = config->adr;
+       int status;
 
        dprintk(1, "\n");
        state = kzalloc(sizeof(struct drxk_state), GFP_KERNEL);
@@ -6385,6 +6565,7 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
        state->demod_address = adr;
        state->single_master = config->single_master;
        state->microcode_name = config->microcode_name;
+       state->qam_demod_parameter_count = config->qam_demod_parameter_count;
        state->no_i2c_bridge = config->no_i2c_bridge;
        state->antenna_gpio = config->antenna_gpio;
        state->antenna_dvbt = config->antenna_dvbt;
@@ -6425,22 +6606,21 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
        state->frontend.demodulator_priv = state;
 
        init_state(state);
-       if (init_drxk(state) < 0)
-               goto error;
 
-       /* Initialize the supported delivery systems */
-       n = 0;
-       if (state->m_hasDVBC) {
-               state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
-               state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C;
-               strlcat(state->frontend.ops.info.name, " DVB-C",
-                       sizeof(state->frontend.ops.info.name));
-       }
-       if (state->m_hasDVBT) {
-               state->frontend.ops.delsys[n++] = SYS_DVBT;
-               strlcat(state->frontend.ops.info.name, " DVB-T",
-                       sizeof(state->frontend.ops.info.name));
-       }
+       /* Load firmware and initialize DRX-K */
+       if (state->microcode_name) {
+               status = request_firmware_nowait(THIS_MODULE, 1,
+                                             state->microcode_name,
+                                             state->i2c->dev.parent,
+                                             GFP_KERNEL,
+                                             state, load_firmware_cb);
+               if (status < 0) {
+                       printk(KERN_ERR
+                       "drxk: failed to request a firmware\n");
+                       return NULL;
+               }
+       } else if (init_drxk(state) < 0)
+               goto error;
 
        printk(KERN_INFO "drxk: frontend initialized.\n");
        return &state->frontend;
index 4bbf841de83a77b90d70e092922ff8d88aa36682..6bb9fc4a7b96cbeeb6a082503499fbff18feb4d2 100644 (file)
@@ -94,7 +94,15 @@ enum DRXPowerMode {
 
 
 enum AGC_CTRL_MODE { DRXK_AGC_CTRL_AUTO = 0, DRXK_AGC_CTRL_USER, DRXK_AGC_CTRL_OFF };
-enum EDrxkState { DRXK_UNINITIALIZED = 0, DRXK_STOPPED, DRXK_DTV_STARTED, DRXK_ATV_STARTED, DRXK_POWERED_DOWN };
+enum EDrxkState {
+       DRXK_UNINITIALIZED = 0,
+       DRXK_STOPPED,
+       DRXK_DTV_STARTED,
+       DRXK_ATV_STARTED,
+       DRXK_POWERED_DOWN,
+       DRXK_NO_DEV                     /* If drxk init failed */
+};
+
 enum EDrxkCoefArrayIndex {
        DRXK_COEF_IDX_MN = 0,
        DRXK_COEF_IDX_FM    ,
@@ -325,6 +333,9 @@ struct drxk_state {
 
        enum DRXPowerMode m_currentPowerMode;
 
+       /* when true, avoids other devices to use the I2C bus */
+       bool              drxk_i2c_exclusive_lock;
+
        /*
         * Configurable parameters at the driver. They stores the values found
         * at struct drxk_config.
@@ -338,7 +349,11 @@ struct drxk_state {
        bool    antenna_dvbt;
        u16     antenna_gpio;
 
+       /* Firmware */
        const char *microcode_name;
+       struct completion fw_wait_load;
+       const struct firmware *fw;
+       int qam_demod_parameter_count;
 };
 
 #define NEVER_LOCK 0
diff --git a/drivers/media/dvb/frontends/rtl2832.c b/drivers/media/dvb/frontends/rtl2832.c
new file mode 100644 (file)
index 0000000..2da592f
--- /dev/null
@@ -0,0 +1,789 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "rtl2832_priv.h"
+#include <linux/bitops.h>
+
+int rtl2832_debug;
+module_param_named(debug, rtl2832_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+#define REG_MASK(b) (BIT(b + 1) - 1)
+
+static const struct rtl2832_reg_entry registers[] = {
+       [DVBT_SOFT_RST]         = {0x1, 0x1,   2, 2},
+       [DVBT_IIC_REPEAT]       = {0x1, 0x1,   3, 3},
+       [DVBT_TR_WAIT_MIN_8K]   = {0x1, 0x88, 11, 2},
+       [DVBT_RSD_BER_FAIL_VAL] = {0x1, 0x8f, 15, 0},
+       [DVBT_EN_BK_TRK]        = {0x1, 0xa6,  7, 7},
+       [DVBT_AD_EN_REG]        = {0x0, 0x8,   7, 7},
+       [DVBT_AD_EN_REG1]       = {0x0, 0x8,   6, 6},
+       [DVBT_EN_BBIN]          = {0x1, 0xb1,  0, 0},
+       [DVBT_MGD_THD0]         = {0x1, 0x95,  7, 0},
+       [DVBT_MGD_THD1]         = {0x1, 0x96,  7, 0},
+       [DVBT_MGD_THD2]         = {0x1, 0x97,  7, 0},
+       [DVBT_MGD_THD3]         = {0x1, 0x98,  7, 0},
+       [DVBT_MGD_THD4]         = {0x1, 0x99,  7, 0},
+       [DVBT_MGD_THD5]         = {0x1, 0x9a,  7, 0},
+       [DVBT_MGD_THD6]         = {0x1, 0x9b,  7, 0},
+       [DVBT_MGD_THD7]         = {0x1, 0x9c,  7, 0},
+       [DVBT_EN_CACQ_NOTCH]    = {0x1, 0x61,  4, 4},
+       [DVBT_AD_AV_REF]        = {0x0, 0x9,   6, 0},
+       [DVBT_REG_PI]           = {0x0, 0xa,   2, 0},
+       [DVBT_PIP_ON]           = {0x0, 0x21,  3, 3},
+       [DVBT_SCALE1_B92]       = {0x2, 0x92,  7, 0},
+       [DVBT_SCALE1_B93]       = {0x2, 0x93,  7, 0},
+       [DVBT_SCALE1_BA7]       = {0x2, 0xa7,  7, 0},
+       [DVBT_SCALE1_BA9]       = {0x2, 0xa9,  7, 0},
+       [DVBT_SCALE1_BAA]       = {0x2, 0xaa,  7, 0},
+       [DVBT_SCALE1_BAB]       = {0x2, 0xab,  7, 0},
+       [DVBT_SCALE1_BAC]       = {0x2, 0xac,  7, 0},
+       [DVBT_SCALE1_BB0]       = {0x2, 0xb0,  7, 0},
+       [DVBT_SCALE1_BB1]       = {0x2, 0xb1,  7, 0},
+       [DVBT_KB_P1]            = {0x1, 0x64,  3, 1},
+       [DVBT_KB_P2]            = {0x1, 0x64,  6, 4},
+       [DVBT_KB_P3]            = {0x1, 0x65,  2, 0},
+       [DVBT_OPT_ADC_IQ]       = {0x0, 0x6,   5, 4},
+       [DVBT_AD_AVI]           = {0x0, 0x9,   1, 0},
+       [DVBT_AD_AVQ]           = {0x0, 0x9,   3, 2},
+       [DVBT_K1_CR_STEP12]     = {0x2, 0xad,  9, 4},
+       [DVBT_TRK_KS_P2]        = {0x1, 0x6f,  2, 0},
+       [DVBT_TRK_KS_I2]        = {0x1, 0x70,  5, 3},
+       [DVBT_TR_THD_SET2]      = {0x1, 0x72,  3, 0},
+       [DVBT_TRK_KC_P2]        = {0x1, 0x73,  5, 3},
+       [DVBT_TRK_KC_I2]        = {0x1, 0x75,  2, 0},
+       [DVBT_CR_THD_SET2]      = {0x1, 0x76,  7, 6},
+       [DVBT_PSET_IFFREQ]      = {0x1, 0x19, 21, 0},
+       [DVBT_SPEC_INV]         = {0x1, 0x15,  0, 0},
+       [DVBT_RSAMP_RATIO]      = {0x1, 0x9f, 27, 2},
+       [DVBT_CFREQ_OFF_RATIO]  = {0x1, 0x9d, 23, 4},
+       [DVBT_FSM_STAGE]        = {0x3, 0x51,  6, 3},
+       [DVBT_RX_CONSTEL]       = {0x3, 0x3c,  3, 2},
+       [DVBT_RX_HIER]          = {0x3, 0x3c,  6, 4},
+       [DVBT_RX_C_RATE_LP]     = {0x3, 0x3d,  2, 0},
+       [DVBT_RX_C_RATE_HP]     = {0x3, 0x3d,  5, 3},
+       [DVBT_GI_IDX]           = {0x3, 0x51,  1, 0},
+       [DVBT_FFT_MODE_IDX]     = {0x3, 0x51,  2, 2},
+       [DVBT_RSD_BER_EST]      = {0x3, 0x4e, 15, 0},
+       [DVBT_CE_EST_EVM]       = {0x4, 0xc,  15, 0},
+       [DVBT_RF_AGC_VAL]       = {0x3, 0x5b, 13, 0},
+       [DVBT_IF_AGC_VAL]       = {0x3, 0x59, 13, 0},
+       [DVBT_DAGC_VAL]         = {0x3, 0x5,   7, 0},
+       [DVBT_SFREQ_OFF]        = {0x3, 0x18, 13, 0},
+       [DVBT_CFREQ_OFF]        = {0x3, 0x5f, 17, 0},
+       [DVBT_POLAR_RF_AGC]     = {0x0, 0xe,   1, 1},
+       [DVBT_POLAR_IF_AGC]     = {0x0, 0xe,   0, 0},
+       [DVBT_AAGC_HOLD]        = {0x1, 0x4,   5, 5},
+       [DVBT_EN_RF_AGC]        = {0x1, 0x4,   6, 6},
+       [DVBT_EN_IF_AGC]        = {0x1, 0x4,   7, 7},
+       [DVBT_IF_AGC_MIN]       = {0x1, 0x8,   7, 0},
+       [DVBT_IF_AGC_MAX]       = {0x1, 0x9,   7, 0},
+       [DVBT_RF_AGC_MIN]       = {0x1, 0xa,   7, 0},
+       [DVBT_RF_AGC_MAX]       = {0x1, 0xb,   7, 0},
+       [DVBT_IF_AGC_MAN]       = {0x1, 0xc,   6, 6},
+       [DVBT_IF_AGC_MAN_VAL]   = {0x1, 0xc,  13, 0},
+       [DVBT_RF_AGC_MAN]       = {0x1, 0xe,   6, 6},
+       [DVBT_RF_AGC_MAN_VAL]   = {0x1, 0xe,  13, 0},
+       [DVBT_DAGC_TRG_VAL]     = {0x1, 0x12,  7, 0},
+       [DVBT_AGC_TARG_VAL_0]   = {0x1, 0x2,   0, 0},
+       [DVBT_AGC_TARG_VAL_8_1] = {0x1, 0x3,   7, 0},
+       [DVBT_AAGC_LOOP_GAIN]   = {0x1, 0xc7,  5, 1},
+       [DVBT_LOOP_GAIN2_3_0]   = {0x1, 0x4,   4, 1},
+       [DVBT_LOOP_GAIN2_4]     = {0x1, 0x5,   7, 7},
+       [DVBT_LOOP_GAIN3]       = {0x1, 0xc8,  4, 0},
+       [DVBT_VTOP1]            = {0x1, 0x6,   5, 0},
+       [DVBT_VTOP2]            = {0x1, 0xc9,  5, 0},
+       [DVBT_VTOP3]            = {0x1, 0xca,  5, 0},
+       [DVBT_KRF1]             = {0x1, 0xcb,  7, 0},
+       [DVBT_KRF2]             = {0x1, 0x7,   7, 0},
+       [DVBT_KRF3]             = {0x1, 0xcd,  7, 0},
+       [DVBT_KRF4]             = {0x1, 0xce,  7, 0},
+       [DVBT_EN_GI_PGA]        = {0x1, 0xe5,  0, 0},
+       [DVBT_THD_LOCK_UP]      = {0x1, 0xd9,  8, 0},
+       [DVBT_THD_LOCK_DW]      = {0x1, 0xdb,  8, 0},
+       [DVBT_THD_UP1]          = {0x1, 0xdd,  7, 0},
+       [DVBT_THD_DW1]          = {0x1, 0xde,  7, 0},
+       [DVBT_INTER_CNT_LEN]    = {0x1, 0xd8,  3, 0},
+       [DVBT_GI_PGA_STATE]     = {0x1, 0xe6,  3, 3},
+       [DVBT_EN_AGC_PGA]       = {0x1, 0xd7,  0, 0},
+       [DVBT_CKOUTPAR]         = {0x1, 0x7b,  5, 5},
+       [DVBT_CKOUT_PWR]        = {0x1, 0x7b,  6, 6},
+       [DVBT_SYNC_DUR]         = {0x1, 0x7b,  7, 7},
+       [DVBT_ERR_DUR]          = {0x1, 0x7c,  0, 0},
+       [DVBT_SYNC_LVL]         = {0x1, 0x7c,  1, 1},
+       [DVBT_ERR_LVL]          = {0x1, 0x7c,  2, 2},
+       [DVBT_VAL_LVL]          = {0x1, 0x7c,  3, 3},
+       [DVBT_SERIAL]           = {0x1, 0x7c,  4, 4},
+       [DVBT_SER_LSB]          = {0x1, 0x7c,  5, 5},
+       [DVBT_CDIV_PH0]         = {0x1, 0x7d,  3, 0},
+       [DVBT_CDIV_PH1]         = {0x1, 0x7d,  7, 4},
+       [DVBT_MPEG_IO_OPT_2_2]  = {0x0, 0x6,   7, 7},
+       [DVBT_MPEG_IO_OPT_1_0]  = {0x0, 0x7,   7, 6},
+       [DVBT_CKOUTPAR_PIP]     = {0x0, 0xb7,  4, 4},
+       [DVBT_CKOUT_PWR_PIP]    = {0x0, 0xb7,  3, 3},
+       [DVBT_SYNC_LVL_PIP]     = {0x0, 0xb7,  2, 2},
+       [DVBT_ERR_LVL_PIP]      = {0x0, 0xb7,  1, 1},
+       [DVBT_VAL_LVL_PIP]      = {0x0, 0xb7,  0, 0},
+       [DVBT_CKOUTPAR_PID]     = {0x0, 0xb9,  4, 4},
+       [DVBT_CKOUT_PWR_PID]    = {0x0, 0xb9,  3, 3},
+       [DVBT_SYNC_LVL_PID]     = {0x0, 0xb9,  2, 2},
+       [DVBT_ERR_LVL_PID]      = {0x0, 0xb9,  1, 1},
+       [DVBT_VAL_LVL_PID]      = {0x0, 0xb9,  0, 0},
+       [DVBT_SM_PASS]          = {0x1, 0x93, 11, 0},
+       [DVBT_AD7_SETTING]      = {0x0, 0x11, 15, 0},
+       [DVBT_RSSI_R]           = {0x3, 0x1,   6, 0},
+       [DVBT_ACI_DET_IND]      = {0x3, 0x12,  0, 0},
+       [DVBT_REG_MON]          = {0x0, 0xd,   1, 0},
+       [DVBT_REG_MONSEL]       = {0x0, 0xd,   2, 2},
+       [DVBT_REG_GPE]          = {0x0, 0xd,   7, 7},
+       [DVBT_REG_GPO]          = {0x0, 0x10,  0, 0},
+       [DVBT_REG_4MSEL]        = {0x0, 0x13,  0, 0},
+};
+
+/* write multiple hardware registers */
+static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
+{
+       int ret;
+       u8 buf[1+len];
+       struct i2c_msg msg[1] = {
+               {
+                       .addr = priv->cfg.i2c_addr,
+                       .flags = 0,
+                       .len = 1+len,
+                       .buf = buf,
+               }
+       };
+
+       buf[0] = reg;
+       memcpy(&buf[1], val, len);
+
+       ret = i2c_transfer(priv->i2c, msg, 1);
+       if (ret == 1) {
+               ret = 0;
+       } else {
+               warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+               ret = -EREMOTEIO;
+       }
+       return ret;
+}
+
+/* read multiple hardware registers */
+static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
+{
+       int ret;
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = priv->cfg.i2c_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &reg,
+               }, {
+                       .addr = priv->cfg.i2c_addr,
+                       .flags = I2C_M_RD,
+                       .len = len,
+                       .buf = val,
+               }
+       };
+
+       ret = i2c_transfer(priv->i2c, msg, 2);
+       if (ret == 2) {
+               ret = 0;
+       } else {
+               warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+               ret = -EREMOTEIO;
+}
+return ret;
+}
+
+/* write multiple registers */
+static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
+       int len)
+{
+       int ret;
+
+
+       /* switch bank if needed */
+       if (page != priv->page) {
+               ret = rtl2832_wr(priv, 0x00, &page, 1);
+               if (ret)
+                       return ret;
+
+               priv->page = page;
+}
+
+return rtl2832_wr(priv, reg, val, len);
+}
+
+/* read multiple registers */
+static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
+       int len)
+{
+       int ret;
+
+       /* switch bank if needed */
+       if (page != priv->page) {
+               ret = rtl2832_wr(priv, 0x00, &page, 1);
+               if (ret)
+                       return ret;
+
+               priv->page = page;
+       }
+
+       return rtl2832_rd(priv, reg, val, len);
+}
+
+#if 0 /* currently not used */
+/* write single register */
+static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val)
+{
+       return rtl2832_wr_regs(priv, reg, page, &val, 1);
+}
+#endif
+
+/* read single register */
+static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val)
+{
+       return rtl2832_rd_regs(priv, reg, page, val, 1);
+}
+
+int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val)
+{
+       int ret;
+
+       u8 reg_start_addr;
+       u8 msb, lsb;
+       u8 page;
+       u8 reading[4];
+       u32 reading_tmp;
+       int i;
+
+       u8 len;
+       u32 mask;
+
+       reg_start_addr = registers[reg].start_address;
+       msb = registers[reg].msb;
+       lsb = registers[reg].lsb;
+       page = registers[reg].page;
+
+       len = (msb >> 3) + 1;
+       mask = REG_MASK(msb - lsb);
+
+       ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
+       if (ret)
+               goto err;
+
+       reading_tmp = 0;
+       for (i = 0; i < len; i++)
+               reading_tmp |= reading[i] << ((len - 1 - i) * 8);
+
+       *val = (reading_tmp >> lsb) & mask;
+
+       return ret;
+
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+
+}
+
+int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
+{
+       int ret, i;
+       u8 len;
+       u8 reg_start_addr;
+       u8 msb, lsb;
+       u8 page;
+       u32 mask;
+
+
+       u8 reading[4];
+       u8 writing[4];
+       u32 reading_tmp;
+       u32 writing_tmp;
+
+
+       reg_start_addr = registers[reg].start_address;
+       msb = registers[reg].msb;
+       lsb = registers[reg].lsb;
+       page = registers[reg].page;
+
+       len = (msb >> 3) + 1;
+       mask = REG_MASK(msb - lsb);
+
+
+       ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
+       if (ret)
+               goto err;
+
+       reading_tmp = 0;
+       for (i = 0; i < len; i++)
+               reading_tmp |= reading[i] << ((len - 1 - i) * 8);
+
+       writing_tmp = reading_tmp & ~(mask << lsb);
+       writing_tmp |= ((val & mask) << lsb);
+
+
+       for (i = 0; i < len; i++)
+               writing[i] = (writing_tmp >> ((len - 1 - i) * 8)) & 0xff;
+
+       ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len);
+       if (ret)
+               goto err;
+
+       return ret;
+
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+
+}
+
+
+static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       int ret;
+       struct rtl2832_priv *priv = fe->demodulator_priv;
+
+       dbg("%s: enable=%d", __func__, enable);
+
+       /* gate already open or close */
+       if (priv->i2c_gate_state == enable)
+               return 0;
+
+       ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable ? 0x1 : 0x0));
+       if (ret)
+               goto err;
+
+       priv->i2c_gate_state = enable;
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+
+
+static int rtl2832_init(struct dvb_frontend *fe)
+{
+       struct rtl2832_priv *priv = fe->demodulator_priv;
+       int i, ret;
+
+       u8 en_bbin;
+       u64 pset_iffreq;
+
+       /* initialization values for the demodulator registers */
+       struct rtl2832_reg_value rtl2832_initial_regs[] = {
+               {DVBT_AD_EN_REG,                0x1},
+               {DVBT_AD_EN_REG1,               0x1},
+               {DVBT_RSD_BER_FAIL_VAL,         0x2800},
+               {DVBT_MGD_THD0,                 0x10},
+               {DVBT_MGD_THD1,                 0x20},
+               {DVBT_MGD_THD2,                 0x20},
+               {DVBT_MGD_THD3,                 0x40},
+               {DVBT_MGD_THD4,                 0x22},
+               {DVBT_MGD_THD5,                 0x32},
+               {DVBT_MGD_THD6,                 0x37},
+               {DVBT_MGD_THD7,                 0x39},
+               {DVBT_EN_BK_TRK,                0x0},
+               {DVBT_EN_CACQ_NOTCH,            0x0},
+               {DVBT_AD_AV_REF,                0x2a},
+               {DVBT_REG_PI,                   0x6},
+               {DVBT_PIP_ON,                   0x0},
+               {DVBT_CDIV_PH0,                 0x8},
+               {DVBT_CDIV_PH1,                 0x8},
+               {DVBT_SCALE1_B92,               0x4},
+               {DVBT_SCALE1_B93,               0xb0},
+               {DVBT_SCALE1_BA7,               0x78},
+               {DVBT_SCALE1_BA9,               0x28},
+               {DVBT_SCALE1_BAA,               0x59},
+               {DVBT_SCALE1_BAB,               0x83},
+               {DVBT_SCALE1_BAC,               0xd4},
+               {DVBT_SCALE1_BB0,               0x65},
+               {DVBT_SCALE1_BB1,               0x43},
+               {DVBT_KB_P1,                    0x1},
+               {DVBT_KB_P2,                    0x4},
+               {DVBT_KB_P3,                    0x7},
+               {DVBT_K1_CR_STEP12,             0xa},
+               {DVBT_REG_GPE,                  0x1},
+               {DVBT_SERIAL,                   0x0},
+               {DVBT_CDIV_PH0,                 0x9},
+               {DVBT_CDIV_PH1,                 0x9},
+               {DVBT_MPEG_IO_OPT_2_2,          0x0},
+               {DVBT_MPEG_IO_OPT_1_0,          0x0},
+               {DVBT_TRK_KS_P2,                0x4},
+               {DVBT_TRK_KS_I2,                0x7},
+               {DVBT_TR_THD_SET2,              0x6},
+               {DVBT_TRK_KC_I2,                0x5},
+               {DVBT_CR_THD_SET2,              0x1},
+               {DVBT_SPEC_INV,                 0x0},
+               {DVBT_DAGC_TRG_VAL,             0x5a},
+               {DVBT_AGC_TARG_VAL_0,           0x0},
+               {DVBT_AGC_TARG_VAL_8_1,         0x5a},
+               {DVBT_AAGC_LOOP_GAIN,           0x16},
+               {DVBT_LOOP_GAIN2_3_0,           0x6},
+               {DVBT_LOOP_GAIN2_4,             0x1},
+               {DVBT_LOOP_GAIN3,               0x16},
+               {DVBT_VTOP1,                    0x35},
+               {DVBT_VTOP2,                    0x21},
+               {DVBT_VTOP3,                    0x21},
+               {DVBT_KRF1,                     0x0},
+               {DVBT_KRF2,                     0x40},
+               {DVBT_KRF3,                     0x10},
+               {DVBT_KRF4,                     0x10},
+               {DVBT_IF_AGC_MIN,               0x80},
+               {DVBT_IF_AGC_MAX,               0x7f},
+               {DVBT_RF_AGC_MIN,               0x80},
+               {DVBT_RF_AGC_MAX,               0x7f},
+               {DVBT_POLAR_RF_AGC,             0x0},
+               {DVBT_POLAR_IF_AGC,             0x0},
+               {DVBT_AD7_SETTING,              0xe9bf},
+               {DVBT_EN_GI_PGA,                0x0},
+               {DVBT_THD_LOCK_UP,              0x0},
+               {DVBT_THD_LOCK_DW,              0x0},
+               {DVBT_THD_UP1,                  0x11},
+               {DVBT_THD_DW1,                  0xef},
+               {DVBT_INTER_CNT_LEN,            0xc},
+               {DVBT_GI_PGA_STATE,             0x0},
+               {DVBT_EN_AGC_PGA,               0x1},
+               {DVBT_IF_AGC_MAN,               0x0},
+       };
+
+
+       dbg("%s", __func__);
+
+       en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0);
+
+       /*
+       * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22)
+       *               / CrystalFreqHz)
+       */
+       pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal;
+       pset_iffreq *= 0x400000;
+       pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
+       pset_iffreq = pset_iffreq & 0x3fffff;
+
+
+
+       for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) {
+               ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg,
+                       rtl2832_initial_regs[i].value);
+               if (ret)
+                       goto err;
+       }
+
+       /* if frequency settings */
+       ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
+               if (ret)
+                       goto err;
+
+       ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
+               if (ret)
+                       goto err;
+
+       priv->sleeping = false;
+
+       return ret;
+
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int rtl2832_sleep(struct dvb_frontend *fe)
+{
+       struct rtl2832_priv *priv = fe->demodulator_priv;
+
+       dbg("%s", __func__);
+       priv->sleeping = true;
+       return 0;
+}
+
+int rtl2832_get_tune_settings(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *s)
+{
+       dbg("%s", __func__);
+       s->min_delay_ms = 1000;
+       s->step_size = fe->ops.info.frequency_stepsize * 2;
+       s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+       return 0;
+}
+
+static int rtl2832_set_frontend(struct dvb_frontend *fe)
+{
+       struct rtl2832_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret, i, j;
+       u64 bw_mode, num, num2;
+       u32 resamp_ratio, cfreq_off_ratio;
+
+
+       static u8 bw_params[3][32] = {
+       /* 6 MHz bandwidth */
+               {
+               0xf5, 0xff, 0x15, 0x38, 0x5d, 0x6d, 0x52, 0x07, 0xfa, 0x2f,
+               0x53, 0xf5, 0x3f, 0xca, 0x0b, 0x91, 0xea, 0x30, 0x63, 0xb2,
+               0x13, 0xda, 0x0b, 0xc4, 0x18, 0x7e, 0x16, 0x66, 0x08, 0x67,
+               0x19, 0xe0,
+               },
+
+       /*  7 MHz bandwidth */
+               {
+               0xe7, 0xcc, 0xb5, 0xba, 0xe8, 0x2f, 0x67, 0x61, 0x00, 0xaf,
+               0x86, 0xf2, 0xbf, 0x59, 0x04, 0x11, 0xb6, 0x33, 0xa4, 0x30,
+               0x15, 0x10, 0x0a, 0x42, 0x18, 0xf8, 0x17, 0xd9, 0x07, 0x22,
+               0x19, 0x10,
+               },
+
+       /*  8 MHz bandwidth */
+               {
+               0x09, 0xf6, 0xd2, 0xa7, 0x9a, 0xc9, 0x27, 0x77, 0x06, 0xbf,
+               0xec, 0xf4, 0x4f, 0x0b, 0xfc, 0x01, 0x63, 0x35, 0x54, 0xa7,
+               0x16, 0x66, 0x08, 0xb4, 0x19, 0x6e, 0x19, 0x65, 0x05, 0xc8,
+               0x19, 0xe0,
+               },
+       };
+
+
+       dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
+               c->frequency, c->bandwidth_hz, c->inversion);
+
+
+       /* program tuner */
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe);
+
+
+       switch (c->bandwidth_hz) {
+       case 6000000:
+               i = 0;
+               bw_mode = 48000000;
+               break;
+       case 7000000:
+               i = 1;
+               bw_mode = 56000000;
+               break;
+       case 8000000:
+               i = 2;
+               bw_mode = 64000000;
+               break;
+       default:
+               dbg("invalid bandwidth");
+               return -EINVAL;
+       }
+
+       for (j = 0; j < sizeof(bw_params[j]); j++) {
+               ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1);
+               if (ret)
+                       goto err;
+       }
+
+       /* calculate and set resample ratio
+       * RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22)
+       *       / ConstWithBandwidthMode)
+       */
+       num = priv->cfg.xtal * 7;
+       num *= 0x400000;
+       num = div_u64(num, bw_mode);
+       resamp_ratio =  num & 0x3ffffff;
+       ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio);
+       if (ret)
+               goto err;
+
+       /* calculate and set cfreq off ratio
+       * CFREQ_OFF_RATIO = - floor(ConstWithBandwidthMode * pow(2, 20)
+       *       / (CrystalFreqHz * 7))
+       */
+       num = bw_mode << 20;
+       num2 = priv->cfg.xtal * 7;
+       num = div_u64(num, num2);
+       num = -num;
+       cfreq_off_ratio = num & 0xfffff;
+       ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
+       if (ret)
+               goto err;
+
+
+       /* soft reset */
+       ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
+       if (ret)
+               goto err;
+
+       ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
+       if (ret)
+               goto err;
+
+       return ret;
+err:
+       info("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct rtl2832_priv *priv = fe->demodulator_priv;
+       int ret;
+       u32 tmp;
+       *status = 0;
+
+
+       dbg("%s", __func__);
+       if (priv->sleeping)
+               return 0;
+
+       ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp);
+       if (ret)
+               goto err;
+
+       if (tmp == 11) {
+               *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                               FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+       }
+       /* TODO find out if this is also true for rtl2832? */
+       /*else if (tmp == 10) {
+               *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                               FE_HAS_VITERBI;
+       }*/
+
+       return ret;
+err:
+       info("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       *snr = 0;
+       return 0;
+}
+
+static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       *ber = 0;
+       return 0;
+}
+
+static int rtl2832_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       *ucblocks = 0;
+       return 0;
+}
+
+
+static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       *strength = 0;
+       return 0;
+}
+
+static struct dvb_frontend_ops rtl2832_ops;
+
+static void rtl2832_release(struct dvb_frontend *fe)
+{
+       struct rtl2832_priv *priv = fe->demodulator_priv;
+
+       dbg("%s", __func__);
+       kfree(priv);
+}
+
+struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
+       struct i2c_adapter *i2c)
+{
+       struct rtl2832_priv *priv = NULL;
+       int ret = 0;
+       u8 tmp;
+
+       dbg("%s", __func__);
+
+       /* allocate memory for the internal state */
+       priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL);
+       if (priv == NULL)
+               goto err;
+
+       /* setup the priv */
+       priv->i2c = i2c;
+       priv->tuner = cfg->tuner;
+       memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config));
+
+       /* check if the demod is there */
+       ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
+       if (ret)
+               goto err;
+
+       /* create dvb_frontend */
+       memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
+       priv->fe.demodulator_priv = priv;
+
+       /* TODO implement sleep mode */
+       priv->sleeping = true;
+
+       return &priv->fe;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       kfree(priv);
+       return NULL;
+}
+EXPORT_SYMBOL(rtl2832_attach);
+
+static struct dvb_frontend_ops rtl2832_ops = {
+       .delsys = { SYS_DVBT },
+       .info = {
+               .name = "Realtek RTL2832 (DVB-T)",
+               .frequency_min    = 174000000,
+               .frequency_max    = 862000000,
+               .frequency_stepsize = 166667,
+               .caps = FE_CAN_FEC_1_2 |
+                       FE_CAN_FEC_2_3 |
+                       FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 |
+                       FE_CAN_FEC_7_8 |
+                       FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK |
+                       FE_CAN_QAM_16 |
+                       FE_CAN_QAM_64 |
+                       FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO |
+                       FE_CAN_RECOVER |
+                       FE_CAN_MUTE_TS
+        },
+
+       .release = rtl2832_release,
+
+       .init = rtl2832_init,
+       .sleep = rtl2832_sleep,
+
+       .get_tune_settings = rtl2832_get_tune_settings,
+
+       .set_frontend = rtl2832_set_frontend,
+
+       .read_status = rtl2832_read_status,
+       .read_snr = rtl2832_read_snr,
+       .read_ber = rtl2832_read_ber,
+       .read_ucblocks = rtl2832_read_ucblocks,
+       .read_signal_strength = rtl2832_read_signal_strength,
+       .i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
+};
+
+MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
+MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.5");
diff --git a/drivers/media/dvb/frontends/rtl2832.h b/drivers/media/dvb/frontends/rtl2832.h
new file mode 100644 (file)
index 0000000..d94dc9a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL2832_H
+#define RTL2832_H
+
+#include <linux/dvb/frontend.h>
+
+struct rtl2832_config {
+       /*
+        * Demodulator I2C address.
+        */
+       u8 i2c_addr;
+
+       /*
+        * Xtal frequency.
+        * Hz
+        * 4000000, 16000000, 25000000, 28800000
+        */
+       u32 xtal;
+
+       /*
+        * IFs for all used modes.
+        * Hz
+        * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
+        */
+       u32 if_dvbt;
+
+       /*
+        */
+       u8 tuner;
+};
+
+
+#if defined(CONFIG_DVB_RTL2832) || \
+       (defined(CONFIG_DVB_RTL2832_MODULE) && defined(MODULE))
+extern struct dvb_frontend *rtl2832_attach(
+       const struct rtl2832_config *cfg,
+       struct i2c_adapter *i2c
+);
+
+extern struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
+       struct dvb_frontend *fe
+);
+#else
+static inline struct dvb_frontend *rtl2832_attach(
+       const struct rtl2832_config *config,
+       struct i2c_adapter *i2c
+)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+
+#endif /* RTL2832_H */
diff --git a/drivers/media/dvb/frontends/rtl2832_priv.h b/drivers/media/dvb/frontends/rtl2832_priv.h
new file mode 100644 (file)
index 0000000..0ce9502
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL2832_PRIV_H
+#define RTL2832_PRIV_H
+
+#include "dvb_frontend.h"
+#include "rtl2832.h"
+
+#define LOG_PREFIX "rtl2832"
+
+#undef dbg
+#define dbg(f, arg...) \
+do { \
+       if (rtl2832_debug)  \
+               printk(KERN_INFO     LOG_PREFIX": " f "\n" , ## arg); \
+} while (0)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct rtl2832_priv {
+       struct i2c_adapter *i2c;
+       struct dvb_frontend fe;
+       struct rtl2832_config cfg;
+
+       bool i2c_gate_state;
+       bool sleeping;
+
+       u8 tuner;
+       u8 page; /* active register page */
+};
+
+struct rtl2832_reg_entry {
+       u8 page;
+       u8 start_address;
+       u8 msb;
+       u8 lsb;
+};
+
+struct rtl2832_reg_value {
+       int reg;
+       u32 value;
+};
+
+
+/* Demod register bit names */
+enum DVBT_REG_BIT_NAME {
+       DVBT_SOFT_RST,
+       DVBT_IIC_REPEAT,
+       DVBT_TR_WAIT_MIN_8K,
+       DVBT_RSD_BER_FAIL_VAL,
+       DVBT_EN_BK_TRK,
+       DVBT_REG_PI,
+       DVBT_REG_PFREQ_1_0,
+       DVBT_PD_DA8,
+       DVBT_LOCK_TH,
+       DVBT_BER_PASS_SCAL,
+       DVBT_CE_FFSM_BYPASS,
+       DVBT_ALPHAIIR_N,
+       DVBT_ALPHAIIR_DIF,
+       DVBT_EN_TRK_SPAN,
+       DVBT_LOCK_TH_LEN,
+       DVBT_CCI_THRE,
+       DVBT_CCI_MON_SCAL,
+       DVBT_CCI_M0,
+       DVBT_CCI_M1,
+       DVBT_CCI_M2,
+       DVBT_CCI_M3,
+       DVBT_SPEC_INIT_0,
+       DVBT_SPEC_INIT_1,
+       DVBT_SPEC_INIT_2,
+       DVBT_AD_EN_REG,
+       DVBT_AD_EN_REG1,
+       DVBT_EN_BBIN,
+       DVBT_MGD_THD0,
+       DVBT_MGD_THD1,
+       DVBT_MGD_THD2,
+       DVBT_MGD_THD3,
+       DVBT_MGD_THD4,
+       DVBT_MGD_THD5,
+       DVBT_MGD_THD6,
+       DVBT_MGD_THD7,
+       DVBT_EN_CACQ_NOTCH,
+       DVBT_AD_AV_REF,
+       DVBT_PIP_ON,
+       DVBT_SCALE1_B92,
+       DVBT_SCALE1_B93,
+       DVBT_SCALE1_BA7,
+       DVBT_SCALE1_BA9,
+       DVBT_SCALE1_BAA,
+       DVBT_SCALE1_BAB,
+       DVBT_SCALE1_BAC,
+       DVBT_SCALE1_BB0,
+       DVBT_SCALE1_BB1,
+       DVBT_KB_P1,
+       DVBT_KB_P2,
+       DVBT_KB_P3,
+       DVBT_OPT_ADC_IQ,
+       DVBT_AD_AVI,
+       DVBT_AD_AVQ,
+       DVBT_K1_CR_STEP12,
+       DVBT_TRK_KS_P2,
+       DVBT_TRK_KS_I2,
+       DVBT_TR_THD_SET2,
+       DVBT_TRK_KC_P2,
+       DVBT_TRK_KC_I2,
+       DVBT_CR_THD_SET2,
+       DVBT_PSET_IFFREQ,
+       DVBT_SPEC_INV,
+       DVBT_BW_INDEX,
+       DVBT_RSAMP_RATIO,
+       DVBT_CFREQ_OFF_RATIO,
+       DVBT_FSM_STAGE,
+       DVBT_RX_CONSTEL,
+       DVBT_RX_HIER,
+       DVBT_RX_C_RATE_LP,
+       DVBT_RX_C_RATE_HP,
+       DVBT_GI_IDX,
+       DVBT_FFT_MODE_IDX,
+       DVBT_RSD_BER_EST,
+       DVBT_CE_EST_EVM,
+       DVBT_RF_AGC_VAL,
+       DVBT_IF_AGC_VAL,
+       DVBT_DAGC_VAL,
+       DVBT_SFREQ_OFF,
+       DVBT_CFREQ_OFF,
+       DVBT_POLAR_RF_AGC,
+       DVBT_POLAR_IF_AGC,
+       DVBT_AAGC_HOLD,
+       DVBT_EN_RF_AGC,
+       DVBT_EN_IF_AGC,
+       DVBT_IF_AGC_MIN,
+       DVBT_IF_AGC_MAX,
+       DVBT_RF_AGC_MIN,
+       DVBT_RF_AGC_MAX,
+       DVBT_IF_AGC_MAN,
+       DVBT_IF_AGC_MAN_VAL,
+       DVBT_RF_AGC_MAN,
+       DVBT_RF_AGC_MAN_VAL,
+       DVBT_DAGC_TRG_VAL,
+       DVBT_AGC_TARG_VAL,
+       DVBT_LOOP_GAIN_3_0,
+       DVBT_LOOP_GAIN_4,
+       DVBT_VTOP,
+       DVBT_KRF,
+       DVBT_AGC_TARG_VAL_0,
+       DVBT_AGC_TARG_VAL_8_1,
+       DVBT_AAGC_LOOP_GAIN,
+       DVBT_LOOP_GAIN2_3_0,
+       DVBT_LOOP_GAIN2_4,
+       DVBT_LOOP_GAIN3,
+       DVBT_VTOP1,
+       DVBT_VTOP2,
+       DVBT_VTOP3,
+       DVBT_KRF1,
+       DVBT_KRF2,
+       DVBT_KRF3,
+       DVBT_KRF4,
+       DVBT_EN_GI_PGA,
+       DVBT_THD_LOCK_UP,
+       DVBT_THD_LOCK_DW,
+       DVBT_THD_UP1,
+       DVBT_THD_DW1,
+       DVBT_INTER_CNT_LEN,
+       DVBT_GI_PGA_STATE,
+       DVBT_EN_AGC_PGA,
+       DVBT_CKOUTPAR,
+       DVBT_CKOUT_PWR,
+       DVBT_SYNC_DUR,
+       DVBT_ERR_DUR,
+       DVBT_SYNC_LVL,
+       DVBT_ERR_LVL,
+       DVBT_VAL_LVL,
+       DVBT_SERIAL,
+       DVBT_SER_LSB,
+       DVBT_CDIV_PH0,
+       DVBT_CDIV_PH1,
+       DVBT_MPEG_IO_OPT_2_2,
+       DVBT_MPEG_IO_OPT_1_0,
+       DVBT_CKOUTPAR_PIP,
+       DVBT_CKOUT_PWR_PIP,
+       DVBT_SYNC_LVL_PIP,
+       DVBT_ERR_LVL_PIP,
+       DVBT_VAL_LVL_PIP,
+       DVBT_CKOUTPAR_PID,
+       DVBT_CKOUT_PWR_PID,
+       DVBT_SYNC_LVL_PID,
+       DVBT_ERR_LVL_PID,
+       DVBT_VAL_LVL_PID,
+       DVBT_SM_PASS,
+       DVBT_UPDATE_REG_2,
+       DVBT_BTHD_P3,
+       DVBT_BTHD_D3,
+       DVBT_FUNC4_REG0,
+       DVBT_FUNC4_REG1,
+       DVBT_FUNC4_REG2,
+       DVBT_FUNC4_REG3,
+       DVBT_FUNC4_REG4,
+       DVBT_FUNC4_REG5,
+       DVBT_FUNC4_REG6,
+       DVBT_FUNC4_REG7,
+       DVBT_FUNC4_REG8,
+       DVBT_FUNC4_REG9,
+       DVBT_FUNC4_REG10,
+       DVBT_FUNC5_REG0,
+       DVBT_FUNC5_REG1,
+       DVBT_FUNC5_REG2,
+       DVBT_FUNC5_REG3,
+       DVBT_FUNC5_REG4,
+       DVBT_FUNC5_REG5,
+       DVBT_FUNC5_REG6,
+       DVBT_FUNC5_REG7,
+       DVBT_FUNC5_REG8,
+       DVBT_FUNC5_REG9,
+       DVBT_FUNC5_REG10,
+       DVBT_FUNC5_REG11,
+       DVBT_FUNC5_REG12,
+       DVBT_FUNC5_REG13,
+       DVBT_FUNC5_REG14,
+       DVBT_FUNC5_REG15,
+       DVBT_FUNC5_REG16,
+       DVBT_FUNC5_REG17,
+       DVBT_FUNC5_REG18,
+       DVBT_AD7_SETTING,
+       DVBT_RSSI_R,
+       DVBT_ACI_DET_IND,
+       DVBT_REG_MON,
+       DVBT_REG_MONSEL,
+       DVBT_REG_GPE,
+       DVBT_REG_GPO,
+       DVBT_REG_4MSEL,
+       DVBT_TEST_REG_1,
+       DVBT_TEST_REG_2,
+       DVBT_TEST_REG_3,
+       DVBT_TEST_REG_4,
+       DVBT_REG_BIT_NAME_ITEM_TERMINATOR,
+};
+
+#endif /* RTL2832_PRIV_H */
index 2322257c69ae33bb5af5ed2ea200b82a671ff18a..e2fec9ebf947d6b5c0ca03eeb50befd233f6f19a 100644 (file)
@@ -634,7 +634,6 @@ static int s5h1420_set_frontend(struct dvb_frontend *fe)
        struct s5h1420_state* state = fe->demodulator_priv;
        int frequency_delta;
        struct dvb_frontend_tune_settings fesettings;
-       uint8_t clock_setting;
 
        dprintk("enter %s\n", __func__);
 
@@ -679,25 +678,6 @@ static int s5h1420_set_frontend(struct dvb_frontend *fe)
        else
                state->fclk = 44000000;
 
-       /* Clock */
-       switch (state->fclk) {
-       default:
-       case 88000000:
-               clock_setting = 80;
-               break;
-       case 86000000:
-               clock_setting = 78;
-               break;
-       case 80000000:
-               clock_setting = 72;
-               break;
-       case 59000000:
-               clock_setting = 51;
-               break;
-       case 44000000:
-               clock_setting = 36;
-               break;
-       }
        dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
        s5h1420_writereg(state, PLL01, state->fclk/1000000 - 8);
        s5h1420_writereg(state, PLL02, 0x40);
index 8b0dc74a3298c8ec03d99cf40b1faa2be0e8a2ba..5d7f8a9b451b8ec93fc596a6d813004b8866cd87 100644 (file)
@@ -1129,7 +1129,6 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
        struct stb0899_internal *internal       = &state->internal;
 
        u8  lsb, msb;
-       u32 i;
 
        *ber = 0;
 
@@ -1137,14 +1136,9 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
        case SYS_DVBS:
        case SYS_DSS:
                if (internal->lock) {
-                       /* average 5 BER values */
-                       for (i = 0; i < 5; i++) {
-                               msleep(100);
-                               lsb = stb0899_read_reg(state, STB0899_ECNT1L);
-                               msb = stb0899_read_reg(state, STB0899_ECNT1M);
-                               *ber += MAKEWORD16(msb, lsb);
-                       }
-                       *ber /= 5;
+                       lsb = stb0899_read_reg(state, STB0899_ECNT1L);
+                       msb = stb0899_read_reg(state, STB0899_ECNT1M);
+                       *ber = MAKEWORD16(msb, lsb);
                        /* Viterbi Check        */
                        if (STB0899_GETFIELD(VSTATUS_PRFVIT, internal->v_status)) {
                                /* Error Rate           */
@@ -1157,13 +1151,9 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
                break;
        case SYS_DVBS2:
                if (internal->lock) {
-                       /* Average 5 PER values */
-                       for (i = 0; i < 5; i++) {
-                               msleep(100);
-                               lsb = stb0899_read_reg(state, STB0899_ECNT1L);
-                               msb = stb0899_read_reg(state, STB0899_ECNT1M);
-                               *ber += MAKEWORD16(msb, lsb);
-                       }
+                       lsb = stb0899_read_reg(state, STB0899_ECNT1L);
+                       msb = stb0899_read_reg(state, STB0899_ECNT1M);
+                       *ber = MAKEWORD16(msb, lsb);
                        /* ber = ber * 10 ^ 7   */
                        *ber *= 10000000;
                        *ber /= (-1 + (1 << (4 + 2 * STB0899_GETFIELD(NOE, internal->err_ctrl))));
index fdd20c7737b57a968d4e5e8edf4d9900ef859d2b..2a8aaeb1112dc10ef1267531c36eb14bbd1c8989 100644 (file)
@@ -1584,7 +1584,7 @@ static int stv0367ter_algo(struct dvb_frontend *fe)
        struct stv0367ter_state *ter_state = state->ter_state;
        int offset = 0, tempo = 0;
        u8 u_var;
-       u8 /*constell,*/ counter, tps_rcvd[2];
+       u8 /*constell,*/ counter;
        s8 step;
        s32 timing_offset = 0;
        u32 trl_nomrate = 0, InternalFreq = 0, temp = 0;
@@ -1709,9 +1709,6 @@ static int stv0367ter_algo(struct dvb_frontend *fe)
                return 0;
 
        ter_state->state = FE_TER_LOCKOK;
-       /* update results */
-       tps_rcvd[0] = stv0367_readreg(state, R367TER_TPS_RCVD2);
-       tps_rcvd[1] = stv0367_readreg(state, R367TER_TPS_RCVD3);
 
        ter_state->mode = stv0367_readbits(state, F367TER_SYR_MODE);
        ter_state->guard = stv0367_readbits(state, F367TER_SYR_GUARD);
index d79e69f65cbb6ee39d9c1b28b6917b37e5182a1b..ea86a5603e5756106a342a18668d3b8889ebdd1e 100644 (file)
@@ -3172,7 +3172,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
        enum stv090x_signal_state signal_state = STV090x_NOCARRIER;
        u32 reg;
        s32 agc1_power, power_iq = 0, i;
-       int lock = 0, low_sr = 0, no_signal = 0;
+       int lock = 0, low_sr = 0;
 
        reg = STV090x_READ_DEMOD(state, TSCFGH);
        STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* Stop path 1 stream merger */
@@ -3413,7 +3413,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
                                goto err;
                } else {
                        signal_state = STV090x_NODATA;
-                       no_signal = stv090x_chk_signal(state);
+                       stv090x_chk_signal(state);
                }
        }
        return signal_state;
index c21bc92d2811219d11c468ece8fc9a171498a131..703c3d05f9f453f67f054234f4e86818743ff5f9 100644 (file)
 
 #include "tda10071_priv.h"
 
-int tda10071_debug;
-module_param_named(debug, tda10071_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-
 static struct dvb_frontend_ops tda10071_ops;
 
 /* write multiple registers */
@@ -48,7 +44,8 @@ static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
        if (ret == 1) {
                ret = 0;
        } else {
-               warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+               dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
+                               "len=%d\n", KBUILD_MODNAME, ret, reg, len);
                ret = -EREMOTEIO;
        }
        return ret;
@@ -79,7 +76,8 @@ static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val,
                memcpy(val, buf, len);
                ret = 0;
        } else {
-               warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+               dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
+                               "len=%d\n", KBUILD_MODNAME, ret, reg, len);
                ret = -EREMOTEIO;
        }
        return ret;
@@ -170,7 +168,7 @@ static int tda10071_cmd_execute(struct tda10071_priv *priv,
                usleep_range(200, 5000);
        }
 
-       dbg("%s: loop=%d", __func__, i);
+       dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
 
        if (i == 0) {
                ret = -ETIMEDOUT;
@@ -179,7 +177,7 @@ static int tda10071_cmd_execute(struct tda10071_priv *priv,
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -196,7 +194,8 @@ static int tda10071_set_tone(struct dvb_frontend *fe,
                goto error;
        }
 
-       dbg("%s: tone_mode=%d", __func__, fe_sec_tone_mode);
+       dev_dbg(&priv->i2c->dev, "%s: tone_mode=%d\n", __func__,
+                       fe_sec_tone_mode);
 
        switch (fe_sec_tone_mode) {
        case SEC_TONE_ON:
@@ -206,24 +205,25 @@ static int tda10071_set_tone(struct dvb_frontend *fe,
                tone = 0;
                break;
        default:
-               dbg("%s: invalid fe_sec_tone_mode", __func__);
+               dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_tone_mode\n",
+                               __func__);
                ret = -EINVAL;
                goto error;
        }
 
-       cmd.args[0x00] = CMD_LNB_PCB_CONFIG;
-       cmd.args[0x01] = 0;
-       cmd.args[0x02] = 0x00;
-       cmd.args[0x03] = 0x00;
-       cmd.args[0x04] = tone;
-       cmd.len = 0x05;
+       cmd.args[0] = CMD_LNB_PCB_CONFIG;
+       cmd.args[1] = 0;
+       cmd.args[2] = 0x00;
+       cmd.args[3] = 0x00;
+       cmd.args[4] = tone;
+       cmd.len = 5;
        ret = tda10071_cmd_execute(priv, &cmd);
        if (ret)
                goto error;
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -240,7 +240,7 @@ static int tda10071_set_voltage(struct dvb_frontend *fe,
                goto error;
        }
 
-       dbg("%s: voltage=%d", __func__, fe_sec_voltage);
+       dev_dbg(&priv->i2c->dev, "%s: voltage=%d\n", __func__, fe_sec_voltage);
 
        switch (fe_sec_voltage) {
        case SEC_VOLTAGE_13:
@@ -253,22 +253,23 @@ static int tda10071_set_voltage(struct dvb_frontend *fe,
                voltage = 0;
                break;
        default:
-               dbg("%s: invalid fe_sec_voltage", __func__);
+               dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_voltage\n",
+                               __func__);
                ret = -EINVAL;
                goto error;
        };
 
-       cmd.args[0x00] = CMD_LNB_SET_DC_LEVEL;
-       cmd.args[0x01] = 0;
-       cmd.args[0x02] = voltage;
-       cmd.len = 0x03;
+       cmd.args[0] = CMD_LNB_SET_DC_LEVEL;
+       cmd.args[1] = 0;
+       cmd.args[2] = voltage;
+       cmd.len = 3;
        ret = tda10071_cmd_execute(priv, &cmd);
        if (ret)
                goto error;
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -285,9 +286,10 @@ static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe,
                goto error;
        }
 
-       dbg("%s: msg_len=%d", __func__, diseqc_cmd->msg_len);
+       dev_dbg(&priv->i2c->dev, "%s: msg_len=%d\n", __func__,
+                       diseqc_cmd->msg_len);
 
-       if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 16) {
+       if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 6) {
                ret = -EINVAL;
                goto error;
        }
@@ -301,7 +303,7 @@ static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe,
                usleep_range(10000, 20000);
        }
 
-       dbg("%s: loop=%d", __func__, i);
+       dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
 
        if (i == 0) {
                ret = -ETIMEDOUT;
@@ -312,22 +314,22 @@ static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe,
        if (ret)
                goto error;
 
-       cmd.args[0x00] = CMD_LNB_SEND_DISEQC;
-       cmd.args[0x01] = 0;
-       cmd.args[0x02] = 0;
-       cmd.args[0x03] = 0;
-       cmd.args[0x04] = 2;
-       cmd.args[0x05] = 0;
-       cmd.args[0x06] = diseqc_cmd->msg_len;
-       memcpy(&cmd.args[0x07], diseqc_cmd->msg, diseqc_cmd->msg_len);
-       cmd.len = 0x07 + diseqc_cmd->msg_len;
+       cmd.args[0] = CMD_LNB_SEND_DISEQC;
+       cmd.args[1] = 0;
+       cmd.args[2] = 0;
+       cmd.args[3] = 0;
+       cmd.args[4] = 2;
+       cmd.args[5] = 0;
+       cmd.args[6] = diseqc_cmd->msg_len;
+       memcpy(&cmd.args[7], diseqc_cmd->msg, diseqc_cmd->msg_len);
+       cmd.len = 7 + diseqc_cmd->msg_len;
        ret = tda10071_cmd_execute(priv, &cmd);
        if (ret)
                goto error;
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -344,7 +346,7 @@ static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe,
                goto error;
        }
 
-       dbg("%s:", __func__);
+       dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
        /* wait LNB RX */
        for (i = 500, tmp = 0; i && !tmp; i--) {
@@ -355,7 +357,7 @@ static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe,
                usleep_range(10000, 20000);
        }
 
-       dbg("%s: loop=%d", __func__, i);
+       dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
 
        if (i == 0) {
                ret = -ETIMEDOUT;
@@ -372,9 +374,9 @@ static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe,
                reply->msg_len = sizeof(reply->msg); /* truncate API max */
 
        /* read reply */
-       cmd.args[0x00] = CMD_LNB_UPDATE_REPLY;
-       cmd.args[0x01] = 0;
-       cmd.len = 0x02;
+       cmd.args[0] = CMD_LNB_UPDATE_REPLY;
+       cmd.args[1] = 0;
+       cmd.len = 2;
        ret = tda10071_cmd_execute(priv, &cmd);
        if (ret)
                goto error;
@@ -385,7 +387,7 @@ static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe,
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -402,7 +404,8 @@ static int tda10071_diseqc_send_burst(struct dvb_frontend *fe,
                goto error;
        }
 
-       dbg("%s: fe_sec_mini_cmd=%d", __func__, fe_sec_mini_cmd);
+       dev_dbg(&priv->i2c->dev, "%s: fe_sec_mini_cmd=%d\n", __func__,
+                       fe_sec_mini_cmd);
 
        switch (fe_sec_mini_cmd) {
        case SEC_MINI_A:
@@ -412,7 +415,8 @@ static int tda10071_diseqc_send_burst(struct dvb_frontend *fe,
                burst = 1;
                break;
        default:
-               dbg("%s: invalid fe_sec_mini_cmd", __func__);
+               dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_mini_cmd\n",
+                               __func__);
                ret = -EINVAL;
                goto error;
        }
@@ -426,7 +430,7 @@ static int tda10071_diseqc_send_burst(struct dvb_frontend *fe,
                usleep_range(10000, 20000);
        }
 
-       dbg("%s: loop=%d", __func__, i);
+       dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
 
        if (i == 0) {
                ret = -ETIMEDOUT;
@@ -437,17 +441,17 @@ static int tda10071_diseqc_send_burst(struct dvb_frontend *fe,
        if (ret)
                goto error;
 
-       cmd.args[0x00] = CMD_LNB_SEND_TONEBURST;
-       cmd.args[0x01] = 0;
-       cmd.args[0x02] = burst;
-       cmd.len = 0x03;
+       cmd.args[0] = CMD_LNB_SEND_TONEBURST;
+       cmd.args[1] = 0;
+       cmd.args[2] = burst;
+       cmd.len = 3;
        ret = tda10071_cmd_execute(priv, &cmd);
        if (ret)
                goto error;
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -481,7 +485,7 @@ static int tda10071_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -506,7 +510,7 @@ static int tda10071_read_snr(struct dvb_frontend *fe, u16 *snr)
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -523,9 +527,9 @@ static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
                goto error;
        }
 
-       cmd.args[0x00] = CMD_GET_AGCACC;
-       cmd.args[0x01] = 0;
-       cmd.len = 0x02;
+       cmd.args[0] = CMD_GET_AGCACC;
+       cmd.args[1] = 0;
+       cmd.len = 2;
        ret = tda10071_cmd_execute(priv, &cmd);
        if (ret)
                goto error;
@@ -545,7 +549,7 @@ static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -583,17 +587,18 @@ static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber)
                goto error;
 
        if (priv->meas_count[i] == tmp) {
-               dbg("%s: meas not ready=%02x", __func__, tmp);
+               dev_dbg(&priv->i2c->dev, "%s: meas not ready=%02x\n", __func__,
+                               tmp);
                *ber = priv->ber;
                return 0;
        } else {
                priv->meas_count[i] = tmp;
        }
 
-       cmd.args[0x00] = CMD_BER_UPDATE_COUNTERS;
-       cmd.args[0x01] = 0;
-       cmd.args[0x02] = i;
-       cmd.len = 0x03;
+       cmd.args[0] = CMD_BER_UPDATE_COUNTERS;
+       cmd.args[1] = 0;
+       cmd.args[2] = i;
+       cmd.len = 3;
        ret = tda10071_cmd_execute(priv, &cmd);
        if (ret)
                goto error;
@@ -612,7 +617,7 @@ static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber)
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -632,7 +637,7 @@ static int tda10071_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -644,10 +649,11 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
        int ret, i;
        u8 mode, rolloff, pilot, inversion, div;
 
-       dbg("%s: delivery_system=%d modulation=%d frequency=%d " \
-               "symbol_rate=%d inversion=%d pilot=%d rolloff=%d", __func__,
-               c->delivery_system, c->modulation, c->frequency,
-               c->symbol_rate, c->inversion, c->pilot, c->rolloff);
+       dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d modulation=%d " \
+               "frequency=%d symbol_rate=%d inversion=%d pilot=%d " \
+               "rolloff=%d\n", __func__, c->delivery_system, c->modulation,
+               c->frequency, c->symbol_rate, c->inversion, c->pilot,
+               c->rolloff);
 
        priv->delivery_system = SYS_UNDEFINED;
 
@@ -669,7 +675,7 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
                inversion = 3;
                break;
        default:
-               dbg("%s: invalid inversion", __func__);
+               dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n", __func__);
                ret = -EINVAL;
                goto error;
        }
@@ -692,7 +698,8 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
                        break;
                case ROLLOFF_AUTO:
                default:
-                       dbg("%s: invalid rolloff", __func__);
+                       dev_dbg(&priv->i2c->dev, "%s: invalid rolloff\n",
+                                       __func__);
                        ret = -EINVAL;
                        goto error;
                }
@@ -708,13 +715,15 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
                        pilot = 2;
                        break;
                default:
-                       dbg("%s: invalid pilot", __func__);
+                       dev_dbg(&priv->i2c->dev, "%s: invalid pilot\n",
+                                       __func__);
                        ret = -EINVAL;
                        goto error;
                }
                break;
        default:
-               dbg("%s: invalid delivery_system", __func__);
+               dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n",
+                               __func__);
                ret = -EINVAL;
                goto error;
        }
@@ -724,13 +733,15 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
                        c->modulation == TDA10071_MODCOD[i].modulation &&
                        c->fec_inner == TDA10071_MODCOD[i].fec) {
                        mode = TDA10071_MODCOD[i].val;
-                       dbg("%s: mode found=%02x", __func__, mode);
+                       dev_dbg(&priv->i2c->dev, "%s: mode found=%02x\n",
+                                       __func__, mode);
                        break;
                }
        }
 
        if (mode == 0xff) {
-               dbg("%s: invalid parameter combination", __func__);
+               dev_dbg(&priv->i2c->dev, "%s: invalid parameter combination\n",
+                               __func__);
                ret = -EINVAL;
                goto error;
        }
@@ -748,22 +759,22 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
        if (ret)
                goto error;
 
-       cmd.args[0x00] = CMD_CHANGE_CHANNEL;
-       cmd.args[0x01] = 0;
-       cmd.args[0x02] = mode;
-       cmd.args[0x03] = (c->frequency >> 16) & 0xff;
-       cmd.args[0x04] = (c->frequency >>  8) & 0xff;
-       cmd.args[0x05] = (c->frequency >>  0) & 0xff;
-       cmd.args[0x06] = ((c->symbol_rate / 1000) >> 8) & 0xff;
-       cmd.args[0x07] = ((c->symbol_rate / 1000) >> 0) & 0xff;
-       cmd.args[0x08] = (tda10071_ops.info.frequency_tolerance >> 8) & 0xff;
-       cmd.args[0x09] = (tda10071_ops.info.frequency_tolerance >> 0) & 0xff;
-       cmd.args[0x0a] = rolloff;
-       cmd.args[0x0b] = inversion;
-       cmd.args[0x0c] = pilot;
-       cmd.args[0x0d] = 0x00;
-       cmd.args[0x0e] = 0x00;
-       cmd.len = 0x0f;
+       cmd.args[0] = CMD_CHANGE_CHANNEL;
+       cmd.args[1] = 0;
+       cmd.args[2] = mode;
+       cmd.args[3] = (c->frequency >> 16) & 0xff;
+       cmd.args[4] = (c->frequency >>  8) & 0xff;
+       cmd.args[5] = (c->frequency >>  0) & 0xff;
+       cmd.args[6] = ((c->symbol_rate / 1000) >> 8) & 0xff;
+       cmd.args[7] = ((c->symbol_rate / 1000) >> 0) & 0xff;
+       cmd.args[8] = (tda10071_ops.info.frequency_tolerance >> 8) & 0xff;
+       cmd.args[9] = (tda10071_ops.info.frequency_tolerance >> 0) & 0xff;
+       cmd.args[10] = rolloff;
+       cmd.args[11] = inversion;
+       cmd.args[12] = pilot;
+       cmd.args[13] = 0x00;
+       cmd.args[14] = 0x00;
+       cmd.len = 15;
        ret = tda10071_cmd_execute(priv, &cmd);
        if (ret)
                goto error;
@@ -772,7 +783,7 @@ static int tda10071_set_frontend(struct dvb_frontend *fe)
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -829,7 +840,7 @@ static int tda10071_get_frontend(struct dvb_frontend *fe)
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -915,10 +926,10 @@ static int tda10071_init(struct dvb_frontend *fe)
                                goto error;
                }
 
-               cmd.args[0x00] = CMD_SET_SLEEP_MODE;
-               cmd.args[0x01] = 0;
-               cmd.args[0x02] = 0;
-               cmd.len = 0x03;
+               cmd.args[0] = CMD_SET_SLEEP_MODE;
+               cmd.args[1] = 0;
+               cmd.args[2] = 0;
+               cmd.len = 3;
                ret = tda10071_cmd_execute(priv, &cmd);
                if (ret)
                        goto error;
@@ -929,10 +940,11 @@ static int tda10071_init(struct dvb_frontend *fe)
                /* request the firmware, this will block and timeout */
                ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent);
                if (ret) {
-                       err("did not find the firmware file. (%s) "
-                               "Please see linux/Documentation/dvb/ for more" \
-                               " details on firmware-problems. (%d)",
-                               fw_file, ret);
+                       dev_err(&priv->i2c->dev, "%s: did not find the " \
+                                       "firmware file. (%s) Please see " \
+                                       "linux/Documentation/dvb/ for more " \
+                                       "details on firmware-problems. (%d)\n",
+                                       KBUILD_MODNAME, fw_file, ret);
                        goto error;
                }
 
@@ -961,10 +973,11 @@ static int tda10071_init(struct dvb_frontend *fe)
                if (ret)
                        goto error_release_firmware;
 
-               info("found a '%s' in cold state, will try to load a firmware",
-                       tda10071_ops.info.name);
-
-               info("downloading firmware from file '%s'", fw_file);
+               dev_info(&priv->i2c->dev, "%s: found a '%s' in cold state, " \
+                               "will try to load a firmware\n", KBUILD_MODNAME,
+                               tda10071_ops.info.name);
+               dev_info(&priv->i2c->dev, "%s: downloading firmware from " \
+                               "file '%s'\n", KBUILD_MODNAME, fw_file);
 
                /* do not download last byte */
                fw_size = fw->size - 1;
@@ -978,7 +991,9 @@ static int tda10071_init(struct dvb_frontend *fe)
                        ret = tda10071_wr_regs(priv, 0xfa,
                                (u8 *) &fw->data[fw_size - remaining], len);
                        if (ret) {
-                               err("firmware download failed=%d", ret);
+                               dev_err(&priv->i2c->dev, "%s: firmware " \
+                                               "download failed=%d\n",
+                                               KBUILD_MODNAME, ret);
                                if (ret)
                                        goto error_release_firmware;
                        }
@@ -1002,15 +1017,16 @@ static int tda10071_init(struct dvb_frontend *fe)
                        goto error;
 
                if (tmp) {
-                       info("firmware did not run");
+                       dev_info(&priv->i2c->dev, "%s: firmware did not run\n",
+                                       KBUILD_MODNAME);
                        ret = -EFAULT;
                        goto error;
                } else {
                        priv->warm = 1;
                }
 
-               cmd.args[0x00] = CMD_GET_FW_VERSION;
-               cmd.len = 0x01;
+               cmd.args[0] = CMD_GET_FW_VERSION;
+               cmd.len = 1;
                ret = tda10071_cmd_execute(priv, &cmd);
                if (ret)
                        goto error;
@@ -1019,54 +1035,55 @@ static int tda10071_init(struct dvb_frontend *fe)
                if (ret)
                        goto error;
 
-               info("firmware version %d.%d.%d.%d",
-                       buf[0], buf[1], buf[2], buf[3]);
-               info("found a '%s' in warm state.", tda10071_ops.info.name);
+               dev_info(&priv->i2c->dev, "%s: firmware version %d.%d.%d.%d\n",
+                               KBUILD_MODNAME, buf[0], buf[1], buf[2], buf[3]);
+               dev_info(&priv->i2c->dev, "%s: found a '%s' in warm state\n",
+                               KBUILD_MODNAME, tda10071_ops.info.name);
 
                ret = tda10071_rd_regs(priv, 0x81, buf, 2);
                if (ret)
                        goto error;
 
-               cmd.args[0x00] = CMD_DEMOD_INIT;
-               cmd.args[0x01] = ((priv->cfg.xtal / 1000) >> 8) & 0xff;
-               cmd.args[0x02] = ((priv->cfg.xtal / 1000) >> 0) & 0xff;
-               cmd.args[0x03] = buf[0];
-               cmd.args[0x04] = buf[1];
-               cmd.args[0x05] = priv->cfg.pll_multiplier;
-               cmd.args[0x06] = priv->cfg.spec_inv;
-               cmd.args[0x07] = 0x00;
-               cmd.len = 0x08;
+               cmd.args[0] = CMD_DEMOD_INIT;
+               cmd.args[1] = ((priv->cfg.xtal / 1000) >> 8) & 0xff;
+               cmd.args[2] = ((priv->cfg.xtal / 1000) >> 0) & 0xff;
+               cmd.args[3] = buf[0];
+               cmd.args[4] = buf[1];
+               cmd.args[5] = priv->cfg.pll_multiplier;
+               cmd.args[6] = priv->cfg.spec_inv;
+               cmd.args[7] = 0x00;
+               cmd.len = 8;
                ret = tda10071_cmd_execute(priv, &cmd);
                if (ret)
                        goto error;
 
-               cmd.args[0x00] = CMD_TUNER_INIT;
-               cmd.args[0x01] = 0x00;
-               cmd.args[0x02] = 0x00;
-               cmd.args[0x03] = 0x00;
-               cmd.args[0x04] = 0x00;
-               cmd.args[0x05] = 0x14;
-               cmd.args[0x06] = 0x00;
-               cmd.args[0x07] = 0x03;
-               cmd.args[0x08] = 0x02;
-               cmd.args[0x09] = 0x02;
-               cmd.args[0x0a] = 0x00;
-               cmd.args[0x0b] = 0x00;
-               cmd.args[0x0c] = 0x00;
-               cmd.args[0x0d] = 0x00;
-               cmd.args[0x0e] = 0x00;
-               cmd.len = 0x0f;
+               cmd.args[0] = CMD_TUNER_INIT;
+               cmd.args[1] = 0x00;
+               cmd.args[2] = 0x00;
+               cmd.args[3] = 0x00;
+               cmd.args[4] = 0x00;
+               cmd.args[5] = 0x14;
+               cmd.args[6] = 0x00;
+               cmd.args[7] = 0x03;
+               cmd.args[8] = 0x02;
+               cmd.args[9] = 0x02;
+               cmd.args[10] = 0x00;
+               cmd.args[11] = 0x00;
+               cmd.args[12] = 0x00;
+               cmd.args[13] = 0x00;
+               cmd.args[14] = 0x00;
+               cmd.len = 15;
                ret = tda10071_cmd_execute(priv, &cmd);
                if (ret)
                        goto error;
 
-               cmd.args[0x00] = CMD_MPEG_CONFIG;
-               cmd.args[0x01] = 0;
-               cmd.args[0x02] = priv->cfg.ts_mode;
-               cmd.args[0x03] = 0x00;
-               cmd.args[0x04] = 0x04;
-               cmd.args[0x05] = 0x00;
-               cmd.len = 0x06;
+               cmd.args[0] = CMD_MPEG_CONFIG;
+               cmd.args[1] = 0;
+               cmd.args[2] = priv->cfg.ts_mode;
+               cmd.args[3] = 0x00;
+               cmd.args[4] = 0x04;
+               cmd.args[5] = 0x00;
+               cmd.len = 6;
                ret = tda10071_cmd_execute(priv, &cmd);
                if (ret)
                        goto error;
@@ -1075,27 +1092,27 @@ static int tda10071_init(struct dvb_frontend *fe)
                if (ret)
                        goto error;
 
-               cmd.args[0x00] = CMD_LNB_CONFIG;
-               cmd.args[0x01] = 0;
-               cmd.args[0x02] = 150;
-               cmd.args[0x03] = 3;
-               cmd.args[0x04] = 22;
-               cmd.args[0x05] = 1;
-               cmd.args[0x06] = 1;
-               cmd.args[0x07] = 30;
-               cmd.args[0x08] = 30;
-               cmd.args[0x09] = 30;
-               cmd.args[0x0a] = 30;
-               cmd.len = 0x0b;
+               cmd.args[0] = CMD_LNB_CONFIG;
+               cmd.args[1] = 0;
+               cmd.args[2] = 150;
+               cmd.args[3] = 3;
+               cmd.args[4] = 22;
+               cmd.args[5] = 1;
+               cmd.args[6] = 1;
+               cmd.args[7] = 30;
+               cmd.args[8] = 30;
+               cmd.args[9] = 30;
+               cmd.args[10] = 30;
+               cmd.len = 11;
                ret = tda10071_cmd_execute(priv, &cmd);
                if (ret)
                        goto error;
 
-               cmd.args[0x00] = CMD_BER_CONTROL;
-               cmd.args[0x01] = 0;
-               cmd.args[0x02] = 14;
-               cmd.args[0x03] = 14;
-               cmd.len = 0x04;
+               cmd.args[0] = CMD_BER_CONTROL;
+               cmd.args[1] = 0;
+               cmd.args[2] = 14;
+               cmd.args[3] = 14;
+               cmd.len = 4;
                ret = tda10071_cmd_execute(priv, &cmd);
                if (ret)
                        goto error;
@@ -1105,7 +1122,7 @@ static int tda10071_init(struct dvb_frontend *fe)
 error_release_firmware:
        release_firmware(fw);
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -1132,10 +1149,10 @@ static int tda10071_sleep(struct dvb_frontend *fe)
                goto error;
        }
 
-       cmd.args[0x00] = CMD_SET_SLEEP_MODE;
-       cmd.args[0x01] = 0;
-       cmd.args[0x02] = 1;
-       cmd.len = 0x03;
+       cmd.args[0] = CMD_SET_SLEEP_MODE;
+       cmd.args[1] = 0;
+       cmd.args[2] = 1;
+       cmd.len = 3;
        ret = tda10071_cmd_execute(priv, &cmd);
        if (ret)
                goto error;
@@ -1149,7 +1166,7 @@ static int tda10071_sleep(struct dvb_frontend *fe)
 
        return ret;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
@@ -1208,7 +1225,7 @@ struct dvb_frontend *tda10071_attach(const struct tda10071_config *config,
 
        return &priv->fe;
 error:
-       dbg("%s: failed=%d", __func__, ret);
+       dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
        kfree(priv);
        return NULL;
 }
index 93c5e6317f076f2b309db44d2f0786579dc8c426..0fa85cfa70c21d85b0f06952b0e8b035c6cd4c92 100644 (file)
 #include "tda10071.h"
 #include <linux/firmware.h>
 
-#define LOG_PREFIX "tda10071"
-
-#undef dbg
-#define dbg(f, arg...) \
-       if (tda10071_debug) \
-               printk(KERN_INFO   LOG_PREFIX": " f "\n" , ## arg)
-#undef err
-#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
-#undef info
-#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
-#undef warn
-#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
-
 struct tda10071_priv {
        struct i2c_adapter *i2c;
        struct dvb_frontend fe;
@@ -112,7 +99,7 @@ struct tda10071_reg_val_mask {
 #define CMD_BER_UPDATE_COUNTERS 0x3f
 
 /* firmare command struct */
-#define TDA10071_ARGLEN      0x1e
+#define TDA10071_ARGLEN      30
 struct tda10071_cmd {
        u8 args[TDA10071_ARGLEN];
        u8 len;
index 7539a5d7102964aaa094be28cd0ae7b9de245687..72ee8de0226025618ecd733716fa30f494eb646b 100644 (file)
@@ -217,6 +217,7 @@ static int demod_attach_drxk(struct ngene_channel *chan,
 
        memset(&config, 0, sizeof(config));
        config.microcode_name = "drxk_a3.mc";
+       config.qam_demod_parameter_count = 4;
        config.adr = 0x29 + (chan->number ^ 2);
 
        chan->fe = dvb_attach(drxk_attach, &config, i2c);
index c257da13d7663c57cc048d461590b3ce87014bc8..24ce5a47f9550d1383dd27c0e751c588775dfbbb 100644 (file)
@@ -5,6 +5,7 @@
 menuconfig RADIO_ADAPTERS
        bool "Radio Adapters"
        depends on VIDEO_V4L2
+       depends on MEDIA_RADIO_SUPPORT
        default y
        ---help---
          Say Y here to enable selecting AM/FM radio adapters.
diff --git a/drivers/media/radio/lm7000.h b/drivers/media/radio/lm7000.h
new file mode 100644 (file)
index 0000000..139cd6b
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef __LM7000_H
+#define __LM7000_H
+
+/* Sanyo LM7000 tuner chip control
+ *
+ * Copyright 2012 Ondrej Zary <linux@rainbow-software.org>
+ * based on radio-aimslab.c by M. Kirkwood
+ * and radio-sf16fmi.c by M. Kirkwood and Petr Vandrovec
+ */
+
+#define LM7000_DATA    (1 << 0)
+#define LM7000_CLK     (1 << 1)
+#define LM7000_CE      (1 << 2)
+
+#define LM7000_FM_100  (0 << 20)
+#define LM7000_FM_50   (1 << 20)
+#define LM7000_FM_25   (2 << 20)
+#define LM7000_BIT_FM  (1 << 23)
+
+static inline void lm7000_set_freq(u32 freq, void *handle,
+                               void (*set_pins)(void *handle, u8 pins))
+{
+       int i;
+       u8 data;
+       u32 val;
+
+       freq += 171200;         /* Add 10.7 MHz IF */
+       freq /= 400;            /* Convert to 25 kHz units */
+       val = freq | LM7000_FM_25 | LM7000_BIT_FM;
+       /* write the 24-bit register, starting with LSB */
+       for (i = 0; i < 24; i++) {
+               data = val & (1 << i) ? LM7000_DATA : 0;
+               set_pins(handle, data | LM7000_CE);
+               udelay(2);
+               set_pins(handle, data | LM7000_CE | LM7000_CLK);
+               udelay(2);
+               set_pins(handle, data | LM7000_CE);
+               udelay(2);
+       }
+       set_pins(handle, 0);
+}
+
+#endif /* __LM7000_H */
index 98e0c8c20312a5f547f8b175a30182b2e799590a..12c70e876f5863587359e5da742139e8a78a6ebd 100644 (file)
@@ -37,6 +37,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
 #include "radio-isa.h"
+#include "lm7000.h"
 
 MODULE_AUTHOR("M. Kirkwood");
 MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
@@ -72,55 +73,38 @@ static struct radio_isa_card *rtrack_alloc(void)
        return rt ? &rt->isa : NULL;
 }
 
-/* The 128+64 on these outb's is to keep the volume stable while tuning.
- * Without them, the volume _will_ creep up with each frequency change
- * and bit 4 (+16) is to keep the signal strength meter enabled.
- */
+#define AIMS_BIT_TUN_CE                (1 << 0)
+#define AIMS_BIT_TUN_CLK       (1 << 1)
+#define AIMS_BIT_TUN_DATA      (1 << 2)
+#define AIMS_BIT_VOL_CE                (1 << 3)
+#define AIMS_BIT_TUN_STRQ      (1 << 4)
+/* bit 5 is not connected */
+#define AIMS_BIT_VOL_UP                (1 << 6)        /* active low */
+#define AIMS_BIT_VOL_DN                (1 << 7)        /* active low */
 
-static void send_0_byte(struct radio_isa_card *isa, int on)
+void rtrack_set_pins(void *handle, u8 pins)
 {
-       outb_p(128+64+16+on+1, isa->io);        /* wr-enable + data low */
-       outb_p(128+64+16+on+2+1, isa->io);      /* clock */
-       msleep(1);
-}
+       struct radio_isa_card *isa = handle;
+       struct rtrack *rt = container_of(isa, struct rtrack, isa);
+       u8 bits = AIMS_BIT_VOL_DN | AIMS_BIT_VOL_UP | AIMS_BIT_TUN_STRQ;
 
-static void send_1_byte(struct radio_isa_card *isa, int on)
-{
-       outb_p(128+64+16+on+4+1, isa->io);      /* wr-enable+data high */
-       outb_p(128+64+16+on+4+2+1, isa->io);    /* clock */
-       msleep(1);
+       if (!v4l2_ctrl_g_ctrl(rt->isa.mute))
+               bits |= AIMS_BIT_VOL_CE;
+
+       if (pins & LM7000_DATA)
+               bits |= AIMS_BIT_TUN_DATA;
+       if (pins & LM7000_CLK)
+               bits |= AIMS_BIT_TUN_CLK;
+       if (pins & LM7000_CE)
+               bits |= AIMS_BIT_TUN_CE;
+
+       outb_p(bits, rt->isa.io);
 }
 
 static int rtrack_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
-       int on = v4l2_ctrl_g_ctrl(isa->mute) ? 0 : 8;
-       int i;
-
-       freq += 171200;                 /* Add 10.7 MHz IF              */
-       freq /= 800;                    /* Convert to 50 kHz units      */
-
-       send_0_byte(isa, on);           /*  0: LSB of frequency         */
-
-       for (i = 0; i < 13; i++)        /*   : frequency bits (1-13)    */
-               if (freq & (1 << i))
-                       send_1_byte(isa, on);
-               else
-                       send_0_byte(isa, on);
-
-       send_0_byte(isa, on);           /* 14: test bit - always 0    */
-       send_0_byte(isa, on);           /* 15: test bit - always 0    */
-
-       send_0_byte(isa, on);           /* 16: band data 0 - always 0 */
-       send_0_byte(isa, on);           /* 17: band data 1 - always 0 */
-       send_0_byte(isa, on);           /* 18: band data 2 - always 0 */
-       send_0_byte(isa, on);           /* 19: time base - always 0   */
-
-       send_0_byte(isa, on);           /* 20: spacing (0 = 25 kHz)   */
-       send_1_byte(isa, on);           /* 21: spacing (1 = 25 kHz)   */
-       send_0_byte(isa, on);           /* 22: spacing (0 = 25 kHz)   */
-       send_1_byte(isa, on);           /* 23: AM/FM (FM = 1, always) */
+       lm7000_set_freq(freq, isa, rtrack_set_pins);
 
-       outb(0xd0 + on, isa->io);       /* volume steady + sigstr */
        return 0;
 }
 
index 94cb6bc690f5631e7cd6a6814cc7148d598c9ec7..3182b26d6efa8f99cb50fdc7d81d5b9681782ab9 100644 (file)
@@ -295,7 +295,8 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        v->type = V4L2_TUNER_RADIO;
        v->rangelow = FREQ_MIN * FREQ_MUL;
        v->rangehigh = FREQ_MAX * FREQ_MUL;
-       v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+       v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+               V4L2_TUNER_CAP_HWSEEK_WRAP;
        v->rxsubchans = is_stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
        v->audmode = radio->stereo ?
                V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
@@ -372,7 +373,7 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *priv,
        timeout = jiffies + msecs_to_jiffies(30000);
        for (;;) {
                if (time_after(jiffies, timeout)) {
-                       retval = -EAGAIN;
+                       retval = -ENODATA;
                        break;
                }
                if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
index a81d723b8c779a883381c2c00f188fb66380bdf4..8185d5fbfa89af74cf0153a822659a69e4846f8b 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include "lm7000.h"
 
 MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
 MODULE_DESCRIPTION("A driver for the SF16-FMI, SF16-FMP and SF16-FMD radio.");
@@ -54,31 +55,33 @@ static struct fmi fmi_card;
 static struct pnp_dev *dev;
 bool pnp_attached;
 
-/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
-/* It is only useful to give freq in interval of 800 (=0.05Mhz),
- * other bits will be truncated, e.g 92.7400016 -> 92.7, but
- * 92.7400017 -> 92.75
- */
-#define RSF16_ENCODE(x)        ((x) / 800 + 214)
 #define RSF16_MINFREQ (87 * 16000)
 #define RSF16_MAXFREQ (108 * 16000)
 
-static void outbits(int bits, unsigned int data, int io)
+#define FMI_BIT_TUN_CE         (1 << 0)
+#define FMI_BIT_TUN_CLK                (1 << 1)
+#define FMI_BIT_TUN_DATA       (1 << 2)
+#define FMI_BIT_VOL_SW         (1 << 3)
+#define FMI_BIT_TUN_STRQ       (1 << 4)
+
+void fmi_set_pins(void *handle, u8 pins)
 {
-       while (bits--) {
-               if (data & 1) {
-                       outb(5, io);
-                       udelay(6);
-                       outb(7, io);
-                       udelay(6);
-               } else {
-                       outb(1, io);
-                       udelay(6);
-                       outb(3, io);
-                       udelay(6);
-               }
-               data >>= 1;
-       }
+       struct fmi *fmi = handle;
+       u8 bits = FMI_BIT_TUN_STRQ;
+
+       if (!fmi->mute)
+               bits |= FMI_BIT_VOL_SW;
+
+       if (pins & LM7000_DATA)
+               bits |= FMI_BIT_TUN_DATA;
+       if (pins & LM7000_CLK)
+               bits |= FMI_BIT_TUN_CLK;
+       if (pins & LM7000_CE)
+               bits |= FMI_BIT_TUN_CE;
+
+       mutex_lock(&fmi->lock);
+       outb_p(bits, fmi->io);
+       mutex_unlock(&fmi->lock);
 }
 
 static inline void fmi_mute(struct fmi *fmi)
@@ -95,20 +98,6 @@ static inline void fmi_unmute(struct fmi *fmi)
        mutex_unlock(&fmi->lock);
 }
 
-static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq)
-{
-       mutex_lock(&fmi->lock);
-       fmi->curfreq = freq;
-
-       outbits(16, RSF16_ENCODE(freq), fmi->io);
-       outbits(8, 0xC0, fmi->io);
-       msleep(143);            /* was schedule_timeout(HZ/7) */
-       mutex_unlock(&fmi->lock);
-       if (!fmi->mute)
-               fmi_unmute(fmi);
-       return 0;
-}
-
 static inline int fmi_getsigstr(struct fmi *fmi)
 {
        int val;
@@ -173,7 +162,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
                return -EINVAL;
        /* rounding in steps of 800 to match the freq
           that will be used */
-       fmi_setfreq(fmi, (f->frequency / 800) * 800);
+       lm7000_set_freq((f->frequency / 800) * 800, fmi, fmi_set_pins);
        return 0;
 }
 
index f1b607099b6c10361a1305c521b612d7c10ca8ff..e8428f573ccdf0a5649a9b04e187187117f33448 100644 (file)
@@ -1514,7 +1514,8 @@ static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv,
        tuner->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH);
 
        tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS |
-               V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO;
+               V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+               V4L2_TUNER_CAP_HWSEEK_BOUNDED | V4L2_TUNER_CAP_HWSEEK_WRAP;
 
        if (radio->stereo)
                tuner->audmode = V4L2_TUNER_MODE_STEREO;
index 969cf494d85bddb50d86bb2cd589c34d970ad5f4..d485b79222fd4f554fb8834a9ed7f3ace84e7efd 100644 (file)
@@ -363,7 +363,7 @@ stop:
 
        /* try again, if timed out */
        if (retval == 0 && timed_out)
-               return -EAGAIN;
+               return -ENODATA;
        return retval;
 }
 
@@ -596,7 +596,9 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
        strcpy(tuner->name, "FM");
        tuner->type = V4L2_TUNER_RADIO;
        tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
-                           V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
+                           V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+                           V4L2_TUNER_CAP_HWSEEK_BOUNDED |
+                           V4L2_TUNER_CAP_HWSEEK_WRAP;
 
        /* range limits */
        switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
index 43fb72291bea15551f7bf5ca01577d23db879ef9..3dd9fc097c473f5974034fdce141079e242e915e 100644 (file)
@@ -251,7 +251,7 @@ again:
        if (!timeleft) {
                fmerr("Timeout(%d sec),didn't get tune ended int\n",
                           jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000);
-               return -ETIMEDOUT;
+               return -ENODATA;
        }
 
        int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT);
index 080b96a61f1a41783e8d7025e63722fb94ceeb0e..49a11ec1f44967fe99bce27b3a602ed320e41170 100644 (file)
@@ -285,7 +285,9 @@ static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv,
        tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO |
        ((fmdev->rx.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0);
        tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
-                           V4L2_TUNER_CAP_LOW;
+                           V4L2_TUNER_CAP_LOW |
+                           V4L2_TUNER_CAP_HWSEEK_BOUNDED |
+                           V4L2_TUNER_CAP_HWSEEK_WRAP;
        tuner->audmode = (stereo_mono_mode ?
                          V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO);
 
index f97eeb870455a975fc5ee5c0b7135e4eaa084fc7..908ef70430e94caebe56a8d361cfbbb48dae30ff 100644 (file)
@@ -1,21 +1,20 @@
-menuconfig RC_CORE
-       tristate "Remote Controller adapters"
+config RC_CORE
+       tristate
+       depends on MEDIA_RC_SUPPORT
        depends on INPUT
-       default INPUT
-       ---help---
-         Enable support for Remote Controllers on Linux. This is
-         needed in order to support several video capture adapters,
-         standalone IR receivers/transmitters, and RF receivers.
+       default y
 
-         Enable this option if you have a video capture board even
-         if you don't need IR, as otherwise, you may not be able to
-         compile the driver for your adapter.
+source "drivers/media/rc/keymaps/Kconfig"
 
-if RC_CORE
+menuconfig RC_DECODERS
+        bool "Remote controller decoders"
+       depends on RC_CORE
+       default y
 
+if RC_DECODERS
 config LIRC
-       tristate
-       default y
+       tristate "LIRC interface driver"
+       depends on RC_CORE
 
        ---help---
           Enable this option to build the Linux Infrared Remote
@@ -24,7 +23,16 @@ config LIRC
           LIRC daemon handles protocol decoding for IR reception and
           encoding for IR transmitting (aka "blasting").
 
-source "drivers/media/rc/keymaps/Kconfig"
+config IR_LIRC_CODEC
+       tristate "Enable IR to LIRC bridge"
+       depends on RC_CORE
+       depends on LIRC
+       default y
+
+       ---help---
+          Enable this option to pass raw IR to and from userspace via
+          the LIRC interface.
+
 
 config IR_NEC_DECODER
        tristate "Enable IR raw decoder for the NEC protocol"
@@ -108,16 +116,13 @@ config IR_MCE_KBD_DECODER
           Enable this option if you have a Microsoft Remote Keyboard for
           Windows Media Center Edition, which you would like to use with
           a raw IR receiver in your system.
+endif #RC_DECODERS
 
-config IR_LIRC_CODEC
-       tristate "Enable IR to LIRC bridge"
+menuconfig RC_DEVICES
+       bool "Remote Controller devices"
        depends on RC_CORE
-       depends on LIRC
-       default y
 
-       ---help---
-          Enable this option to pass raw IR to and from userspace via
-          the LIRC interface.
+if RC_DEVICES
 
 config RC_ATI_REMOTE
        tristate "ATI / X10 based USB RF remote controls"
@@ -276,4 +281,4 @@ config IR_GPIO_CIR
           To compile this driver as a module, choose M here: the module will
           be called gpio-ir-recv.
 
-endif #RC_CORE
+endif #RC_DEVICES
index bef5296173c904baffc14b8856627839de57f51d..647dd951b0e8c31772e66bcdc333a54c3f839574 100644 (file)
@@ -1018,6 +1018,8 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
 
        spin_lock_init(&dev->hw_lock);
 
+       dev->hw_io = pnp_port_start(pnp_dev, 0);
+
        pnp_set_drvdata(pnp_dev, dev);
        dev->pnp_dev = pnp_dev;
 
@@ -1072,7 +1074,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
 
        /* claim the resources */
        error = -EBUSY;
-       dev->hw_io = pnp_port_start(pnp_dev, 0);
        if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) {
                dev->hw_io = -1;
                dev->irq = -1;
index 6aabf7ae3a31b79948f6afa5341284ce185f5ca9..ab30c64f812491d186e3a088bea23cc6849651a2 100644 (file)
@@ -23,6 +23,8 @@
  * USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pnp.h>
@@ -110,30 +112,32 @@ static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset)
        return val;
 }
 
-#define pr_reg(text, ...) \
-       printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__)
-
 /* dump current cir register contents */
 static void cir_dump_regs(struct fintek_dev *fintek)
 {
        fintek_config_mode_enable(fintek);
        fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
 
-       pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME);
-       pr_reg(" * CR CIR BASE ADDR: 0x%x\n",
-              (fintek_cr_read(fintek, CIR_CR_BASE_ADDR_HI) << 8) |
+       pr_info("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME);
+       pr_info(" * CR CIR BASE ADDR: 0x%x\n",
+               (fintek_cr_read(fintek, CIR_CR_BASE_ADDR_HI) << 8) |
                fintek_cr_read(fintek, CIR_CR_BASE_ADDR_LO));
-       pr_reg(" * CR CIR IRQ NUM:   0x%x\n",
-              fintek_cr_read(fintek, CIR_CR_IRQ_SEL));
+       pr_info(" * CR CIR IRQ NUM:   0x%x\n",
+               fintek_cr_read(fintek, CIR_CR_IRQ_SEL));
 
        fintek_config_mode_disable(fintek);
 
-       pr_reg("%s: Dump CIR registers:\n", FINTEK_DRIVER_NAME);
-       pr_reg(" * STATUS:     0x%x\n", fintek_cir_reg_read(fintek, CIR_STATUS));
-       pr_reg(" * CONTROL:    0x%x\n", fintek_cir_reg_read(fintek, CIR_CONTROL));
-       pr_reg(" * RX_DATA:    0x%x\n", fintek_cir_reg_read(fintek, CIR_RX_DATA));
-       pr_reg(" * TX_CONTROL: 0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_CONTROL));
-       pr_reg(" * TX_DATA:    0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_DATA));
+       pr_info("%s: Dump CIR registers:\n", FINTEK_DRIVER_NAME);
+       pr_info(" * STATUS:     0x%x\n",
+               fintek_cir_reg_read(fintek, CIR_STATUS));
+       pr_info(" * CONTROL:    0x%x\n",
+               fintek_cir_reg_read(fintek, CIR_CONTROL));
+       pr_info(" * RX_DATA:    0x%x\n",
+               fintek_cir_reg_read(fintek, CIR_RX_DATA));
+       pr_info(" * TX_CONTROL: 0x%x\n",
+               fintek_cir_reg_read(fintek, CIR_TX_CONTROL));
+       pr_info(" * TX_DATA:    0x%x\n",
+               fintek_cir_reg_read(fintek, CIR_TX_DATA));
 }
 
 /* detect hardware features */
index 0d875450c5ce3d92f1295445b852f77617ed5364..04cb272db16a37fb11e2cd2cdeadb75b3d7b3760 100644 (file)
@@ -82,12 +82,21 @@ static int __devinit gpio_ir_recv_probe(struct platform_device *pdev)
                goto err_allocate_device;
        }
 
+       rcdev->priv = gpio_dev;
        rcdev->driver_type = RC_DRIVER_IR_RAW;
-       rcdev->allowed_protos = RC_TYPE_ALL;
        rcdev->input_name = GPIO_IR_DEVICE_NAME;
+       rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0";
        rcdev->input_id.bustype = BUS_HOST;
+       rcdev->input_id.vendor = 0x0001;
+       rcdev->input_id.product = 0x0001;
+       rcdev->input_id.version = 0x0100;
+       rcdev->dev.parent = &pdev->dev;
        rcdev->driver_name = GPIO_IR_DRIVER_NAME;
-       rcdev->map_name = RC_MAP_EMPTY;
+       if (pdata->allowed_protos)
+               rcdev->allowed_protos = pdata->allowed_protos;
+       else
+               rcdev->allowed_protos = RC_TYPE_ALL;
+       rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY;
 
        gpio_dev->rcdev = rcdev;
        gpio_dev->gpio_nr = pdata->gpio_nr;
@@ -188,18 +197,7 @@ static struct platform_driver gpio_ir_recv_driver = {
 #endif
        },
 };
-
-static int __init gpio_ir_recv_init(void)
-{
-       return platform_driver_register(&gpio_ir_recv_driver);
-}
-module_init(gpio_ir_recv_init);
-
-static void __exit gpio_ir_recv_exit(void)
-{
-       platform_driver_unregister(&gpio_ir_recv_driver);
-}
-module_exit(gpio_ir_recv_exit);
+module_platform_driver(gpio_ir_recv_driver);
 
 MODULE_DESCRIPTION("GPIO IR Receiver driver");
 MODULE_LICENSE("GPL v2");
index dc8a7dddccd458edb615e60b0c8eb0a242167779..699eef39128bf3eacf91a08d1a1026a1dfac1653 100644 (file)
@@ -25,6 +25,8 @@
  * USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pnp.h>
@@ -123,43 +125,40 @@ static u8 nvt_cir_wake_reg_read(struct nvt_dev *nvt, u8 offset)
        return val;
 }
 
-#define pr_reg(text, ...) \
-       printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__)
-
 /* dump current cir register contents */
 static void cir_dump_regs(struct nvt_dev *nvt)
 {
        nvt_efm_enable(nvt);
        nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
 
-       pr_reg("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME);
-       pr_reg(" * CR CIR ACTIVE :   0x%x\n",
-              nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
-       pr_reg(" * CR CIR BASE ADDR: 0x%x\n",
-              (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
+       pr_info("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME);
+       pr_info(" * CR CIR ACTIVE :   0x%x\n",
+               nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
+       pr_info(" * CR CIR BASE ADDR: 0x%x\n",
+               (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
                nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
-       pr_reg(" * CR CIR IRQ NUM:   0x%x\n",
-              nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
+       pr_info(" * CR CIR IRQ NUM:   0x%x\n",
+               nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
 
        nvt_efm_disable(nvt);
 
-       pr_reg("%s: Dump CIR registers:\n", NVT_DRIVER_NAME);
-       pr_reg(" * IRCON:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON));
-       pr_reg(" * IRSTS:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS));
-       pr_reg(" * IREN:      0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN));
-       pr_reg(" * RXFCONT:   0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT));
-       pr_reg(" * CP:        0x%x\n", nvt_cir_reg_read(nvt, CIR_CP));
-       pr_reg(" * CC:        0x%x\n", nvt_cir_reg_read(nvt, CIR_CC));
-       pr_reg(" * SLCH:      0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH));
-       pr_reg(" * SLCL:      0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL));
-       pr_reg(" * FIFOCON:   0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON));
-       pr_reg(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS));
-       pr_reg(" * SRXFIFO:   0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO));
-       pr_reg(" * TXFCONT:   0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT));
-       pr_reg(" * STXFIFO:   0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO));
-       pr_reg(" * FCCH:      0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH));
-       pr_reg(" * FCCL:      0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL));
-       pr_reg(" * IRFSM:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM));
+       pr_info("%s: Dump CIR registers:\n", NVT_DRIVER_NAME);
+       pr_info(" * IRCON:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON));
+       pr_info(" * IRSTS:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS));
+       pr_info(" * IREN:      0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN));
+       pr_info(" * RXFCONT:   0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT));
+       pr_info(" * CP:        0x%x\n", nvt_cir_reg_read(nvt, CIR_CP));
+       pr_info(" * CC:        0x%x\n", nvt_cir_reg_read(nvt, CIR_CC));
+       pr_info(" * SLCH:      0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH));
+       pr_info(" * SLCL:      0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL));
+       pr_info(" * FIFOCON:   0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON));
+       pr_info(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS));
+       pr_info(" * SRXFIFO:   0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO));
+       pr_info(" * TXFCONT:   0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT));
+       pr_info(" * STXFIFO:   0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO));
+       pr_info(" * FCCH:      0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH));
+       pr_info(" * FCCL:      0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL));
+       pr_info(" * IRFSM:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM));
 }
 
 /* dump current cir wake register contents */
@@ -170,59 +169,59 @@ static void cir_wake_dump_regs(struct nvt_dev *nvt)
        nvt_efm_enable(nvt);
        nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
 
-       pr_reg("%s: Dump CIR WAKE logical device registers:\n",
-              NVT_DRIVER_NAME);
-       pr_reg(" * CR CIR WAKE ACTIVE :   0x%x\n",
-              nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
-       pr_reg(" * CR CIR WAKE BASE ADDR: 0x%x\n",
-              (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
+       pr_info("%s: Dump CIR WAKE logical device registers:\n",
+               NVT_DRIVER_NAME);
+       pr_info(" * CR CIR WAKE ACTIVE :   0x%x\n",
+               nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
+       pr_info(" * CR CIR WAKE BASE ADDR: 0x%x\n",
+               (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
                nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
-       pr_reg(" * CR CIR WAKE IRQ NUM:   0x%x\n",
-              nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
+       pr_info(" * CR CIR WAKE IRQ NUM:   0x%x\n",
+               nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
 
        nvt_efm_disable(nvt);
 
-       pr_reg("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME);
-       pr_reg(" * IRCON:          0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON));
-       pr_reg(" * IRSTS:          0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS));
-       pr_reg(" * IREN:           0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN));
-       pr_reg(" * FIFO CMP DEEP:  0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_DEEP));
-       pr_reg(" * FIFO CMP TOL:   0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_TOL));
-       pr_reg(" * FIFO COUNT:     0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT));
-       pr_reg(" * SLCH:           0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCH));
-       pr_reg(" * SLCL:           0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCL));
-       pr_reg(" * FIFOCON:        0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON));
-       pr_reg(" * SRXFSTS:        0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_SRXFSTS));
-       pr_reg(" * SAMPLE RX FIFO: 0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_SAMPLE_RX_FIFO));
-       pr_reg(" * WR FIFO DATA:   0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_WR_FIFO_DATA));
-       pr_reg(" * RD FIFO ONLY:   0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
-       pr_reg(" * RD FIFO ONLY IDX: 0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX));
-       pr_reg(" * FIFO IGNORE:    0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_IGNORE));
-       pr_reg(" * IRFSM:          0x%x\n",
-              nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRFSM));
+       pr_info("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME);
+       pr_info(" * IRCON:          0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON));
+       pr_info(" * IRSTS:          0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS));
+       pr_info(" * IREN:           0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN));
+       pr_info(" * FIFO CMP DEEP:  0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_DEEP));
+       pr_info(" * FIFO CMP TOL:   0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_TOL));
+       pr_info(" * FIFO COUNT:     0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT));
+       pr_info(" * SLCH:           0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCH));
+       pr_info(" * SLCL:           0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCL));
+       pr_info(" * FIFOCON:        0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON));
+       pr_info(" * SRXFSTS:        0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_SRXFSTS));
+       pr_info(" * SAMPLE RX FIFO: 0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_SAMPLE_RX_FIFO));
+       pr_info(" * WR FIFO DATA:   0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_WR_FIFO_DATA));
+       pr_info(" * RD FIFO ONLY:   0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
+       pr_info(" * RD FIFO ONLY IDX: 0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX));
+       pr_info(" * FIFO IGNORE:    0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_IGNORE));
+       pr_info(" * IRFSM:          0x%x\n",
+               nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRFSM));
 
        fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT);
-       pr_reg("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len);
-       pr_reg("* Contents = ");
+       pr_info("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len);
+       pr_info("* Contents =");
        for (i = 0; i < fifo_len; i++)
-               printk(KERN_CONT "%02x ",
-                      nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
-       printk(KERN_CONT "\n");
+               pr_cont(" %02x",
+                       nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
+       pr_cont("\n");
 }
 
 /* detect hardware features */
index 99937c94d7dfdd34ef30d9cb28cf23d3df17a3f9..c128fac0ce2cf4b4c0f2d7484fc21b024b3cb5ef 100644 (file)
@@ -5,7 +5,7 @@
 config VIDEO_V4L2
        tristate
        depends on VIDEO_DEV && VIDEO_V4L2_COMMON
-       default VIDEO_DEV && VIDEO_V4L2_COMMON
+       default y
 
 config VIDEOBUF_GEN
        tristate
@@ -73,6 +73,7 @@ config VIDEOBUF2_DMA_SG
 menuconfig VIDEO_CAPTURE_DRIVERS
        bool "Video capture adapters"
        depends on VIDEO_V4L2
+       depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT
        default y
        ---help---
          Say Y here to enable selecting the video adapters for
@@ -461,6 +462,15 @@ config VIDEO_ADV7343
          To compile this driver as a module, choose M here: the
          module will be called adv7343.
 
+config VIDEO_ADV7393
+       tristate "ADV7393 video encoder"
+       depends on I2C
+       help
+         Support for Analog Devices I2C bus based ADV7393 encoder.
+
+         To compile this driver as a module, choose M here: the
+         module will be called adv7393.
+
 config VIDEO_AK881X
        tristate "AK8813/AK8814 video encoders"
        depends on I2C
@@ -478,6 +488,7 @@ config VIDEO_SMIAPP_PLL
 config VIDEO_OV7670
        tristate "OmniVision OV7670 sensor support"
        depends on I2C && VIDEO_V4L2
+       depends on MEDIA_CAMERA_SUPPORT
        ---help---
          This is a Video4Linux2 sensor-level driver for the OmniVision
          OV7670 VGA camera.  It currently only works with the M88ALP01
@@ -486,6 +497,7 @@ config VIDEO_OV7670
 config VIDEO_VS6624
        tristate "ST VS6624 sensor support"
        depends on VIDEO_V4L2 && I2C
+       depends on MEDIA_CAMERA_SUPPORT
        ---help---
          This is a Video4Linux2 sensor-level driver for the ST VS6624
          camera.
@@ -496,6 +508,7 @@ config VIDEO_VS6624
 config VIDEO_MT9M032
        tristate "MT9M032 camera sensor support"
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       depends on MEDIA_CAMERA_SUPPORT
        select VIDEO_APTINA_PLL
        ---help---
          This driver supports MT9M032 camera sensors from Aptina, monochrome
@@ -504,6 +517,7 @@ config VIDEO_MT9M032
 config VIDEO_MT9P031
        tristate "Aptina MT9P031 support"
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       depends on MEDIA_CAMERA_SUPPORT
        select VIDEO_APTINA_PLL
        ---help---
          This is a Video4Linux2 sensor-level driver for the Aptina
@@ -512,6 +526,7 @@ config VIDEO_MT9P031
 config VIDEO_MT9T001
        tristate "Aptina MT9T001 support"
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       depends on MEDIA_CAMERA_SUPPORT
        ---help---
          This is a Video4Linux2 sensor-level driver for the Aptina
          (Micron) mt0t001 3 Mpixel camera.
@@ -519,6 +534,7 @@ config VIDEO_MT9T001
 config VIDEO_MT9V011
        tristate "Micron mt9v011 sensor support"
        depends on I2C && VIDEO_V4L2
+       depends on MEDIA_CAMERA_SUPPORT
        ---help---
          This is a Video4Linux2 sensor-level driver for the Micron
          mt0v011 1.3 Mpixel camera.  It currently only works with the
@@ -527,6 +543,7 @@ config VIDEO_MT9V011
 config VIDEO_MT9V032
        tristate "Micron MT9V032 sensor support"
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       depends on MEDIA_CAMERA_SUPPORT
        ---help---
          This is a Video4Linux2 sensor-level driver for the Micron
          MT9V032 752x480 CMOS sensor.
@@ -534,6 +551,7 @@ config VIDEO_MT9V032
 config VIDEO_TCM825X
        tristate "TCM825x camera sensor support"
        depends on I2C && VIDEO_V4L2
+       depends on MEDIA_CAMERA_SUPPORT
        ---help---
          This is a driver for the Toshiba TCM825x VGA camera sensor.
          It is used for example in Nokia N800.
@@ -541,12 +559,14 @@ config VIDEO_TCM825X
 config VIDEO_SR030PC30
        tristate "Siliconfile SR030PC30 sensor support"
        depends on I2C && VIDEO_V4L2
+       depends on MEDIA_CAMERA_SUPPORT
        ---help---
          This driver supports SR030PC30 VGA camera from Siliconfile
 
 config VIDEO_NOON010PC30
        tristate "Siliconfile NOON010PC30 sensor support"
        depends on I2C && VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_SUBDEV_API
+       depends on MEDIA_CAMERA_SUPPORT
        ---help---
          This driver supports NOON010PC30 CIF camera from Siliconfile
 
@@ -554,6 +574,7 @@ source "drivers/media/video/m5mols/Kconfig"
 
 config VIDEO_S5K6AA
        tristate "Samsung S5K6AAFX sensor support"
+       depends on MEDIA_CAMERA_SUPPORT
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
        ---help---
          This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
@@ -566,6 +587,7 @@ comment "Flash devices"
 config VIDEO_ADP1653
        tristate "ADP1653 flash support"
        depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
+       depends on MEDIA_CAMERA_SUPPORT
        ---help---
          This is a driver for the ADP1653 flash controller. It is used for
          example in Nokia N900.
@@ -573,6 +595,7 @@ config VIDEO_ADP1653
 config VIDEO_AS3645A
        tristate "AS3645A flash driver support"
        depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
+       depends on MEDIA_CAMERA_SUPPORT
        ---help---
          This is a driver for the AS3645A and LM3555 flash controllers. It has
          build in control for flash, torch and indicator LEDs.
@@ -647,30 +670,14 @@ menuconfig V4L_USB_DRIVERS
        depends on USB
        default y
 
-if V4L_USB_DRIVERS
+if V4L_USB_DRIVERS && MEDIA_CAMERA_SUPPORT
 
-source "drivers/media/video/au0828/Kconfig"
+       comment "Webcam devices"
 
 source "drivers/media/video/uvc/Kconfig"
 
 source "drivers/media/video/gspca/Kconfig"
 
-source "drivers/media/video/pvrusb2/Kconfig"
-
-source "drivers/media/video/hdpvr/Kconfig"
-
-source "drivers/media/video/em28xx/Kconfig"
-
-source "drivers/media/video/tlg2300/Kconfig"
-
-source "drivers/media/video/cx231xx/Kconfig"
-
-source "drivers/media/video/tm6000/Kconfig"
-
-source "drivers/media/video/usbvision/Kconfig"
-
-source "drivers/media/video/sn9c102/Kconfig"
-
 source "drivers/media/video/pwc/Kconfig"
 
 source "drivers/media/video/cpia2/Kconfig"
@@ -711,15 +718,46 @@ config USB_S2255
          Say Y here if you want support for the Sensoray 2255 USB device.
          This driver can be compiled as a module, called s2255drv.
 
+source "drivers/media/video/sn9c102/Kconfig"
+
+endif # V4L_USB_DRIVERS && MEDIA_CAMERA_SUPPORT
+
+if V4L_USB_DRIVERS
+
+       comment "Webcam and/or TV USB devices"
+
+source "drivers/media/video/em28xx/Kconfig"
+
+endif
+
+if V4L_USB_DRIVERS && MEDIA_ANALOG_TV_SUPPORT
+
+       comment "TV USB devices"
+
+source "drivers/media/video/au0828/Kconfig"
+
+source "drivers/media/video/pvrusb2/Kconfig"
+
+source "drivers/media/video/hdpvr/Kconfig"
+
+source "drivers/media/video/tlg2300/Kconfig"
+
+source "drivers/media/video/cx231xx/Kconfig"
+
+source "drivers/media/video/tm6000/Kconfig"
+
+source "drivers/media/video/usbvision/Kconfig"
+
 endif # V4L_USB_DRIVERS
 
 #
-# PCI drivers configuration
+# PCI drivers configuration - No devices here are for webcams
 #
 
 menuconfig V4L_PCI_DRIVERS
        bool "V4L PCI(e) devices"
        depends on PCI
+       depends on MEDIA_ANALOG_TV_SUPPORT
        default y
        ---help---
          Say Y here to enable support for these PCI(e) drivers.
@@ -814,11 +852,13 @@ endif # V4L_PCI_DRIVERS
 
 #
 # ISA & parallel port drivers configuration
+#      All devices here are webcam or grabber devices
 #
 
 menuconfig V4L_ISA_PARPORT_DRIVERS
        bool "V4L ISA and parallel port devices"
        depends on ISA || PARPORT
+       depends on MEDIA_CAMERA_SUPPORT
        default n
        ---help---
          Say Y here to enable support for these ISA and parallel port drivers.
@@ -871,8 +911,13 @@ config VIDEO_W9966
 
 endif # V4L_ISA_PARPORT_DRIVERS
 
+#
+# Platform drivers
+#      All drivers here are currently for webcam support
+
 menuconfig V4L_PLATFORM_DRIVERS
        bool "V4L platform devices"
+       depends on MEDIA_CAMERA_SUPPORT
        default n
        ---help---
          Say Y here to enable support for platform-specific V4L drivers.
index d209de0e0ca8821dd566844e288d6077fc75f6bf..b7da9faa3b0ac96030983dbf1c057d2c7f88ac8e 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
 obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o
 obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o
 obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
+obj-$(CONFIG_VIDEO_ADV7393) += adv7393.o
 obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
 obj-$(CONFIG_VIDEO_VS6624)  += vs6624.o
 obj-$(CONFIG_VIDEO_BT819) += bt819.o
diff --git a/drivers/media/video/adv7393.c b/drivers/media/video/adv7393.c
new file mode 100644 (file)
index 0000000..3dc6098
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * adv7393 - ADV7393 Video Encoder Driver
+ *
+ * The encoder hardware does not support SECAM.
+ *
+ * Copyright (C) 2010-2012 ADVANSEE - http://www.advansee.com/
+ * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
+ *
+ * Based on ADV7343 driver,
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+
+#include <media/adv7393.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+#include "adv7393_regs.h"
+
+MODULE_DESCRIPTION("ADV7393 video encoder driver");
+MODULE_LICENSE("GPL");
+
+static bool debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+struct adv7393_state {
+       struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
+       u8 reg00;
+       u8 reg01;
+       u8 reg02;
+       u8 reg35;
+       u8 reg80;
+       u8 reg82;
+       u32 output;
+       v4l2_std_id std;
+};
+
+static inline struct adv7393_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct adv7393_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct adv7393_state, hdl)->sd;
+}
+
+static inline int adv7393_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static const u8 adv7393_init_reg_val[] = {
+       ADV7393_SOFT_RESET, ADV7393_SOFT_RESET_DEFAULT,
+       ADV7393_POWER_MODE_REG, ADV7393_POWER_MODE_REG_DEFAULT,
+
+       ADV7393_HD_MODE_REG1, ADV7393_HD_MODE_REG1_DEFAULT,
+       ADV7393_HD_MODE_REG2, ADV7393_HD_MODE_REG2_DEFAULT,
+       ADV7393_HD_MODE_REG3, ADV7393_HD_MODE_REG3_DEFAULT,
+       ADV7393_HD_MODE_REG4, ADV7393_HD_MODE_REG4_DEFAULT,
+       ADV7393_HD_MODE_REG5, ADV7393_HD_MODE_REG5_DEFAULT,
+       ADV7393_HD_MODE_REG6, ADV7393_HD_MODE_REG6_DEFAULT,
+       ADV7393_HD_MODE_REG7, ADV7393_HD_MODE_REG7_DEFAULT,
+
+       ADV7393_SD_MODE_REG1, ADV7393_SD_MODE_REG1_DEFAULT,
+       ADV7393_SD_MODE_REG2, ADV7393_SD_MODE_REG2_DEFAULT,
+       ADV7393_SD_MODE_REG3, ADV7393_SD_MODE_REG3_DEFAULT,
+       ADV7393_SD_MODE_REG4, ADV7393_SD_MODE_REG4_DEFAULT,
+       ADV7393_SD_MODE_REG5, ADV7393_SD_MODE_REG5_DEFAULT,
+       ADV7393_SD_MODE_REG6, ADV7393_SD_MODE_REG6_DEFAULT,
+       ADV7393_SD_MODE_REG7, ADV7393_SD_MODE_REG7_DEFAULT,
+       ADV7393_SD_MODE_REG8, ADV7393_SD_MODE_REG8_DEFAULT,
+
+       ADV7393_SD_TIMING_REG0, ADV7393_SD_TIMING_REG0_DEFAULT,
+
+       ADV7393_SD_HUE_ADJUST, ADV7393_SD_HUE_ADJUST_DEFAULT,
+       ADV7393_SD_CGMS_WSS0, ADV7393_SD_CGMS_WSS0_DEFAULT,
+       ADV7393_SD_BRIGHTNESS_WSS, ADV7393_SD_BRIGHTNESS_WSS_DEFAULT,
+};
+
+/*
+ *                         2^32
+ * FSC(reg) =  FSC (HZ) * --------
+ *                       27000000
+ */
+static const struct adv7393_std_info stdinfo[] = {
+       {
+               /* FSC(Hz) = 4,433,618.75 Hz */
+               SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443,
+       }, {
+               /* FSC(Hz) = 3,579,545.45 Hz */
+               SD_STD_NTSC, 569408542, V4L2_STD_NTSC,
+       }, {
+               /* FSC(Hz) = 3,575,611.00 Hz */
+               SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M,
+       }, {
+               /* FSC(Hz) = 3,582,056.00 Hz */
+               SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc,
+       }, {
+               /* FSC(Hz) = 4,433,618.75 Hz */
+               SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N,
+       }, {
+               /* FSC(Hz) = 4,433,618.75 Hz */
+               SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60,
+       }, {
+               /* FSC(Hz) = 4,433,618.75 Hz */
+               SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL,
+       },
+};
+
+static int adv7393_setstd(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct adv7393_state *state = to_state(sd);
+       const struct adv7393_std_info *std_info;
+       int num_std;
+       u8 reg;
+       u32 val;
+       int err = 0;
+       int i;
+
+       num_std = ARRAY_SIZE(stdinfo);
+
+       for (i = 0; i < num_std; i++) {
+               if (stdinfo[i].stdid & std)
+                       break;
+       }
+
+       if (i == num_std) {
+               v4l2_dbg(1, debug, sd,
+                               "Invalid std or std is not supported: %llx\n",
+                                               (unsigned long long)std);
+               return -EINVAL;
+       }
+
+       std_info = &stdinfo[i];
+
+       /* Set the standard */
+       val = state->reg80 & ~SD_STD_MASK;
+       val |= std_info->standard_val3;
+       err = adv7393_write(sd, ADV7393_SD_MODE_REG1, val);
+       if (err < 0)
+               goto setstd_exit;
+
+       state->reg80 = val;
+
+       /* Configure the input mode register */
+       val = state->reg01 & ~INPUT_MODE_MASK;
+       val |= SD_INPUT_MODE;
+       err = adv7393_write(sd, ADV7393_MODE_SELECT_REG, val);
+       if (err < 0)
+               goto setstd_exit;
+
+       state->reg01 = val;
+
+       /* Program the sub carrier frequency registers */
+       val = std_info->fsc_val;
+       for (reg = ADV7393_FSC_REG0; reg <= ADV7393_FSC_REG3; reg++) {
+               err = adv7393_write(sd, reg, val);
+               if (err < 0)
+                       goto setstd_exit;
+               val >>= 8;
+       }
+
+       val = state->reg82;
+
+       /* Pedestal settings */
+       if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443))
+               val |= SD_PEDESTAL_EN;
+       else
+               val &= SD_PEDESTAL_DI;
+
+       err = adv7393_write(sd, ADV7393_SD_MODE_REG2, val);
+       if (err < 0)
+               goto setstd_exit;
+
+       state->reg82 = val;
+
+setstd_exit:
+       if (err != 0)
+               v4l2_err(sd, "Error setting std, write failed\n");
+
+       return err;
+}
+
+static int adv7393_setoutput(struct v4l2_subdev *sd, u32 output_type)
+{
+       struct adv7393_state *state = to_state(sd);
+       u8 val;
+       int err = 0;
+
+       if (output_type > ADV7393_SVIDEO_ID) {
+               v4l2_dbg(1, debug, sd,
+                       "Invalid output type or output type not supported:%d\n",
+                                                               output_type);
+               return -EINVAL;
+       }
+
+       /* Enable Appropriate DAC */
+       val = state->reg00 & 0x03;
+
+       if (output_type == ADV7393_COMPOSITE_ID)
+               val |= ADV7393_COMPOSITE_POWER_VALUE;
+       else if (output_type == ADV7393_COMPONENT_ID)
+               val |= ADV7393_COMPONENT_POWER_VALUE;
+       else
+               val |= ADV7393_SVIDEO_POWER_VALUE;
+
+       err = adv7393_write(sd, ADV7393_POWER_MODE_REG, val);
+       if (err < 0)
+               goto setoutput_exit;
+
+       state->reg00 = val;
+
+       /* Enable YUV output */
+       val = state->reg02 | YUV_OUTPUT_SELECT;
+       err = adv7393_write(sd, ADV7393_MODE_REG0, val);
+       if (err < 0)
+               goto setoutput_exit;
+
+       state->reg02 = val;
+
+       /* configure SD DAC Output 1 bit */
+       val = state->reg82;
+       if (output_type == ADV7393_COMPONENT_ID)
+               val &= SD_DAC_OUT1_DI;
+       else
+               val |= SD_DAC_OUT1_EN;
+       err = adv7393_write(sd, ADV7393_SD_MODE_REG2, val);
+       if (err < 0)
+               goto setoutput_exit;
+
+       state->reg82 = val;
+
+       /* configure ED/HD Color DAC Swap bit to zero */
+       val = state->reg35 & HD_DAC_SWAP_DI;
+       err = adv7393_write(sd, ADV7393_HD_MODE_REG6, val);
+       if (err < 0)
+               goto setoutput_exit;
+
+       state->reg35 = val;
+
+setoutput_exit:
+       if (err != 0)
+               v4l2_err(sd, "Error setting output, write failed\n");
+
+       return err;
+}
+
+static int adv7393_log_status(struct v4l2_subdev *sd)
+{
+       struct adv7393_state *state = to_state(sd);
+
+       v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std);
+       v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" :
+                       ((state->output == 1) ? "Component" : "S-Video"));
+       return 0;
+}
+
+static int adv7393_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_subdev *sd = to_sd(ctrl);
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return adv7393_write(sd, ADV7393_SD_BRIGHTNESS_WSS,
+                                       ctrl->val & SD_BRIGHTNESS_VALUE_MASK);
+
+       case V4L2_CID_HUE:
+               return adv7393_write(sd, ADV7393_SD_HUE_ADJUST,
+                                       ctrl->val - ADV7393_HUE_MIN);
+
+       case V4L2_CID_GAIN:
+               return adv7393_write(sd, ADV7393_DAC123_OUTPUT_LEVEL,
+                                       ctrl->val);
+       }
+       return -EINVAL;
+}
+
+static int adv7393_g_chip_ident(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7393, 0);
+}
+
+static const struct v4l2_ctrl_ops adv7393_ctrl_ops = {
+       .s_ctrl = adv7393_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops adv7393_core_ops = {
+       .log_status = adv7393_log_status,
+       .g_chip_ident = adv7393_g_chip_ident,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
+};
+
+static int adv7393_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct adv7393_state *state = to_state(sd);
+       int err = 0;
+
+       if (state->std == std)
+               return 0;
+
+       err = adv7393_setstd(sd, std);
+       if (!err)
+               state->std = std;
+
+       return err;
+}
+
+static int adv7393_s_routing(struct v4l2_subdev *sd,
+               u32 input, u32 output, u32 config)
+{
+       struct adv7393_state *state = to_state(sd);
+       int err = 0;
+
+       if (state->output == output)
+               return 0;
+
+       err = adv7393_setoutput(sd, output);
+       if (!err)
+               state->output = output;
+
+       return err;
+}
+
+static const struct v4l2_subdev_video_ops adv7393_video_ops = {
+       .s_std_output   = adv7393_s_std_output,
+       .s_routing      = adv7393_s_routing,
+};
+
+static const struct v4l2_subdev_ops adv7393_ops = {
+       .core   = &adv7393_core_ops,
+       .video  = &adv7393_video_ops,
+};
+
+static int adv7393_initialize(struct v4l2_subdev *sd)
+{
+       struct adv7393_state *state = to_state(sd);
+       int err = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(adv7393_init_reg_val); i += 2) {
+
+               err = adv7393_write(sd, adv7393_init_reg_val[i],
+                                       adv7393_init_reg_val[i+1]);
+               if (err) {
+                       v4l2_err(sd, "Error initializing\n");
+                       return err;
+               }
+       }
+
+       /* Configure for default video standard */
+       err = adv7393_setoutput(sd, state->output);
+       if (err < 0) {
+               v4l2_err(sd, "Error setting output during init\n");
+               return -EINVAL;
+       }
+
+       err = adv7393_setstd(sd, state->std);
+       if (err < 0) {
+               v4l2_err(sd, "Error setting std during init\n");
+               return -EINVAL;
+       }
+
+       return err;
+}
+
+static int adv7393_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct adv7393_state *state;
+       int err;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       state = kzalloc(sizeof(struct adv7393_state), GFP_KERNEL);
+       if (state == NULL)
+               return -ENOMEM;
+
+       state->reg00    = ADV7393_POWER_MODE_REG_DEFAULT;
+       state->reg01    = 0x00;
+       state->reg02    = 0x20;
+       state->reg35    = ADV7393_HD_MODE_REG6_DEFAULT;
+       state->reg80    = ADV7393_SD_MODE_REG1_DEFAULT;
+       state->reg82    = ADV7393_SD_MODE_REG2_DEFAULT;
+
+       state->output = ADV7393_COMPOSITE_ID;
+       state->std = V4L2_STD_NTSC;
+
+       v4l2_i2c_subdev_init(&state->sd, client, &adv7393_ops);
+
+       v4l2_ctrl_handler_init(&state->hdl, 3);
+       v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS, ADV7393_BRIGHTNESS_MIN,
+                                            ADV7393_BRIGHTNESS_MAX, 1,
+                                            ADV7393_BRIGHTNESS_DEF);
+       v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops,
+                       V4L2_CID_HUE, ADV7393_HUE_MIN,
+                                     ADV7393_HUE_MAX, 1,
+                                     ADV7393_HUE_DEF);
+       v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops,
+                       V4L2_CID_GAIN, ADV7393_GAIN_MIN,
+                                      ADV7393_GAIN_MAX, 1,
+                                      ADV7393_GAIN_DEF);
+       state->sd.ctrl_handler = &state->hdl;
+       if (state->hdl.error) {
+               int err = state->hdl.error;
+
+               v4l2_ctrl_handler_free(&state->hdl);
+               kfree(state);
+               return err;
+       }
+       v4l2_ctrl_handler_setup(&state->hdl);
+
+       err = adv7393_initialize(&state->sd);
+       if (err) {
+               v4l2_ctrl_handler_free(&state->hdl);
+               kfree(state);
+       }
+       return err;
+}
+
+static int adv7393_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct adv7393_state *state = to_state(sd);
+
+       v4l2_device_unregister_subdev(sd);
+       v4l2_ctrl_handler_free(&state->hdl);
+       kfree(state);
+
+       return 0;
+}
+
+static const struct i2c_device_id adv7393_id[] = {
+       {"adv7393", 0},
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, adv7393_id);
+
+static struct i2c_driver adv7393_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "adv7393",
+       },
+       .probe          = adv7393_probe,
+       .remove         = adv7393_remove,
+       .id_table       = adv7393_id,
+};
+module_i2c_driver(adv7393_driver);
diff --git a/drivers/media/video/adv7393_regs.h b/drivers/media/video/adv7393_regs.h
new file mode 100644 (file)
index 0000000..7896833
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * ADV7393 encoder related structure and register definitions
+ *
+ * Copyright (C) 2010-2012 ADVANSEE - http://www.advansee.com/
+ * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
+ *
+ * Based on ADV7343 driver,
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef ADV7393_REGS_H
+#define ADV7393_REGS_H
+
+struct adv7393_std_info {
+       u32 standard_val3;
+       u32 fsc_val;
+       v4l2_std_id stdid;
+};
+
+/* Register offset macros */
+#define ADV7393_POWER_MODE_REG         (0x00)
+#define ADV7393_MODE_SELECT_REG                (0x01)
+#define ADV7393_MODE_REG0              (0x02)
+
+#define ADV7393_DAC123_OUTPUT_LEVEL    (0x0B)
+
+#define ADV7393_SOFT_RESET             (0x17)
+
+#define ADV7393_HD_MODE_REG1           (0x30)
+#define ADV7393_HD_MODE_REG2           (0x31)
+#define ADV7393_HD_MODE_REG3           (0x32)
+#define ADV7393_HD_MODE_REG4           (0x33)
+#define ADV7393_HD_MODE_REG5           (0x34)
+#define ADV7393_HD_MODE_REG6           (0x35)
+
+#define ADV7393_HD_MODE_REG7           (0x39)
+
+#define ADV7393_SD_MODE_REG1           (0x80)
+#define ADV7393_SD_MODE_REG2           (0x82)
+#define ADV7393_SD_MODE_REG3           (0x83)
+#define ADV7393_SD_MODE_REG4           (0x84)
+#define ADV7393_SD_MODE_REG5           (0x86)
+#define ADV7393_SD_MODE_REG6           (0x87)
+#define ADV7393_SD_MODE_REG7           (0x88)
+#define ADV7393_SD_MODE_REG8           (0x89)
+
+#define ADV7393_SD_TIMING_REG0         (0x8A)
+
+#define ADV7393_FSC_REG0               (0x8C)
+#define ADV7393_FSC_REG1               (0x8D)
+#define ADV7393_FSC_REG2               (0x8E)
+#define ADV7393_FSC_REG3               (0x8F)
+
+#define ADV7393_SD_CGMS_WSS0           (0x99)
+
+#define ADV7393_SD_HUE_ADJUST          (0xA0)
+#define ADV7393_SD_BRIGHTNESS_WSS      (0xA1)
+
+/* Default values for the registers */
+#define ADV7393_POWER_MODE_REG_DEFAULT         (0x10)
+#define ADV7393_HD_MODE_REG1_DEFAULT           (0x3C)  /* Changed Default
+                                                          720p EAV/SAV code*/
+#define ADV7393_HD_MODE_REG2_DEFAULT           (0x01)  /* Changed Pixel data
+                                                          valid */
+#define ADV7393_HD_MODE_REG3_DEFAULT           (0x00)  /* Color delay 0 clks */
+#define ADV7393_HD_MODE_REG4_DEFAULT           (0xEC)  /* Changed */
+#define ADV7393_HD_MODE_REG5_DEFAULT           (0x08)
+#define ADV7393_HD_MODE_REG6_DEFAULT           (0x00)
+#define ADV7393_HD_MODE_REG7_DEFAULT           (0x00)
+#define ADV7393_SOFT_RESET_DEFAULT             (0x02)
+#define ADV7393_COMPOSITE_POWER_VALUE          (0x10)
+#define ADV7393_COMPONENT_POWER_VALUE          (0x1C)
+#define ADV7393_SVIDEO_POWER_VALUE             (0x0C)
+#define ADV7393_SD_HUE_ADJUST_DEFAULT          (0x80)
+#define ADV7393_SD_BRIGHTNESS_WSS_DEFAULT      (0x00)
+
+#define ADV7393_SD_CGMS_WSS0_DEFAULT           (0x10)
+
+#define ADV7393_SD_MODE_REG1_DEFAULT           (0x10)
+#define ADV7393_SD_MODE_REG2_DEFAULT           (0xC9)
+#define ADV7393_SD_MODE_REG3_DEFAULT           (0x00)
+#define ADV7393_SD_MODE_REG4_DEFAULT           (0x00)
+#define ADV7393_SD_MODE_REG5_DEFAULT           (0x02)
+#define ADV7393_SD_MODE_REG6_DEFAULT           (0x8C)
+#define ADV7393_SD_MODE_REG7_DEFAULT           (0x14)
+#define ADV7393_SD_MODE_REG8_DEFAULT           (0x00)
+
+#define ADV7393_SD_TIMING_REG0_DEFAULT         (0x0C)
+
+/* Bit masks for Mode Select Register */
+#define INPUT_MODE_MASK                        (0x70)
+#define SD_INPUT_MODE                  (0x00)
+#define HD_720P_INPUT_MODE             (0x10)
+#define HD_1080I_INPUT_MODE            (0x10)
+
+/* Bit masks for Mode Register 0 */
+#define TEST_PATTERN_BLACK_BAR_EN      (0x04)
+#define YUV_OUTPUT_SELECT              (0x20)
+#define RGB_OUTPUT_SELECT              (0xDF)
+
+/* Bit masks for SD brightness/WSS */
+#define SD_BRIGHTNESS_VALUE_MASK       (0x7F)
+#define SD_BLANK_WSS_DATA_MASK         (0x80)
+
+/* Bit masks for soft reset register */
+#define SOFT_RESET                     (0x02)
+
+/* Bit masks for HD Mode Register 1 */
+#define OUTPUT_STD_MASK                (0x03)
+#define OUTPUT_STD_SHIFT       (0)
+#define OUTPUT_STD_EIA0_2      (0x00)
+#define OUTPUT_STD_EIA0_1      (0x01)
+#define OUTPUT_STD_FULL                (0x02)
+#define EMBEDDED_SYNC          (0x04)
+#define EXTERNAL_SYNC          (0xFB)
+#define STD_MODE_MASK          (0x1F)
+#define STD_MODE_SHIFT         (3)
+#define STD_MODE_720P          (0x05)
+#define STD_MODE_720P_25       (0x08)
+#define STD_MODE_720P_30       (0x07)
+#define STD_MODE_720P_50       (0x06)
+#define STD_MODE_1080I         (0x0D)
+#define STD_MODE_1080I_25      (0x0E)
+#define STD_MODE_1080P_24      (0x11)
+#define STD_MODE_1080P_25      (0x10)
+#define STD_MODE_1080P_30      (0x0F)
+#define STD_MODE_525P          (0x00)
+#define STD_MODE_625P          (0x03)
+
+/* Bit masks for SD Mode Register 1 */
+#define SD_STD_MASK            (0x03)
+#define SD_STD_NTSC            (0x00)
+#define SD_STD_PAL_BDGHI       (0x01)
+#define SD_STD_PAL_M           (0x02)
+#define SD_STD_PAL_N           (0x03)
+#define SD_LUMA_FLTR_MASK      (0x07)
+#define SD_LUMA_FLTR_SHIFT     (2)
+#define SD_CHROMA_FLTR_MASK    (0x07)
+#define SD_CHROMA_FLTR_SHIFT   (5)
+
+/* Bit masks for SD Mode Register 2 */
+#define SD_PRPB_SSAF_EN                (0x01)
+#define SD_PRPB_SSAF_DI                (0xFE)
+#define SD_DAC_OUT1_EN         (0x02)
+#define SD_DAC_OUT1_DI         (0xFD)
+#define SD_PEDESTAL_EN         (0x08)
+#define SD_PEDESTAL_DI         (0xF7)
+#define SD_SQUARE_PIXEL_EN     (0x10)
+#define SD_SQUARE_PIXEL_DI     (0xEF)
+#define SD_PIXEL_DATA_VALID    (0x40)
+#define SD_ACTIVE_EDGE_EN      (0x80)
+#define SD_ACTIVE_EDGE_DI      (0x7F)
+
+/* Bit masks for HD Mode Register 6 */
+#define HD_PRPB_SYNC_EN                (0x04)
+#define HD_PRPB_SYNC_DI                (0xFB)
+#define HD_DAC_SWAP_EN         (0x08)
+#define HD_DAC_SWAP_DI         (0xF7)
+#define HD_GAMMA_CURVE_A       (0xEF)
+#define HD_GAMMA_CURVE_B       (0x10)
+#define HD_GAMMA_EN            (0x20)
+#define HD_GAMMA_DI            (0xDF)
+#define HD_ADPT_FLTR_MODEA     (0xBF)
+#define HD_ADPT_FLTR_MODEB     (0x40)
+#define HD_ADPT_FLTR_EN                (0x80)
+#define HD_ADPT_FLTR_DI                (0x7F)
+
+#define ADV7393_BRIGHTNESS_MAX (63)
+#define ADV7393_BRIGHTNESS_MIN (-64)
+#define ADV7393_BRIGHTNESS_DEF (0)
+#define ADV7393_HUE_MAX                (127)
+#define ADV7393_HUE_MIN                (-128)
+#define ADV7393_HUE_DEF                (0)
+#define ADV7393_GAIN_MAX       (64)
+#define ADV7393_GAIN_MIN       (-64)
+#define ADV7393_GAIN_DEF       (0)
+
+#endif
index 856ab962cd63516b79865d47414a2b7b59fa0926..5f3a00c2c4f6685a47b644136fe7beab01b15533 100644 (file)
@@ -676,6 +676,7 @@ struct tvcard bttv_tvcards[] = {
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .has_remote     = 1,
+               .has_radio      = 1,  /* not every card has radio */
        },
        [BTTV_BOARD_VOBIS_BOOSTAR] = {
                .name           = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
index ff7a589d8e0f5e0486dd72c8870e4d965a8ce50e..b58ff87db771750dfa7a511d7f382b924dba8814 100644 (file)
@@ -557,12 +557,6 @@ static const struct bttv_format formats[] = {
                .btformat = BT848_COLOR_FMT_YUY2,
                .depth    = 16,
                .flags    = FORMAT_FLAGS_PACKED,
-       },{
-               .name     = "4:2:2, packed, YUYV",
-               .fourcc   = V4L2_PIX_FMT_YUYV,
-               .btformat = BT848_COLOR_FMT_YUY2,
-               .depth    = 16,
-               .flags    = FORMAT_FLAGS_PACKED,
        },{
                .name     = "4:2:2, packed, UYVY",
                .fourcc   = V4L2_PIX_FMT_UYVY,
index 55e92902a76c6292900b62f4eec8c233b18ce8fe..a62a7b739991806567231870dc143ceb3cac675a 100644 (file)
@@ -932,7 +932,7 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
        buf->sequence = cam->buffers[buf->index].seq;
        buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
        buf->length = cam->frame_size;
-       buf->input = 0;
+       buf->reserved2 = 0;
        buf->reserved = 0;
        memset(&buf->timecode, 0, sizeof(buf->timecode));
 
diff --git a/drivers/media/video/cs8420.h b/drivers/media/video/cs8420.h
deleted file mode 100644 (file)
index 621c0c6..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* cs8420.h - cs8420 initializations
-   Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-#ifndef __CS8420_H__
-#define __CS8420_H__
-
-/* Initialization Sequence */
-
-static __u8 init8420[] = {
-       1, 0x01,        2, 0x02,        3, 0x00,        4, 0x46,
-       5, 0x24,        6, 0x84,        18, 0x18,       19, 0x13,
-};
-
-#define INIT8420LEN    (sizeof(init8420)/2)
-
-static __u8 mode8420pro[] = {  /* professional output mode */
-       32, 0xa1,       33, 0x00,       34, 0x00,       35, 0x00,
-       36, 0x00,       37, 0x00,       38, 0x00,       39, 0x00,
-       40, 0x00,       41, 0x00,       42, 0x00,       43, 0x00,
-       44, 0x00,       45, 0x00,       46, 0x00,       47, 0x00,
-       48, 0x00,       49, 0x00,       50, 0x00,       51, 0x00,
-       52, 0x00,       53, 0x00,       54, 0x00,       55, 0x00,
-};
-#define MODE8420LEN    (sizeof(mode8420pro)/2)
-
-static __u8 mode8420con[] = {  /* consumer output mode */
-       32, 0x20,       33, 0x00,       34, 0x00,       35, 0x48,
-       36, 0x00,       37, 0x00,       38, 0x00,       39, 0x00,
-       40, 0x00,       41, 0x00,       42, 0x00,       43, 0x00,
-       44, 0x00,       45, 0x00,       46, 0x00,       47, 0x00,
-       48, 0x00,       49, 0x00,       50, 0x00,       51, 0x00,
-       52, 0x00,       53, 0x00,       54, 0x00,       55, 0x00,
-};
-
-#endif
index 35fde4e931f5c4c4b7c97e7303d229acf3b35500..e9912db3b496ae69618b411896fe054ba35d4827 100644 (file)
@@ -1142,24 +1142,6 @@ static long cx18_default(struct file *file, void *fh, bool valid_prio,
        return 0;
 }
 
-long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd,
-                   unsigned long arg)
-{
-       struct video_device *vfd = video_devdata(filp);
-       struct cx18_open_id *id = file2id(filp);
-       struct cx18 *cx = id->cx;
-       long res;
-
-       mutex_lock(&cx->serialize_lock);
-
-       if (cx18_debug & CX18_DBGFLG_IOCTL)
-               vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
-       res = video_ioctl2(filp, cmd, arg);
-       vfd->debug = 0;
-       mutex_unlock(&cx->serialize_lock);
-       return res;
-}
-
 static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
        .vidioc_querycap                = cx18_querycap,
        .vidioc_s_audio                 = cx18_s_audio,
index dcb2559ad52050dbaeb0420bff74ed8ebae660f4..2f9dd591ee0f9421d95610756b91b43fbb419674 100644 (file)
@@ -29,5 +29,3 @@ void cx18_set_funcs(struct video_device *vdev);
 int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std);
 int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
 int cx18_s_input(struct file *file, void *fh, unsigned int inp);
-long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd,
-                   unsigned long arg);
index 4185bcb80ca3fb01c45c0d9b97b9139c087b94b8..9d598ab88615c07a82103010e6cb9c5a1e19600d 100644 (file)
@@ -40,8 +40,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = {
        .owner = THIS_MODULE,
        .read = cx18_v4l2_read,
        .open = cx18_v4l2_open,
-       /* FIXME change to video_ioctl2 if serialization lock can be removed */
-       .unlocked_ioctl = cx18_v4l2_ioctl,
+       .unlocked_ioctl = video_ioctl2,
        .release = cx18_v4l2_close,
        .poll = cx18_v4l2_enc_poll,
        .mmap = cx18_v4l2_mmap,
@@ -376,6 +375,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
        s->video_dev->fops = &cx18_v4l2_enc_fops;
        s->video_dev->release = video_device_release;
        s->video_dev->tvnorms = V4L2_STD_ALL;
+       s->video_dev->lock = &cx->serialize_lock;
        set_bit(V4L2_FL_USE_FH_PRIO, &s->video_dev->flags);
        cx18_set_funcs(s->video_dev);
        return 0;
index b085a3c6dc048fb29514669046d4d145ee55351e..447148eff9588658f954ba5e3d90cdbe6c1fbc76 100644 (file)
@@ -89,7 +89,7 @@ void initGPIO(struct cx231xx *dev)
        verve_read_byte(dev, 0x07, &val);
        cx231xx_info(" verve_read_byte address0x07=0x%x\n", val);
 
-       cx231xx_capture_start(dev, 1, 2);
+       cx231xx_capture_start(dev, 1, Vbi);
 
        cx231xx_mode_register(dev, EP_MODE_SET, 0x0500FE00);
        cx231xx_mode_register(dev, GBULK_BIT_EN, 0xFFFDFFFF);
@@ -99,7 +99,7 @@ void uninitGPIO(struct cx231xx *dev)
 {
        u8 value[4] = { 0, 0, 0, 0 };
 
-       cx231xx_capture_start(dev, 0, 2);
+       cx231xx_capture_start(dev, 0, Vbi);
        verve_write_byte(dev, 0x07, 0x14);
        cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
                        0x68, value, 4);
@@ -2516,29 +2516,29 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
 
        if (dev->udev->speed == USB_SPEED_HIGH) {
                switch (media_type) {
-               case 81: /* audio */
+               case Audio:
                        cx231xx_info("%s: Audio enter HANC\n", __func__);
                        status =
                            cx231xx_mode_register(dev, TS_MODE_REG, 0x9300);
                        break;
 
-               case 2: /* vbi */
+               case Vbi:
                        cx231xx_info("%s: set vanc registers\n", __func__);
                        status = cx231xx_mode_register(dev, TS_MODE_REG, 0x300);
                        break;
 
-               case 3: /* sliced cc */
+               case Sliced_cc:
                        cx231xx_info("%s: set hanc registers\n", __func__);
                        status =
                            cx231xx_mode_register(dev, TS_MODE_REG, 0x1300);
                        break;
 
-               case 0: /* video */
+               case Raw_Video:
                        cx231xx_info("%s: set video registers\n", __func__);
                        status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100);
                        break;
 
-               case 4: /* ts1 */
+               case TS1_serial_mode:
                        cx231xx_info("%s: set ts1 registers", __func__);
 
                if (dev->board.has_417) {
@@ -2569,7 +2569,7 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
                }
                        break;
 
-               case 6: /* ts1 parallel mode */
+               case TS1_parallel_mode:
                        cx231xx_info("%s: set ts1 parallel mode registers\n",
                                     __func__);
                        status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100);
@@ -2592,52 +2592,28 @@ int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type)
        /* get EP for media type */
        pcb_config = (struct pcb_config *)&dev->current_pcb_config;
 
-       if (pcb_config->config_num == 1) {
+       if (pcb_config->config_num) {
                switch (media_type) {
-               case 0: /* Video */
+               case Raw_Video:
                        ep_mask = ENABLE_EP4;   /* ep4  [00:1000] */
                        break;
-               case 1: /* Audio */
+               case Audio:
                        ep_mask = ENABLE_EP3;   /* ep3  [00:0100] */
                        break;
-               case 2: /* Vbi */
+               case Vbi:
                        ep_mask = ENABLE_EP5;   /* ep5 [01:0000] */
                        break;
-               case 3: /* Sliced_cc */
+               case Sliced_cc:
                        ep_mask = ENABLE_EP6;   /* ep6 [10:0000] */
                        break;
-               case 4: /* ts1 */
-               case 6: /* ts1 parallel mode */
+               case TS1_serial_mode:
+               case TS1_parallel_mode:
                        ep_mask = ENABLE_EP1;   /* ep1 [00:0001] */
                        break;
-               case 5: /* ts2 */
+               case TS2:
                        ep_mask = ENABLE_EP2;   /* ep2 [00:0010] */
                        break;
                }
-
-       } else if (pcb_config->config_num > 1) {
-               switch (media_type) {
-               case 0: /* Video */
-                       ep_mask = ENABLE_EP4;   /* ep4  [00:1000] */
-                       break;
-               case 1: /* Audio */
-                       ep_mask = ENABLE_EP3;   /* ep3  [00:0100] */
-                       break;
-               case 2: /* Vbi */
-                       ep_mask = ENABLE_EP5;   /* ep5 [01:0000] */
-                       break;
-               case 3: /* Sliced_cc */
-                       ep_mask = ENABLE_EP6;   /* ep6 [10:0000] */
-                       break;
-               case 4: /* ts1 */
-               case 6: /* ts1 parallel mode */
-                       ep_mask = ENABLE_EP1;   /* ep1 [00:0001] */
-                       break;
-               case 5: /* ts2 */
-                       ep_mask = ENABLE_EP2;   /* ep2 [00:0010] */
-                       break;
-               }
-
        }
 
        if (start) {
index 8ed460d692e0485925c156d0314e9ee50756c634..02d4d36735d39e6d68a1f8b82d3f3896f4a8e468 100644 (file)
@@ -1023,7 +1023,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        int nr = 0, ifnum;
        int i, isoc_pipe = 0;
        char *speed;
-       char descr[255] = "";
        struct usb_interface_assoc_descriptor *assoc_desc;
 
        udev = usb_get_dev(interface_to_usbdev(interface));
@@ -1098,20 +1097,10 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
                speed = "unknown";
        }
 
-       if (udev->manufacturer)
-               strlcpy(descr, udev->manufacturer, sizeof(descr));
-
-       if (udev->product) {
-               if (*descr)
-                       strlcat(descr, " ", sizeof(descr));
-               strlcat(descr, udev->product, sizeof(descr));
-       }
-       if (*descr)
-               strlcat(descr, " ", sizeof(descr));
-
-       cx231xx_info("New device %s@ %s Mbps "
+       cx231xx_info("New device %s %s @ %s Mbps "
             "(%04x:%04x) with %d interfaces\n",
-            descr,
+            udev->manufacturer ? udev->manufacturer : "",
+            udev->product ? udev->product : "",
             speed,
             le16_to_cpu(udev->descriptor.idVendor),
             le16_to_cpu(udev->descriptor.idProduct),
index 04bf6627d3629c824e174e4679de2525ff16ee38..dfac6e34859fc2d7b8647ac4c8afdd70f6e2de8b 100644 (file)
@@ -585,13 +585,10 @@ static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol,
 {
        snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
        struct cx88_core *core = chip->core;
-       struct v4l2_control client_ctl;
        int left = value->value.integer.value[0];
        int right = value->value.integer.value[1];
        int v, b;
 
-       memset(&client_ctl, 0, sizeof(client_ctl));
-
        /* Pass volume & balance onto any WM8775 */
        if (left >= right) {
                v = left << 10;
@@ -600,13 +597,8 @@ static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol,
                v = right << 10;
                b = right ? 0xffff - (0x8000 * left) / right : 0x8000;
        }
-       client_ctl.value = v;
-       client_ctl.id = V4L2_CID_AUDIO_VOLUME;
-       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
-
-       client_ctl.value = b;
-       client_ctl.id = V4L2_CID_AUDIO_BALANCE;
-       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+       wm8775_s_ctrl(core, V4L2_CID_AUDIO_VOLUME, v);
+       wm8775_s_ctrl(core, V4L2_CID_AUDIO_BALANCE, b);
 }
 
 /* OK - TODO: test it */
@@ -687,14 +679,8 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
                cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);
                /* Pass mute onto any WM8775 */
                if ((core->board.audio_chip == V4L2_IDENT_WM8775) &&
-                   ((1<<6) == bit)) {
-                       struct v4l2_control client_ctl;
-
-                       memset(&client_ctl, 0, sizeof(client_ctl));
-                       client_ctl.value = 0 != (vol & bit);
-                       client_ctl.id = V4L2_CID_AUDIO_MUTE;
-                       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
-               }
+                   ((1<<6) == bit))
+                       wm8775_s_ctrl(core, V4L2_CID_AUDIO_MUTE, 0 != (vol & bit));
                ret = 1;
        }
        spin_unlock_irq(&chip->reg_lock);
@@ -724,13 +710,10 @@ static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,
 {
        snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
        struct cx88_core *core = chip->core;
-       struct v4l2_control client_ctl;
-
-       memset(&client_ctl, 0, sizeof(client_ctl));
-       client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
-       call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl);
-       value->value.integer.value[0] = client_ctl.value ? 1 : 0;
+       s32 val;
 
+       val = wm8775_g_ctrl(core, V4L2_CID_AUDIO_LOUDNESS);
+       value->value.integer.value[0] = val ? 1 : 0;
        return 0;
 }
 
index ed7b2aa1ed831d4582c68679476ce8b08b733da7..843ffd9e533b06a04e4eb7720743ec35624e4eb0 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/firmware.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 #include <media/cx2341x.h>
 
 #include "cx88.h"
@@ -523,11 +524,10 @@ static void blackbird_codec_settings(struct cx8802_dev *dev)
        blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
                                dev->height, dev->width);
 
-       dev->params.width = dev->width;
-       dev->params.height = dev->height;
-       dev->params.is_50hz = (dev->core->tvnorm & V4L2_STD_625_50) != 0;
-
-       cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
+       dev->cxhdl.width = dev->width;
+       dev->cxhdl.height = dev->height;
+       cx2341x_handler_set_50hz(&dev->cxhdl, dev->core->tvnorm & V4L2_STD_625_50);
+       cx2341x_handler_setup(&dev->cxhdl);
 }
 
 static int blackbird_initialize_codec(struct cx8802_dev *dev)
@@ -618,6 +618,8 @@ static int blackbird_start_codec(struct file *file, void *priv)
        /* initialize the video input */
        blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
 
+       cx2341x_handler_set_busy(&dev->cxhdl, 1);
+
        /* start capturing to the host interface */
        blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
                        BLACKBIRD_MPEG_CAPTURE,
@@ -636,6 +638,8 @@ static int blackbird_stop_codec(struct cx8802_dev *dev)
                        BLACKBIRD_RAW_BITS_NONE
                );
 
+       cx2341x_handler_set_busy(&dev->cxhdl, 0);
+
        dev->mpeg_active = 0;
        return 0;
 }
@@ -685,58 +689,15 @@ static struct videobuf_queue_ops blackbird_qops = {
 
 /* ------------------------------------------------------------------ */
 
-static const u32 *ctrl_classes[] = {
-       cx88_user_ctrls,
-       cx2341x_mpeg_ctrls,
-       NULL
-};
-
-static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qctrl)
-{
-       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
-       if (qctrl->id == 0)
-               return -EINVAL;
-
-       /* Standard V4L2 controls */
-       if (cx8800_ctrl_query(dev->core, qctrl) == 0)
-               return 0;
-
-       /* MPEG V4L2 controls */
-       if (cx2341x_ctrl_query(&dev->params, qctrl))
-               qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
-       return 0;
-}
-
-/* ------------------------------------------------------------------ */
-/* IOCTL Handlers                                                     */
-
-static int vidioc_querymenu (struct file *file, void *priv,
-                               struct v4l2_querymenu *qmenu)
-{
-       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
-       struct v4l2_queryctrl qctrl;
-
-       qctrl.id = qmenu->id;
-       blackbird_queryctrl(dev, &qctrl);
-       return v4l2_ctrl_query_menu(qmenu, &qctrl,
-                       cx2341x_ctrl_get_menu(&dev->params, qmenu->id));
-}
-
-static int vidioc_querycap (struct file *file, void  *priv,
+static int vidioc_querycap(struct file *file, void  *priv,
                                        struct v4l2_capability *cap)
 {
        struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
        struct cx88_core  *core = dev->core;
 
        strcpy(cap->driver, "cx88_blackbird");
-       strlcpy(cap->card, core->board.name, sizeof(cap->card));
-       sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-       cap->capabilities =
-               V4L2_CAP_VIDEO_CAPTURE |
-               V4L2_CAP_READWRITE     |
-               V4L2_CAP_STREAMING;
-       if (UNSET != core->board.tuner_type)
-               cap->capabilities |= V4L2_CAP_TUNER;
+       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+       cx88_querycap(file, core, cap);
        return 0;
 }
 
@@ -748,6 +709,7 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
 
        strlcpy(f->description, "MPEG", sizeof(f->description));
        f->pixelformat = V4L2_PIX_FMT_MPEG;
+       f->flags = V4L2_FMT_FLAG_COMPRESSED;
        return 0;
 }
 
@@ -759,12 +721,12 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
-       f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
-       f->fmt.pix.colorspace   = 0;
+       f->fmt.pix.sizeimage    = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */;
+       f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
        f->fmt.pix.width        = dev->width;
        f->fmt.pix.height       = dev->height;
        f->fmt.pix.field        = fh->mpegq.field;
-       dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+       dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
                dev->width, dev->height, fh->mpegq.field );
        return 0;
 }
@@ -777,9 +739,9 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
-       f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
-       f->fmt.pix.colorspace   = 0;
-       dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+       f->fmt.pix.sizeimage    = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */;
+       f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
+       dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
                dev->width, dev->height, fh->mpegq.field );
        return 0;
 }
@@ -793,15 +755,15 @@ static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
 
        f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
        f->fmt.pix.bytesperline = 0;
-       f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
-       f->fmt.pix.colorspace   = 0;
+       f->fmt.pix.sizeimage    = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */;
+       f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
        dev->width              = f->fmt.pix.width;
        dev->height             = f->fmt.pix.height;
        fh->mpegq.field         = f->fmt.pix.field;
        cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
        blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
                                f->fmt.pix.height, f->fmt.pix.width);
-       dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+       dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
                f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
        return 0;
 }
@@ -834,60 +796,21 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
        struct cx8802_fh  *fh   = priv;
+       struct cx8802_dev *dev  = fh->dev;
+
+       if (!dev->mpeg_active)
+               blackbird_start_codec(file, fh);
        return videobuf_streamon(&fh->mpegq);
 }
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
        struct cx8802_fh  *fh   = priv;
-       return videobuf_streamoff(&fh->mpegq);
-}
-
-static int vidioc_g_ext_ctrls (struct file *file, void *priv,
-                              struct v4l2_ext_controls *f)
-{
-       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
-
-       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-       return cx2341x_ext_ctrls(&dev->params, 0, f, VIDIOC_G_EXT_CTRLS);
-}
-
-static int vidioc_s_ext_ctrls (struct file *file, void *priv,
-                              struct v4l2_ext_controls *f)
-{
-       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
-       struct cx2341x_mpeg_params p;
-       int err;
-
-       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
+       struct cx8802_dev *dev  = fh->dev;
 
        if (dev->mpeg_active)
                blackbird_stop_codec(dev);
-
-       p = dev->params;
-       err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
-       if (!err) {
-               err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
-               dev->params = p;
-       }
-       return err;
-}
-
-static int vidioc_try_ext_ctrls (struct file *file, void *priv,
-                              struct v4l2_ext_controls *f)
-{
-       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
-       struct cx2341x_mpeg_params p;
-       int err;
-
-       if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-       p = dev->params;
-       err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
-
-       return err;
+       return videobuf_streamoff(&fh->mpegq);
 }
 
 static int vidioc_s_frequency (struct file *file, void *priv,
@@ -897,6 +820,10 @@ static int vidioc_s_frequency (struct file *file, void *priv,
        struct cx8802_dev *dev  = fh->dev;
        struct cx88_core  *core = dev->core;
 
+       if (unlikely(UNSET == core->board.tuner_type))
+               return -EINVAL;
+       if (unlikely(f->tuner != 0))
+               return -EINVAL;
        if (dev->mpeg_active)
                blackbird_stop_codec(dev);
 
@@ -914,29 +841,11 @@ static int vidioc_log_status (struct file *file, void *priv)
        char name[32 + 2];
 
        snprintf(name, sizeof(name), "%s/2", core->name);
-       printk("%s/2: ============  START LOG STATUS  ============\n",
-               core->name);
        call_all(core, core, log_status);
-       cx2341x_log_status(&dev->params, name);
-       printk("%s/2: =============  END LOG STATUS  =============\n",
-               core->name);
+       v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name);
        return 0;
 }
 
-static int vidioc_queryctrl (struct file *file, void *priv,
-                               struct v4l2_queryctrl *qctrl)
-{
-       struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
-
-       if (blackbird_queryctrl(dev, qctrl) == 0)
-               return 0;
-
-       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
-       if (unlikely(qctrl->id == 0))
-               return -EINVAL;
-       return cx8800_ctrl_query(dev->core, qctrl);
-}
-
 static int vidioc_enum_input (struct file *file, void *priv,
                                struct v4l2_input *i)
 {
@@ -944,22 +853,6 @@ static int vidioc_enum_input (struct file *file, void *priv,
        return cx88_enum_input (core,i);
 }
 
-static int vidioc_g_ctrl (struct file *file, void *priv,
-                               struct v4l2_control *ctl)
-{
-       struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
-       return
-               cx88_get_control(core,ctl);
-}
-
-static int vidioc_s_ctrl (struct file *file, void *priv,
-                               struct v4l2_control *ctl)
-{
-       struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
-       return
-               cx88_set_control(core,ctl);
-}
-
 static int vidioc_g_frequency (struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
@@ -968,8 +861,9 @@ static int vidioc_g_frequency (struct file *file, void *priv,
 
        if (unlikely(UNSET == core->board.tuner_type))
                return -EINVAL;
+       if (unlikely(f->tuner != 0))
+               return -EINVAL;
 
-       f->type = V4L2_TUNER_ANALOG_TV;
        f->frequency = core->freq;
        call_all(core, tuner, g_frequency, f);
 
@@ -990,6 +884,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
 
        if (i >= 4)
                return -EINVAL;
+       if (0 == INPUT(i).type)
+               return -EINVAL;
 
        mutex_lock(&core->lock);
        cx88_newstation(core);
@@ -1010,9 +906,9 @@ static int vidioc_g_tuner (struct file *file, void *priv,
                return -EINVAL;
 
        strcpy(t->name, "Television");
-       t->type       = V4L2_TUNER_ANALOG_TV;
        t->capability = V4L2_TUNER_CAP_NORM;
        t->rangehigh  = 0xffffffffUL;
+       call_all(core, tuner, g_tuner, t);
 
        cx88_get_stereo(core ,t);
        reg = cx_read(MO_DEVICE_STATUS);
@@ -1034,6 +930,14 @@ static int vidioc_s_tuner (struct file *file, void *priv,
        return 0;
 }
 
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
+{
+       struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+       *tvnorm = core->tvnorm;
+       return 0;
+}
+
 static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
 {
        struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
@@ -1087,6 +991,7 @@ static int mpeg_open(struct file *file)
                mutex_unlock(&dev->core->lock);
                return -ENOMEM;
        }
+       v4l2_fh_init(&fh->fh, vdev);
        file->private_data = fh;
        fh->dev      = dev;
 
@@ -1103,6 +1008,7 @@ static int mpeg_open(struct file *file)
 
        dev->core->mpeg_users++;
        mutex_unlock(&dev->core->lock);
+       v4l2_fh_add(&fh->fh);
        return 0;
 }
 
@@ -1123,6 +1029,8 @@ static int mpeg_release(struct file *file)
 
        videobuf_mmap_free(&fh->mpegq);
 
+       v4l2_fh_del(&fh->fh);
+       v4l2_fh_exit(&fh->fh);
        file->private_data = NULL;
        kfree(fh);
 
@@ -1155,13 +1063,14 @@ mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 static unsigned int
 mpeg_poll(struct file *file, struct poll_table_struct *wait)
 {
+       unsigned long req_events = poll_requested_events(wait);
        struct cx8802_fh *fh = file->private_data;
        struct cx8802_dev *dev = fh->dev;
 
-       if (!dev->mpeg_active)
+       if (!dev->mpeg_active && (req_events & (POLLIN | POLLRDNORM)))
                blackbird_start_codec(file, fh);
 
-       return videobuf_poll_stream(file, &fh->mpegq, wait);
+       return v4l2_ctrl_poll(file, wait) | videobuf_poll_stream(file, &fh->mpegq, wait);
 }
 
 static int
@@ -1180,11 +1089,10 @@ static const struct v4l2_file_operations mpeg_fops =
        .read          = mpeg_read,
        .poll          = mpeg_poll,
        .mmap          = mpeg_mmap,
-       .ioctl         = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
-       .vidioc_querymenu     = vidioc_querymenu,
        .vidioc_querycap      = vidioc_querycap,
        .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
        .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
@@ -1196,21 +1104,18 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
        .vidioc_dqbuf         = vidioc_dqbuf,
        .vidioc_streamon      = vidioc_streamon,
        .vidioc_streamoff     = vidioc_streamoff,
-       .vidioc_g_ext_ctrls   = vidioc_g_ext_ctrls,
-       .vidioc_s_ext_ctrls   = vidioc_s_ext_ctrls,
-       .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
        .vidioc_s_frequency   = vidioc_s_frequency,
        .vidioc_log_status    = vidioc_log_status,
-       .vidioc_queryctrl     = vidioc_queryctrl,
        .vidioc_enum_input    = vidioc_enum_input,
-       .vidioc_g_ctrl        = vidioc_g_ctrl,
-       .vidioc_s_ctrl        = vidioc_s_ctrl,
        .vidioc_g_frequency   = vidioc_g_frequency,
        .vidioc_g_input       = vidioc_g_input,
        .vidioc_s_input       = vidioc_s_input,
        .vidioc_g_tuner       = vidioc_g_tuner,
        .vidioc_s_tuner       = vidioc_s_tuner,
+       .vidioc_g_std         = vidioc_g_std,
        .vidioc_s_std         = vidioc_s_std,
+       .vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
 };
 
 static struct video_device cx8802_mpeg_template = {
@@ -1218,7 +1123,6 @@ static struct video_device cx8802_mpeg_template = {
        .fops                 = &mpeg_fops,
        .ioctl_ops            = &mpeg_ioctl_ops,
        .tvnorms              = CX88_NORMS,
-       .current_norm         = V4L2_STD_NTSC_M,
 };
 
 /* ------------------------------------------------------------------ */
@@ -1286,6 +1190,7 @@ static int blackbird_register_video(struct cx8802_dev *dev)
 
        dev->mpeg_dev = cx88_vdev_init(dev->core,dev->pci,
                                       &cx8802_mpeg_template,"mpeg");
+       dev->mpeg_dev->ctrl_handler = &dev->cxhdl.hdl;
        video_set_drvdata(dev->mpeg_dev, dev);
        err = video_register_device(dev->mpeg_dev,VFL_TYPE_GRABBER, -1);
        if (err < 0) {
@@ -1318,17 +1223,20 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
                goto fail_core;
 
        dev->width = 720;
-       dev->height = 576;
-       cx2341x_fill_defaults(&dev->params);
-       dev->params.port = CX2341X_PORT_STREAMING;
-
-       cx8802_mpeg_template.current_norm = core->tvnorm;
-
        if (core->tvnorm & V4L2_STD_525_60) {
                dev->height = 480;
        } else {
                dev->height = 576;
        }
+       dev->cxhdl.port = CX2341X_PORT_STREAMING;
+       dev->cxhdl.width = dev->width;
+       dev->cxhdl.height = dev->height;
+       dev->cxhdl.func = blackbird_mbox_func;
+       dev->cxhdl.priv = dev;
+       err = cx2341x_handler_init(&dev->cxhdl, 36);
+       if (err)
+               goto fail_core;
+       v4l2_ctrl_add_handler(&dev->cxhdl.hdl, &core->video_hdl);
 
        /* blackbird stuff */
        printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n",
@@ -1336,12 +1244,14 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
        host_setup(dev->core);
 
        blackbird_initialize_codec(dev);
-       blackbird_register_video(dev);
 
        /* initial device configuration: needed ? */
 //     init_controls(core);
        cx88_set_tvnorm(core,core->tvnorm);
        cx88_video_mux(core,0);
+       cx2341x_handler_set_50hz(&dev->cxhdl, dev->height == 576);
+       cx2341x_handler_setup(&dev->cxhdl);
+       blackbird_register_video(dev);
 
        return 0;
 
@@ -1351,8 +1261,12 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
 
 static int cx8802_blackbird_remove(struct cx8802_driver *drv)
 {
+       struct cx88_core *core = drv->core;
+       struct cx8802_dev *dev = core->dvbdev;
+
        /* blackbird */
        blackbird_unregister_video(drv->core->dvbdev);
+       v4l2_ctrl_handler_free(&dev->cxhdl.hdl);
 
        return 0;
 }
index cbd5d119a2c660ebd7f8e9aba9b4206795d290e9..4e9d4f7229602e3e3a4f3fbc1a321507a07d894a 100644 (file)
@@ -3693,7 +3693,22 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
                return NULL;
        }
 
+       if (v4l2_ctrl_handler_init(&core->video_hdl, 13)) {
+               v4l2_device_unregister(&core->v4l2_dev);
+               kfree(core);
+               return NULL;
+       }
+
+       if (v4l2_ctrl_handler_init(&core->audio_hdl, 13)) {
+               v4l2_ctrl_handler_free(&core->video_hdl);
+               v4l2_device_unregister(&core->v4l2_dev);
+               kfree(core);
+               return NULL;
+       }
+
        if (0 != cx88_get_resources(core, pci)) {
+               v4l2_ctrl_handler_free(&core->video_hdl);
+               v4l2_ctrl_handler_free(&core->audio_hdl);
                v4l2_device_unregister(&core->v4l2_dev);
                kfree(core);
                return NULL;
@@ -3706,6 +3721,11 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
        core->bmmio = (u8 __iomem *)core->lmmio;
 
        if (core->lmmio == NULL) {
+               release_mem_region(pci_resource_start(pci, 0),
+                          pci_resource_len(pci, 0));
+               v4l2_ctrl_handler_free(&core->video_hdl);
+               v4l2_ctrl_handler_free(&core->audio_hdl);
+               v4l2_device_unregister(&core->v4l2_dev);
                kfree(core);
                return NULL;
        }
index fbfdd8067937604ab31482727a3204de970a6167..e81c735f012a263b918bfdb324aff12578b06c1d 100644 (file)
@@ -1012,6 +1012,9 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
        // tell i2c chips
        call_all(core, core, s_std, norm);
 
+       /* The chroma_agc control should be inaccessible if the video format is SECAM */
+       v4l2_ctrl_grab(core->chroma_agc, cxiformat == VideoFormatSECAM);
+
        // done
        return 0;
 }
@@ -1030,10 +1033,10 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
                return NULL;
        *vfd = *template_;
        vfd->v4l2_dev = &core->v4l2_dev;
-       vfd->parent = &pci->dev;
        vfd->release = video_device_release;
        snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
                 core->name, type, core->board.name);
+       set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
        return vfd;
 }
 
@@ -1086,6 +1089,8 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
        iounmap(core->lmmio);
        cx88_devcount--;
        mutex_unlock(&devlist);
+       v4l2_ctrl_handler_free(&core->video_hdl);
+       v4l2_ctrl_handler_free(&core->audio_hdl);
        v4l2_device_unregister(&core->v4l2_dev);
        kfree(core);
 }
index 921c56d115d6e06ec228f4edd7d301f4b5fe338c..f6fcc7e763ab9c1964bbd9eab1d18b6bb6749eec 100644 (file)
@@ -40,6 +40,7 @@
 #include "cx88.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 #include <media/wm8775.h>
 
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
@@ -155,219 +156,147 @@ static const struct cx8800_fmt* format_by_fourcc(unsigned int fourcc)
 
 /* ------------------------------------------------------------------- */
 
-static const struct v4l2_queryctrl no_ctl = {
-       .name  = "42",
-       .flags = V4L2_CTRL_FLAG_DISABLED,
+struct cx88_ctrl {
+       /* control information */
+       u32 id;
+       s32 minimum;
+       s32 maximum;
+       u32 step;
+       s32 default_value;
+
+       /* control register information */
+       u32 off;
+       u32 reg;
+       u32 sreg;
+       u32 mask;
+       u32 shift;
 };
 
-static const struct cx88_ctrl cx8800_ctls[] = {
+static const struct cx88_ctrl cx8800_vid_ctls[] = {
        /* --- video --- */
        {
-               .v = {
-                       .id            = V4L2_CID_BRIGHTNESS,
-                       .name          = "Brightness",
-                       .minimum       = 0x00,
-                       .maximum       = 0xff,
-                       .step          = 1,
-                       .default_value = 0x7f,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 128,
-               .reg                   = MO_CONTR_BRIGHT,
-               .mask                  = 0x00ff,
-               .shift                 = 0,
+               .id            = V4L2_CID_BRIGHTNESS,
+               .minimum       = 0x00,
+               .maximum       = 0xff,
+               .step          = 1,
+               .default_value = 0x7f,
+               .off           = 128,
+               .reg           = MO_CONTR_BRIGHT,
+               .mask          = 0x00ff,
+               .shift         = 0,
        },{
-               .v = {
-                       .id            = V4L2_CID_CONTRAST,
-                       .name          = "Contrast",
-                       .minimum       = 0,
-                       .maximum       = 0xff,
-                       .step          = 1,
-                       .default_value = 0x3f,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 0,
-               .reg                   = MO_CONTR_BRIGHT,
-               .mask                  = 0xff00,
-               .shift                 = 8,
+               .id            = V4L2_CID_CONTRAST,
+               .minimum       = 0,
+               .maximum       = 0xff,
+               .step          = 1,
+               .default_value = 0x3f,
+               .off           = 0,
+               .reg           = MO_CONTR_BRIGHT,
+               .mask          = 0xff00,
+               .shift         = 8,
        },{
-               .v = {
-                       .id            = V4L2_CID_HUE,
-                       .name          = "Hue",
-                       .minimum       = 0,
-                       .maximum       = 0xff,
-                       .step          = 1,
-                       .default_value = 0x7f,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 128,
-               .reg                   = MO_HUE,
-               .mask                  = 0x00ff,
-               .shift                 = 0,
+               .id            = V4L2_CID_HUE,
+               .minimum       = 0,
+               .maximum       = 0xff,
+               .step          = 1,
+               .default_value = 0x7f,
+               .off           = 128,
+               .reg           = MO_HUE,
+               .mask          = 0x00ff,
+               .shift         = 0,
        },{
                /* strictly, this only describes only U saturation.
                 * V saturation is handled specially through code.
                 */
-               .v = {
-                       .id            = V4L2_CID_SATURATION,
-                       .name          = "Saturation",
-                       .minimum       = 0,
-                       .maximum       = 0xff,
-                       .step          = 1,
-                       .default_value = 0x7f,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 0,
-               .reg                   = MO_UV_SATURATION,
-               .mask                  = 0x00ff,
-               .shift                 = 0,
+               .id            = V4L2_CID_SATURATION,
+               .minimum       = 0,
+               .maximum       = 0xff,
+               .step          = 1,
+               .default_value = 0x7f,
+               .off           = 0,
+               .reg           = MO_UV_SATURATION,
+               .mask          = 0x00ff,
+               .shift         = 0,
        }, {
-               .v = {
-                       .id            = V4L2_CID_SHARPNESS,
-                       .name          = "Sharpness",
-                       .minimum       = 0,
-                       .maximum       = 4,
-                       .step          = 1,
-                       .default_value = 0x0,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 0,
+               .id            = V4L2_CID_SHARPNESS,
+               .minimum       = 0,
+               .maximum       = 4,
+               .step          = 1,
+               .default_value = 0x0,
+               .off           = 0,
                /* NOTE: the value is converted and written to both even
                   and odd registers in the code */
-               .reg                   = MO_FILTER_ODD,
-               .mask                  = 7 << 7,
-               .shift                 = 7,
+               .reg           = MO_FILTER_ODD,
+               .mask          = 7 << 7,
+               .shift         = 7,
        }, {
-               .v = {
-                       .id            = V4L2_CID_CHROMA_AGC,
-                       .name          = "Chroma AGC",
-                       .minimum       = 0,
-                       .maximum       = 1,
-                       .default_value = 0x1,
-                       .type          = V4L2_CTRL_TYPE_BOOLEAN,
-               },
-               .reg                   = MO_INPUT_FORMAT,
-               .mask                  = 1 << 10,
-               .shift                 = 10,
+               .id            = V4L2_CID_CHROMA_AGC,
+               .minimum       = 0,
+               .maximum       = 1,
+               .default_value = 0x1,
+               .reg           = MO_INPUT_FORMAT,
+               .mask          = 1 << 10,
+               .shift         = 10,
        }, {
-               .v = {
-                       .id            = V4L2_CID_COLOR_KILLER,
-                       .name          = "Color killer",
-                       .minimum       = 0,
-                       .maximum       = 1,
-                       .default_value = 0x1,
-                       .type          = V4L2_CTRL_TYPE_BOOLEAN,
-               },
-               .reg                   = MO_INPUT_FORMAT,
-               .mask                  = 1 << 9,
-               .shift                 = 9,
+               .id            = V4L2_CID_COLOR_KILLER,
+               .minimum       = 0,
+               .maximum       = 1,
+               .default_value = 0x1,
+               .reg           = MO_INPUT_FORMAT,
+               .mask          = 1 << 9,
+               .shift         = 9,
        }, {
-               .v = {
-                       .id            = V4L2_CID_BAND_STOP_FILTER,
-                       .name          = "Notch filter",
-                       .minimum       = 0,
-                       .maximum       = 1,
-                       .step          = 1,
-                       .default_value = 0x0,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .off                   = 0,
-               .reg                   = MO_HTOTAL,
-               .mask                  = 3 << 11,
-               .shift                 = 11,
-       }, {
-       /* --- audio --- */
-               .v = {
-                       .id            = V4L2_CID_AUDIO_MUTE,
-                       .name          = "Mute",
-                       .minimum       = 0,
-                       .maximum       = 1,
-                       .default_value = 1,
-                       .type          = V4L2_CTRL_TYPE_BOOLEAN,
-               },
-               .reg                   = AUD_VOL_CTL,
-               .sreg                  = SHADOW_AUD_VOL_CTL,
-               .mask                  = (1 << 6),
-               .shift                 = 6,
+               .id            = V4L2_CID_BAND_STOP_FILTER,
+               .minimum       = 0,
+               .maximum       = 1,
+               .step          = 1,
+               .default_value = 0x0,
+               .off           = 0,
+               .reg           = MO_HTOTAL,
+               .mask          = 3 << 11,
+               .shift         = 11,
+       }
+};
+
+static const struct cx88_ctrl cx8800_aud_ctls[] = {
+       {
+               /* --- audio --- */
+               .id            = V4L2_CID_AUDIO_MUTE,
+               .minimum       = 0,
+               .maximum       = 1,
+               .default_value = 1,
+               .reg           = AUD_VOL_CTL,
+               .sreg          = SHADOW_AUD_VOL_CTL,
+               .mask          = (1 << 6),
+               .shift         = 6,
        },{
-               .v = {
-                       .id            = V4L2_CID_AUDIO_VOLUME,
-                       .name          = "Volume",
-                       .minimum       = 0,
-                       .maximum       = 0x3f,
-                       .step          = 1,
-                       .default_value = 0x3f,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .reg                   = AUD_VOL_CTL,
-               .sreg                  = SHADOW_AUD_VOL_CTL,
-               .mask                  = 0x3f,
-               .shift                 = 0,
+               .id            = V4L2_CID_AUDIO_VOLUME,
+               .minimum       = 0,
+               .maximum       = 0x3f,
+               .step          = 1,
+               .default_value = 0x3f,
+               .reg           = AUD_VOL_CTL,
+               .sreg          = SHADOW_AUD_VOL_CTL,
+               .mask          = 0x3f,
+               .shift         = 0,
        },{
-               .v = {
-                       .id            = V4L2_CID_AUDIO_BALANCE,
-                       .name          = "Balance",
-                       .minimum       = 0,
-                       .maximum       = 0x7f,
-                       .step          = 1,
-                       .default_value = 0x40,
-                       .type          = V4L2_CTRL_TYPE_INTEGER,
-               },
-               .reg                   = AUD_BAL_CTL,
-               .sreg                  = SHADOW_AUD_BAL_CTL,
-               .mask                  = 0x7f,
-               .shift                 = 0,
+               .id            = V4L2_CID_AUDIO_BALANCE,
+               .minimum       = 0,
+               .maximum       = 0x7f,
+               .step          = 1,
+               .default_value = 0x40,
+               .reg           = AUD_BAL_CTL,
+               .sreg          = SHADOW_AUD_BAL_CTL,
+               .mask          = 0x7f,
+               .shift         = 0,
        }
 };
-enum { CX8800_CTLS = ARRAY_SIZE(cx8800_ctls) };
-
-/* Must be sorted from low to high control ID! */
-const u32 cx88_user_ctrls[] = {
-       V4L2_CID_USER_CLASS,
-       V4L2_CID_BRIGHTNESS,
-       V4L2_CID_CONTRAST,
-       V4L2_CID_SATURATION,
-       V4L2_CID_HUE,
-       V4L2_CID_AUDIO_VOLUME,
-       V4L2_CID_AUDIO_BALANCE,
-       V4L2_CID_AUDIO_MUTE,
-       V4L2_CID_SHARPNESS,
-       V4L2_CID_CHROMA_AGC,
-       V4L2_CID_COLOR_KILLER,
-       V4L2_CID_BAND_STOP_FILTER,
-       0
-};
-EXPORT_SYMBOL(cx88_user_ctrls);
 
-static const u32 * const ctrl_classes[] = {
-       cx88_user_ctrls,
-       NULL
+enum {
+       CX8800_VID_CTLS = ARRAY_SIZE(cx8800_vid_ctls),
+       CX8800_AUD_CTLS = ARRAY_SIZE(cx8800_aud_ctls),
 };
 
-int cx8800_ctrl_query(struct cx88_core *core, struct v4l2_queryctrl *qctrl)
-{
-       int i;
-
-       if (qctrl->id < V4L2_CID_BASE ||
-           qctrl->id >= V4L2_CID_LASTP1)
-               return -EINVAL;
-       for (i = 0; i < CX8800_CTLS; i++)
-               if (cx8800_ctls[i].v.id == qctrl->id)
-                       break;
-       if (i == CX8800_CTLS) {
-               *qctrl = no_ctl;
-               return 0;
-       }
-       *qctrl = cx8800_ctls[i].v;
-       /* Report chroma AGC as inactive when SECAM is selected */
-       if (cx8800_ctls[i].v.id == V4L2_CID_CHROMA_AGC &&
-           core->tvnorm & V4L2_STD_SECAM)
-               qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
-
-       return 0;
-}
-EXPORT_SYMBOL(cx8800_ctrl_query);
-
 /* ------------------------------------------------------------------- */
 /* resource management                                                 */
 
@@ -591,8 +520,9 @@ static int
 buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
 {
        struct cx8800_fh *fh = q->priv_data;
+       struct cx8800_dev  *dev = fh->dev;
 
-       *size = fh->fmt->depth*fh->width*fh->height >> 3;
+       *size = dev->fmt->depth * dev->width * dev->height >> 3;
        if (0 == *count)
                *count = 32;
        if (*size * *count > vid_limit * 1024 * 1024)
@@ -611,21 +541,21 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
        int rc, init_buffer = 0;
 
-       BUG_ON(NULL == fh->fmt);
-       if (fh->width  < 48 || fh->width  > norm_maxw(core->tvnorm) ||
-           fh->height < 32 || fh->height > norm_maxh(core->tvnorm))
+       BUG_ON(NULL == dev->fmt);
+       if (dev->width  < 48 || dev->width  > norm_maxw(core->tvnorm) ||
+           dev->height < 32 || dev->height > norm_maxh(core->tvnorm))
                return -EINVAL;
-       buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+       buf->vb.size = (dev->width * dev->height * dev->fmt->depth) >> 3;
        if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
                return -EINVAL;
 
-       if (buf->fmt       != fh->fmt    ||
-           buf->vb.width  != fh->width  ||
-           buf->vb.height != fh->height ||
+       if (buf->fmt       != dev->fmt    ||
+           buf->vb.width  != dev->width  ||
+           buf->vb.height != dev->height ||
            buf->vb.field  != field) {
-               buf->fmt       = fh->fmt;
-               buf->vb.width  = fh->width;
-               buf->vb.height = fh->height;
+               buf->fmt       = dev->fmt;
+               buf->vb.width  = dev->width;
+               buf->vb.height = dev->height;
                buf->vb.field  = field;
                init_buffer = 1;
        }
@@ -675,7 +605,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        }
        dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
                buf, buf->vb.i,
-               fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
+               dev->width, dev->height, dev->fmt->depth, dev->fmt->name,
                (unsigned long)buf->risc.dma);
 
        buf->vb.state = VIDEOBUF_PREPARED;
@@ -755,12 +685,15 @@ static const struct videobuf_queue_ops cx8800_video_qops = {
 
 /* ------------------------------------------------------------------ */
 
-static struct videobuf_queue* get_queue(struct cx8800_fh *fh)
+static struct videobuf_queue *get_queue(struct file *file)
 {
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       struct video_device *vdev = video_devdata(file);
+       struct cx8800_fh *fh = file->private_data;
+
+       switch (vdev->vfl_type) {
+       case VFL_TYPE_GRABBER:
                return &fh->vidq;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case VFL_TYPE_VBI:
                return &fh->vbiq;
        default:
                BUG();
@@ -768,12 +701,14 @@ static struct videobuf_queue* get_queue(struct cx8800_fh *fh)
        }
 }
 
-static int get_ressource(struct cx8800_fh *fh)
+static int get_resource(struct file *file)
 {
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       struct video_device *vdev = video_devdata(file);
+
+       switch (vdev->vfl_type) {
+       case VFL_TYPE_GRABBER:
                return RESOURCE_VIDEO;
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case VFL_TYPE_VBI:
                return RESOURCE_VBI;
        default:
                BUG();
@@ -810,13 +745,9 @@ static int video_open(struct file *file)
        if (unlikely(!fh))
                return -ENOMEM;
 
+       v4l2_fh_init(&fh->fh, vdev);
        file->private_data = fh;
        fh->dev      = dev;
-       fh->radio    = radio;
-       fh->type     = type;
-       fh->width    = 320;
-       fh->height   = 240;
-       fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
 
        mutex_lock(&core->lock);
 
@@ -833,7 +764,7 @@ static int video_open(struct file *file)
                            sizeof(struct cx88_buffer),
                            fh, NULL);
 
-       if (fh->radio) {
+       if (vdev->vfl_type == VFL_TYPE_RADIO) {
                dprintk(1,"video_open: setting radio device\n");
                cx_write(MO_GP3_IO, core->board.radio.gpio3);
                cx_write(MO_GP0_IO, core->board.radio.gpio0);
@@ -859,6 +790,7 @@ static int video_open(struct file *file)
 
        core->users++;
        mutex_unlock(&core->lock);
+       v4l2_fh_add(&fh->fh);
 
        return 0;
 }
@@ -866,15 +798,16 @@ static int video_open(struct file *file)
 static ssize_t
 video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
+       struct video_device *vdev = video_devdata(file);
        struct cx8800_fh *fh = file->private_data;
 
-       switch (fh->type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       switch (vdev->vfl_type) {
+       case VFL_TYPE_GRABBER:
                if (res_locked(fh->dev,RESOURCE_VIDEO))
                        return -EBUSY;
                return videobuf_read_one(&fh->vidq, data, count, ppos,
                                         file->f_flags & O_NONBLOCK);
-       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case VFL_TYPE_VBI:
                if (!res_get(fh->dev,fh,RESOURCE_VBI))
                        return -EBUSY;
                return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,
@@ -888,16 +821,16 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 static unsigned int
 video_poll(struct file *file, struct poll_table_struct *wait)
 {
+       struct video_device *vdev = video_devdata(file);
        struct cx8800_fh *fh = file->private_data;
        struct cx88_buffer *buf;
-       unsigned int rc = POLLERR;
+       unsigned int rc = v4l2_ctrl_poll(file, wait);
 
-       if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
+       if (vdev->vfl_type == VFL_TYPE_VBI) {
                if (!res_get(fh->dev,fh,RESOURCE_VBI))
-                       return POLLERR;
-               return videobuf_poll_stream(file, &fh->vbiq, wait);
+                       return rc | POLLERR;
+               return rc | videobuf_poll_stream(file, &fh->vbiq, wait);
        }
-
        mutex_lock(&fh->vidq.vb_lock);
        if (res_check(fh,RESOURCE_VIDEO)) {
                /* streaming capture */
@@ -913,9 +846,7 @@ video_poll(struct file *file, struct poll_table_struct *wait)
        poll_wait(file, &buf->vb.done, wait);
        if (buf->vb.state == VIDEOBUF_DONE ||
            buf->vb.state == VIDEOBUF_ERROR)
-               rc = POLLIN|POLLRDNORM;
-       else
-               rc = 0;
+               rc |= POLLIN|POLLRDNORM;
 done:
        mutex_unlock(&fh->vidq.vb_lock);
        return rc;
@@ -952,6 +883,8 @@ static int video_release(struct file *file)
        videobuf_mmap_free(&fh->vbiq);
 
        mutex_lock(&dev->core->lock);
+       v4l2_fh_del(&fh->fh);
+       v4l2_fh_exit(&fh->fh);
        file->private_data = NULL;
        kfree(fh);
 
@@ -966,156 +899,104 @@ static int video_release(struct file *file)
 static int
 video_mmap(struct file *file, struct vm_area_struct * vma)
 {
-       struct cx8800_fh *fh = file->private_data;
-
-       return videobuf_mmap_mapper(get_queue(fh), vma);
+       return videobuf_mmap_mapper(get_queue(file), vma);
 }
 
 /* ------------------------------------------------------------------ */
 /* VIDEO CTRL IOCTLS                                                  */
 
-int cx88_get_control (struct cx88_core  *core, struct v4l2_control *ctl)
+static int cx8800_s_vid_ctrl(struct v4l2_ctrl *ctrl)
 {
-       const struct cx88_ctrl  *c    = NULL;
-       u32 value;
-       int i;
+       struct cx88_core *core =
+               container_of(ctrl->handler, struct cx88_core, video_hdl);
+       const struct cx88_ctrl *cc = ctrl->priv;
+       u32 value, mask;
 
-       for (i = 0; i < CX8800_CTLS; i++)
-               if (cx8800_ctls[i].v.id == ctl->id)
-                       c = &cx8800_ctls[i];
-       if (unlikely(NULL == c))
-               return -EINVAL;
+       mask = cc->mask;
+       switch (ctrl->id) {
+       case V4L2_CID_SATURATION:
+               /* special v_sat handling */
 
-       value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg);
-       switch (ctl->id) {
-       case V4L2_CID_AUDIO_BALANCE:
-               ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40)
-                                       : (0x7f - (value & 0x7f));
-               break;
-       case V4L2_CID_AUDIO_VOLUME:
-               ctl->value = 0x3f - (value & 0x3f);
+               value = ((ctrl->val - cc->off) << cc->shift) & cc->mask;
+
+               if (core->tvnorm & V4L2_STD_SECAM) {
+                       /* For SECAM, both U and V sat should be equal */
+                       value = value << 8 | value;
+               } else {
+                       /* Keeps U Saturation proportional to V Sat */
+                       value = (value * 0x5a) / 0x7f << 8 | value;
+               }
+               mask = 0xffff;
                break;
        case V4L2_CID_SHARPNESS:
-               ctl->value = ((value & 0x0200) ? (((value & 0x0180) >> 7) + 1)
-                                                : 0);
+               /* 0b000, 0b100, 0b101, 0b110, or 0b111 */
+               value = (ctrl->val < 1 ? 0 : ((ctrl->val + 3) << 7));
+               /* needs to be set for both fields */
+               cx_andor(MO_FILTER_EVEN, mask, value);
+               break;
+       case V4L2_CID_CHROMA_AGC:
+               value = ((ctrl->val - cc->off) << cc->shift) & cc->mask;
                break;
        default:
-               ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift;
+               value = ((ctrl->val - cc->off) << cc->shift) & cc->mask;
                break;
        }
-       dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
-                               ctl->id, c->v.name, ctl->value, c->reg,
-                               value,c->mask, c->sreg ? " [shadowed]" : "");
+       dprintk(1, "set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
+                               ctrl->id, ctrl->name, ctrl->val, cc->reg, value,
+                               mask, cc->sreg ? " [shadowed]" : "");
+       if (cc->sreg)
+               cx_sandor(cc->sreg, cc->reg, mask, value);
+       else
+               cx_andor(cc->reg, mask, value);
        return 0;
 }
-EXPORT_SYMBOL(cx88_get_control);
 
-int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
+static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl)
 {
-       const struct cx88_ctrl *c = NULL;
+       struct cx88_core *core =
+               container_of(ctrl->handler, struct cx88_core, audio_hdl);
+       const struct cx88_ctrl *cc = ctrl->priv;
        u32 value,mask;
-       int i;
-
-       for (i = 0; i < CX8800_CTLS; i++) {
-               if (cx8800_ctls[i].v.id == ctl->id) {
-                       c = &cx8800_ctls[i];
-               }
-       }
-       if (unlikely(NULL == c))
-               return -EINVAL;
-
-       if (ctl->value < c->v.minimum)
-               ctl->value = c->v.minimum;
-       if (ctl->value > c->v.maximum)
-               ctl->value = c->v.maximum;
 
        /* Pass changes onto any WM8775 */
        if (core->board.audio_chip == V4L2_IDENT_WM8775) {
-               struct v4l2_control client_ctl;
-               memset(&client_ctl, 0, sizeof(client_ctl));
-               client_ctl.id = ctl->id;
-
-               switch (ctl->id) {
+               switch (ctrl->id) {
                case V4L2_CID_AUDIO_MUTE:
-                       client_ctl.value = ctl->value;
+                       wm8775_s_ctrl(core, ctrl->id, ctrl->val);
                        break;
                case V4L2_CID_AUDIO_VOLUME:
-                       client_ctl.value = (ctl->value) ?
-                               (0x90 + ctl->value) << 8 : 0;
+                       wm8775_s_ctrl(core, ctrl->id, (ctrl->val) ?
+                                               (0x90 + ctrl->val) << 8 : 0);
                        break;
                case V4L2_CID_AUDIO_BALANCE:
-                       client_ctl.value = ctl->value << 9;
+                       wm8775_s_ctrl(core, ctrl->id, ctrl->val << 9);
                        break;
                default:
-                       client_ctl.id = 0;
                        break;
                }
-               if (client_ctl.id)
-                       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
        }
 
-       mask=c->mask;
-       switch (ctl->id) {
+       mask = cc->mask;
+       switch (ctrl->id) {
        case V4L2_CID_AUDIO_BALANCE:
-               value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40);
+               value = (ctrl->val < 0x40) ? (0x7f - ctrl->val) : (ctrl->val - 0x40);
                break;
        case V4L2_CID_AUDIO_VOLUME:
-               value = 0x3f - (ctl->value & 0x3f);
-               break;
-       case V4L2_CID_SATURATION:
-               /* special v_sat handling */
-
-               value = ((ctl->value - c->off) << c->shift) & c->mask;
-
-               if (core->tvnorm & V4L2_STD_SECAM) {
-                       /* For SECAM, both U and V sat should be equal */
-                       value=value<<8|value;
-               } else {
-                       /* Keeps U Saturation proportional to V Sat */
-                       value=(value*0x5a)/0x7f<<8|value;
-               }
-               mask=0xffff;
-               break;
-       case V4L2_CID_SHARPNESS:
-               /* 0b000, 0b100, 0b101, 0b110, or 0b111 */
-               value = (ctl->value < 1 ? 0 : ((ctl->value + 3) << 7));
-               /* needs to be set for both fields */
-               cx_andor(MO_FILTER_EVEN, mask, value);
-               break;
-       case V4L2_CID_CHROMA_AGC:
-               /* Do not allow chroma AGC to be enabled for SECAM */
-               value = ((ctl->value - c->off) << c->shift) & c->mask;
-               if (core->tvnorm & V4L2_STD_SECAM && value)
-                       return -EINVAL;
+               value = 0x3f - (ctrl->val & 0x3f);
                break;
        default:
-               value = ((ctl->value - c->off) << c->shift) & c->mask;
+               value = ((ctrl->val - cc->off) << cc->shift) & cc->mask;
                break;
        }
        dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n",
-                               ctl->id, c->v.name, ctl->value, c->reg, value,
-                               mask, c->sreg ? " [shadowed]" : "");
-       if (c->sreg) {
-               cx_sandor(c->sreg, c->reg, mask, value);
-       } else {
-               cx_andor(c->reg, mask, value);
-       }
+                               ctrl->id, ctrl->name, ctrl->val, cc->reg, value,
+                               mask, cc->sreg ? " [shadowed]" : "");
+       if (cc->sreg)
+               cx_sandor(cc->sreg, cc->reg, mask, value);
+       else
+               cx_andor(cc->reg, mask, value);
        return 0;
 }
-EXPORT_SYMBOL(cx88_set_control);
-
-static void init_controls(struct cx88_core *core)
-{
-       struct v4l2_control ctrl;
-       int i;
-
-       for (i = 0; i < CX8800_CTLS; i++) {
-               ctrl.id=cx8800_ctls[i].v.id;
-               ctrl.value=cx8800_ctls[i].v.default_value;
-
-               cx88_set_control(core, &ctrl);
-       }
-}
 
 /* ------------------------------------------------------------------ */
 /* VIDEO IOCTLS                                                       */
@@ -1124,15 +1005,17 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
        struct cx8800_fh  *fh   = priv;
+       struct cx8800_dev *dev = fh->dev;
 
-       f->fmt.pix.width        = fh->width;
-       f->fmt.pix.height       = fh->height;
+       f->fmt.pix.width        = dev->width;
+       f->fmt.pix.height       = dev->height;
        f->fmt.pix.field        = fh->vidq.field;
-       f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+       f->fmt.pix.pixelformat  = dev->fmt->fourcc;
        f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * fh->fmt->depth) >> 3;
+               (f->fmt.pix.width * dev->fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
                f->fmt.pix.height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
        return 0;
 }
 
@@ -1184,33 +1067,54 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
        struct cx8800_fh  *fh   = priv;
+       struct cx8800_dev *dev = fh->dev;
        int err = vidioc_try_fmt_vid_cap (file,priv,f);
 
        if (0 != err)
                return err;
-       fh->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
-       fh->width      = f->fmt.pix.width;
-       fh->height     = f->fmt.pix.height;
+       dev->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
+       dev->width      = f->fmt.pix.width;
+       dev->height     = f->fmt.pix.height;
        fh->vidq.field = f->fmt.pix.field;
        return 0;
 }
 
-static int vidioc_querycap (struct file *file, void  *priv,
+void cx88_querycap(struct file *file, struct cx88_core *core,
+               struct v4l2_capability *cap)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       strlcpy(cap->card, core->board.name, sizeof(cap->card));
+       cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+       if (UNSET != core->board.tuner_type)
+               cap->device_caps |= V4L2_CAP_TUNER;
+       switch (vdev->vfl_type) {
+       case VFL_TYPE_RADIO:
+               cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
+               break;
+       case VFL_TYPE_GRABBER:
+               cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+               break;
+       case VFL_TYPE_VBI:
+               cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
+               break;
+       }
+       cap->capabilities = cap->device_caps | V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS;
+       if (core->board.radio.type == CX88_RADIO)
+               cap->capabilities |= V4L2_CAP_RADIO;
+}
+EXPORT_SYMBOL(cx88_querycap);
+
+static int vidioc_querycap(struct file *file, void  *priv,
                                        struct v4l2_capability *cap)
 {
        struct cx8800_dev *dev  = ((struct cx8800_fh *)priv)->dev;
        struct cx88_core  *core = dev->core;
 
        strcpy(cap->driver, "cx8800");
-       strlcpy(cap->card, core->board.name, sizeof(cap->card));
-       sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-       cap->capabilities =
-               V4L2_CAP_VIDEO_CAPTURE |
-               V4L2_CAP_READWRITE     |
-               V4L2_CAP_STREAMING     |
-               V4L2_CAP_VBI_CAPTURE;
-       if (UNSET != core->board.tuner_type)
-               cap->capabilities |= V4L2_CAP_TUNER;
+       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+       cx88_querycap(file, core, cap);
        return 0;
 }
 
@@ -1228,69 +1132,67 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void  *priv,
 
 static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
 {
-       struct cx8800_fh  *fh   = priv;
-       return (videobuf_reqbufs(get_queue(fh), p));
+       return videobuf_reqbufs(get_queue(file), p);
 }
 
 static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
 {
-       struct cx8800_fh  *fh   = priv;
-       return (videobuf_querybuf(get_queue(fh), p));
+       return videobuf_querybuf(get_queue(file), p);
 }
 
 static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
 {
-       struct cx8800_fh  *fh   = priv;
-       return (videobuf_qbuf(get_queue(fh), p));
+       return videobuf_qbuf(get_queue(file), p);
 }
 
 static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
 {
-       struct cx8800_fh  *fh   = priv;
-       return (videobuf_dqbuf(get_queue(fh), p,
-                               file->f_flags & O_NONBLOCK));
+       return videobuf_dqbuf(get_queue(file), p,
+                               file->f_flags & O_NONBLOCK);
 }
 
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
+       struct video_device *vdev = video_devdata(file);
        struct cx8800_fh  *fh   = priv;
        struct cx8800_dev *dev  = fh->dev;
 
-       /* We should remember that this driver also supports teletext,  */
-       /* so we have to test if the v4l2_buf_type is VBI capture data. */
-       if (unlikely((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
-                    (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)))
-               return -EINVAL;
-
-       if (unlikely(i != fh->type))
+       if ((vdev->vfl_type == VFL_TYPE_GRABBER && i != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+           (vdev->vfl_type == VFL_TYPE_VBI && i != V4L2_BUF_TYPE_VBI_CAPTURE))
                return -EINVAL;
 
-       if (unlikely(!res_get(dev,fh,get_ressource(fh))))
+       if (unlikely(!res_get(dev, fh, get_resource(file))))
                return -EBUSY;
-       return videobuf_streamon(get_queue(fh));
+       return videobuf_streamon(get_queue(file));
 }
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
+       struct video_device *vdev = video_devdata(file);
        struct cx8800_fh  *fh   = priv;
        struct cx8800_dev *dev  = fh->dev;
        int               err, res;
 
-       if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
-           (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
+       if ((vdev->vfl_type == VFL_TYPE_GRABBER && i != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+           (vdev->vfl_type == VFL_TYPE_VBI && i != V4L2_BUF_TYPE_VBI_CAPTURE))
                return -EINVAL;
 
-       if (i != fh->type)
-               return -EINVAL;
-
-       res = get_ressource(fh);
-       err = videobuf_streamoff(get_queue(fh));
+       res = get_resource(file);
+       err = videobuf_streamoff(get_queue(file));
        if (err < 0)
                return err;
        res_free(dev,fh,res);
        return 0;
 }
 
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
+{
+       struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+
+       *tvnorm = core->tvnorm;
+       return 0;
+}
+
 static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms)
 {
        struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
@@ -1327,8 +1229,8 @@ int cx88_enum_input (struct cx88_core  *core,struct v4l2_input *i)
        if ((CX88_VMUX_TELEVISION == INPUT(n).type) ||
            (CX88_VMUX_CABLE      == INPUT(n).type)) {
                i->type = V4L2_INPUT_TYPE_TUNER;
-               i->std = CX88_NORMS;
        }
+       i->std = CX88_NORMS;
        return 0;
 }
 EXPORT_SYMBOL(cx88_enum_input);
@@ -1354,6 +1256,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
 
        if (i >= 4)
                return -EINVAL;
+       if (0 == INPUT(i).type)
+               return -EINVAL;
 
        mutex_lock(&core->lock);
        cx88_newstation(core);
@@ -1362,35 +1266,6 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
        return 0;
 }
 
-
-
-static int vidioc_queryctrl (struct file *file, void *priv,
-                               struct v4l2_queryctrl *qctrl)
-{
-       struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
-
-       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
-       if (unlikely(qctrl->id == 0))
-               return -EINVAL;
-       return cx8800_ctrl_query(core, qctrl);
-}
-
-static int vidioc_g_ctrl (struct file *file, void *priv,
-                               struct v4l2_control *ctl)
-{
-       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
-       return
-               cx88_get_control(core,ctl);
-}
-
-static int vidioc_s_ctrl (struct file *file, void *priv,
-                               struct v4l2_control *ctl)
-{
-       struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
-       return
-               cx88_set_control(core,ctl);
-}
-
 static int vidioc_g_tuner (struct file *file, void *priv,
                                struct v4l2_tuner *t)
 {
@@ -1403,9 +1278,9 @@ static int vidioc_g_tuner (struct file *file, void *priv,
                return -EINVAL;
 
        strcpy(t->name, "Television");
-       t->type       = V4L2_TUNER_ANALOG_TV;
        t->capability = V4L2_TUNER_CAP_NORM;
        t->rangehigh  = 0xffffffffUL;
+       call_all(core, tuner, g_tuner, t);
 
        cx88_get_stereo(core ,t);
        reg = cx_read(MO_DEVICE_STATUS);
@@ -1435,9 +1310,9 @@ static int vidioc_g_frequency (struct file *file, void *priv,
 
        if (unlikely(UNSET == core->board.tuner_type))
                return -EINVAL;
+       if (f->tuner)
+               return -EINVAL;
 
-       /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
-       f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
        f->frequency = core->freq;
 
        call_all(core, tuner, g_frequency, f);
@@ -1454,9 +1329,10 @@ int cx88_set_freq (struct cx88_core  *core,
                return -EINVAL;
 
        mutex_lock(&core->lock);
-       core->freq = f->frequency;
        cx88_newstation(core);
        call_all(core, tuner, s_frequency, f);
+       call_all(core, tuner, g_frequency, f);
+       core->freq = f->frequency;
 
        /* When changing channels it is required to reset TVAUDIO */
        msleep (10);
@@ -1474,13 +1350,17 @@ static int vidioc_s_frequency (struct file *file, void *priv,
        struct cx8800_fh  *fh   = priv;
        struct cx88_core  *core = fh->dev->core;
 
-       if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
-               return -EINVAL;
-       if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
-               return -EINVAL;
+       return cx88_set_freq(core, f);
+}
 
-       return
-               cx88_set_freq (core,f);
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+                               struct v4l2_dbg_chip_ident *chip)
+{
+       if (!v4l2_chip_match_host(&chip->match))
+               return -EINVAL;
+       chip->revision = 0;
+       chip->ident = V4L2_IDENT_UNKNOWN;
+       return 0;
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1513,19 +1393,6 @@ static int vidioc_s_register (struct file *file, void *fh,
 /* RADIO ESPECIFIC IOCTLS                                      */
 /* ----------------------------------------------------------- */
 
-static int radio_querycap (struct file *file, void  *priv,
-                                       struct v4l2_capability *cap)
-{
-       struct cx8800_dev *dev  = ((struct cx8800_fh *)priv)->dev;
-       struct cx88_core  *core = dev->core;
-
-       strcpy(cap->driver, "cx8800");
-       strlcpy(cap->card, core->board.name, sizeof(cap->card));
-       sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
-       cap->capabilities = V4L2_CAP_TUNER;
-       return 0;
-}
-
 static int radio_g_tuner (struct file *file, void *priv,
                                struct v4l2_tuner *t)
 {
@@ -1535,32 +1402,11 @@ static int radio_g_tuner (struct file *file, void *priv,
                return -EINVAL;
 
        strcpy(t->name, "Radio");
-       t->type = V4L2_TUNER_RADIO;
 
        call_all(core, tuner, g_tuner, t);
        return 0;
 }
 
-static int radio_enum_input (struct file *file, void *priv,
-                               struct v4l2_input *i)
-{
-       if (i->index != 0)
-               return -EINVAL;
-       strcpy(i->name,"Radio");
-       i->type = V4L2_INPUT_TYPE_TUNER;
-
-       return 0;
-}
-
-static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
-{
-       if (unlikely(a->index))
-               return -EINVAL;
-
-       strcpy(a->name,"Radio");
-       return 0;
-}
-
 /* FIXME: Should add a standard for radio */
 
 static int radio_s_tuner (struct file *file, void *priv,
@@ -1570,46 +1416,14 @@ static int radio_s_tuner (struct file *file, void *priv,
 
        if (0 != t->index)
                return -EINVAL;
+       if (t->audmode > V4L2_TUNER_MODE_STEREO)
+               t->audmode = V4L2_TUNER_MODE_STEREO;
 
        call_all(core, tuner, s_tuner, t);
 
        return 0;
 }
 
-static int radio_s_audio (struct file *file, void *fh,
-                         struct v4l2_audio *a)
-{
-       return 0;
-}
-
-static int radio_s_input (struct file *file, void *fh, unsigned int i)
-{
-       return 0;
-}
-
-static int radio_queryctrl (struct file *file, void *priv,
-                           struct v4l2_queryctrl *c)
-{
-       int i;
-
-       if (c->id <  V4L2_CID_BASE ||
-               c->id >= V4L2_CID_LASTP1)
-               return -EINVAL;
-       if (c->id == V4L2_CID_AUDIO_MUTE ||
-               c->id == V4L2_CID_AUDIO_VOLUME ||
-               c->id == V4L2_CID_AUDIO_BALANCE) {
-               for (i = 0; i < CX8800_CTLS; i++) {
-                       if (cx8800_ctls[i].v.id == c->id)
-                               break;
-               }
-               if (i == CX8800_CTLS)
-                       return -EINVAL;
-               *c = cx8800_ctls[i].v;
-       } else
-               *c = no_ctl;
-       return 0;
-}
-
 /* ----------------------------------------------------------- */
 
 static void cx8800_vid_timeout(unsigned long data)
@@ -1752,63 +1566,89 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
-       .vidioc_g_fmt_vbi_cap     = cx8800_vbi_fmt,
-       .vidioc_try_fmt_vbi_cap   = cx8800_vbi_fmt,
-       .vidioc_s_fmt_vbi_cap     = cx8800_vbi_fmt,
        .vidioc_reqbufs       = vidioc_reqbufs,
        .vidioc_querybuf      = vidioc_querybuf,
        .vidioc_qbuf          = vidioc_qbuf,
        .vidioc_dqbuf         = vidioc_dqbuf,
+       .vidioc_g_std         = vidioc_g_std,
        .vidioc_s_std         = vidioc_s_std,
        .vidioc_enum_input    = vidioc_enum_input,
        .vidioc_g_input       = vidioc_g_input,
        .vidioc_s_input       = vidioc_s_input,
-       .vidioc_queryctrl     = vidioc_queryctrl,
-       .vidioc_g_ctrl        = vidioc_g_ctrl,
-       .vidioc_s_ctrl        = vidioc_s_ctrl,
        .vidioc_streamon      = vidioc_streamon,
        .vidioc_streamoff     = vidioc_streamoff,
        .vidioc_g_tuner       = vidioc_g_tuner,
        .vidioc_s_tuner       = vidioc_s_tuner,
        .vidioc_g_frequency   = vidioc_g_frequency,
        .vidioc_s_frequency   = vidioc_s_frequency,
+       .vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
+       .vidioc_g_chip_ident  = vidioc_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register    = vidioc_g_register,
        .vidioc_s_register    = vidioc_s_register,
 #endif
 };
 
-static struct video_device cx8800_vbi_template;
-
 static const struct video_device cx8800_video_template = {
        .name                 = "cx8800-video",
        .fops                 = &video_fops,
        .ioctl_ops            = &video_ioctl_ops,
        .tvnorms              = CX88_NORMS,
-       .current_norm         = V4L2_STD_NTSC_M,
+};
+
+static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
+       .vidioc_querycap      = vidioc_querycap,
+       .vidioc_g_fmt_vbi_cap     = cx8800_vbi_fmt,
+       .vidioc_try_fmt_vbi_cap   = cx8800_vbi_fmt,
+       .vidioc_s_fmt_vbi_cap     = cx8800_vbi_fmt,
+       .vidioc_reqbufs       = vidioc_reqbufs,
+       .vidioc_querybuf      = vidioc_querybuf,
+       .vidioc_qbuf          = vidioc_qbuf,
+       .vidioc_dqbuf         = vidioc_dqbuf,
+       .vidioc_g_std         = vidioc_g_std,
+       .vidioc_s_std         = vidioc_s_std,
+       .vidioc_enum_input    = vidioc_enum_input,
+       .vidioc_g_input       = vidioc_g_input,
+       .vidioc_s_input       = vidioc_s_input,
+       .vidioc_streamon      = vidioc_streamon,
+       .vidioc_streamoff     = vidioc_streamoff,
+       .vidioc_g_tuner       = vidioc_g_tuner,
+       .vidioc_s_tuner       = vidioc_s_tuner,
+       .vidioc_g_frequency   = vidioc_g_frequency,
+       .vidioc_s_frequency   = vidioc_s_frequency,
+       .vidioc_g_chip_ident  = vidioc_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register    = vidioc_g_register,
+       .vidioc_s_register    = vidioc_s_register,
+#endif
+};
+
+static const struct video_device cx8800_vbi_template = {
+       .name                 = "cx8800-vbi",
+       .fops                 = &video_fops,
+       .ioctl_ops            = &vbi_ioctl_ops,
+       .tvnorms              = CX88_NORMS,
 };
 
 static const struct v4l2_file_operations radio_fops =
 {
        .owner         = THIS_MODULE,
        .open          = video_open,
+       .poll          = v4l2_ctrl_poll,
        .release       = video_release,
        .unlocked_ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops radio_ioctl_ops = {
-       .vidioc_querycap      = radio_querycap,
+       .vidioc_querycap      = vidioc_querycap,
        .vidioc_g_tuner       = radio_g_tuner,
-       .vidioc_enum_input    = radio_enum_input,
-       .vidioc_g_audio       = radio_g_audio,
        .vidioc_s_tuner       = radio_s_tuner,
-       .vidioc_s_audio       = radio_s_audio,
-       .vidioc_s_input       = radio_s_input,
-       .vidioc_queryctrl     = radio_queryctrl,
-       .vidioc_g_ctrl        = vidioc_g_ctrl,
-       .vidioc_s_ctrl        = vidioc_s_ctrl,
        .vidioc_g_frequency   = vidioc_g_frequency,
        .vidioc_s_frequency   = vidioc_s_frequency,
+       .vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event    = v4l2_event_unsubscribe,
+       .vidioc_g_chip_ident  = vidioc_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register    = vidioc_g_register,
        .vidioc_s_register    = vidioc_s_register,
@@ -1821,6 +1661,14 @@ static const struct video_device cx8800_radio_template = {
        .ioctl_ops            = &radio_ioctl_ops,
 };
 
+static const struct v4l2_ctrl_ops cx8800_ctrl_vid_ops = {
+       .s_ctrl = cx8800_s_vid_ctrl,
+};
+
+static const struct v4l2_ctrl_ops cx8800_ctrl_aud_ops = {
+       .s_ctrl = cx8800_s_aud_ctrl,
+};
+
 /* ----------------------------------------------------------- */
 
 static void cx8800_unregister_video(struct cx8800_dev *dev)
@@ -1853,8 +1701,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
 {
        struct cx8800_dev *dev;
        struct cx88_core *core;
-
        int err;
+       int i;
 
        dev = kzalloc(sizeof(*dev),GFP_KERNEL);
        if (NULL == dev)
@@ -1888,14 +1736,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
                goto fail_core;
        }
 
-       /* Initialize VBI template */
-       memcpy( &cx8800_vbi_template, &cx8800_video_template,
-               sizeof(cx8800_vbi_template) );
-       strcpy(cx8800_vbi_template.name,"cx8800-vbi");
-
        /* initialize driver struct */
        spin_lock_init(&dev->slock);
-       core->tvnorm = cx8800_video_template.current_norm;
+       core->tvnorm = V4L2_STD_NTSC_M;
 
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
@@ -1925,6 +1768,35 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
        }
        cx_set(MO_PCI_INTMSK, core->pci_irqmask);
 
+       for (i = 0; i < CX8800_AUD_CTLS; i++) {
+               const struct cx88_ctrl *cc = &cx8800_aud_ctls[i];
+               struct v4l2_ctrl *vc;
+
+               vc = v4l2_ctrl_new_std(&core->audio_hdl, &cx8800_ctrl_aud_ops,
+                       cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value);
+               if (vc == NULL) {
+                       err = core->audio_hdl.error;
+                       goto fail_core;
+               }
+               vc->priv = (void *)cc;
+       }
+
+       for (i = 0; i < CX8800_VID_CTLS; i++) {
+               const struct cx88_ctrl *cc = &cx8800_vid_ctls[i];
+               struct v4l2_ctrl *vc;
+
+               vc = v4l2_ctrl_new_std(&core->video_hdl, &cx8800_ctrl_vid_ops,
+                       cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value);
+               if (vc == NULL) {
+                       err = core->video_hdl.error;
+                       goto fail_core;
+               }
+               vc->priv = (void *)cc;
+               if (vc->id == V4L2_CID_CHROMA_AGC)
+                       core->chroma_agc = vc;
+       }
+       v4l2_ctrl_add_handler(&core->video_hdl, &core->audio_hdl);
+
        /* load and configure helper modules */
 
        if (core->board.audio_chip == V4L2_IDENT_WM8775) {
@@ -1942,8 +1814,10 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
 
                sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap,
                                &wm8775_info, NULL);
-               if (sd != NULL)
+               if (sd != NULL) {
+                       core->sd_wm8775 = sd;
                        sd->grp_id = WM8775_GID;
+               }
        }
 
        if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
@@ -1971,16 +1845,22 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
        /* Sets device info at pci_dev */
        pci_set_drvdata(pci_dev, dev);
 
+       dev->width   = 320;
+       dev->height  = 240;
+       dev->fmt     = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+
        /* initial device configuration */
        mutex_lock(&core->lock);
        cx88_set_tvnorm(core, core->tvnorm);
-       init_controls(core);
+       v4l2_ctrl_handler_setup(&core->video_hdl);
+       v4l2_ctrl_handler_setup(&core->audio_hdl);
        cx88_video_mux(core, 0);
 
        /* register v4l devices */
        dev->video_dev = cx88_vdev_init(core,dev->pci,
                                        &cx8800_video_template,"video");
        video_set_drvdata(dev->video_dev, dev);
+       dev->video_dev->ctrl_handler = &core->video_hdl;
        err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
                                    video_nr[core->nr]);
        if (err < 0) {
@@ -2007,6 +1887,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
                dev->radio_dev = cx88_vdev_init(core,dev->pci,
                                                &cx8800_radio_template,"radio");
                video_set_drvdata(dev->radio_dev, dev);
+               dev->radio_dev->ctrl_handler = &core->audio_hdl;
                err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
                                            radio_nr[core->nr]);
                if (err < 0) {
index c9659def2a787d79ecfa97c5cc56ff62b4521e47..0cae0fd9e1647d50f73b4826c2a35861f71a771c 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kdev_t.h>
 
 #include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
 #include <media/tuner.h>
 #include <media/tveeprom.h>
 #include <media/videobuf-dma-sg.h>
@@ -115,15 +116,6 @@ struct cx8800_fmt {
        u32   cxformat;
 };
 
-struct cx88_ctrl {
-       struct v4l2_queryctrl  v;
-       u32                    off;
-       u32                    reg;
-       u32                    sreg;
-       u32                    mask;
-       u32                    shift;
-};
-
 /* ----------------------------------------------------------- */
 /* SRAM memory management data (see cx88-core.c)               */
 
@@ -359,6 +351,10 @@ struct cx88_core {
 
        /* config info -- analog */
        struct v4l2_device         v4l2_dev;
+       struct v4l2_ctrl_handler   video_hdl;
+       struct v4l2_ctrl           *chroma_agc;
+       struct v4l2_ctrl_handler   audio_hdl;
+       struct v4l2_subdev         *sd_wm8775;
        struct i2c_client          *i2c_rtc;
        unsigned int               boardnr;
        struct cx88_board          board;
@@ -409,8 +405,6 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
        return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
 }
 
-#define WM8775_GID     (1 << 0)
-
 #define call_hw(core, grpid, o, f, args...) \
        do {                                                    \
                if (!core->i2c_rc) {                            \
@@ -424,6 +418,36 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
 
 #define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
 
+#define WM8775_GID      (1 << 0)
+
+#define wm8775_s_ctrl(core, id, val) \
+       do {                                                                    \
+               struct v4l2_ctrl *ctrl_ =                                       \
+                       v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id);      \
+               if (ctrl_ && !core->i2c_rc) {                                   \
+                       if (core->gate_ctrl)                                    \
+                               core->gate_ctrl(core, 1);                       \
+                       v4l2_ctrl_s_ctrl(ctrl_, val);                           \
+                       if (core->gate_ctrl)                                    \
+                               core->gate_ctrl(core, 0);                       \
+               }                                                               \
+       } while (0)
+
+#define wm8775_g_ctrl(core, id) \
+       ({                                                                      \
+               struct v4l2_ctrl *ctrl_ =                                       \
+                       v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id);      \
+               s32 val = 0;                                                    \
+               if (ctrl_ && !core->i2c_rc) {                                   \
+                       if (core->gate_ctrl)                                    \
+                               core->gate_ctrl(core, 1);                       \
+                       val = v4l2_ctrl_g_ctrl(ctrl_);                          \
+                       if (core->gate_ctrl)                                    \
+                               core->gate_ctrl(core, 0);                       \
+               }                                                               \
+               val;                                                            \
+       })
+
 struct cx8800_dev;
 struct cx8802_dev;
 
@@ -431,19 +455,11 @@ struct cx8802_dev;
 /* function 0: video stuff                                     */
 
 struct cx8800_fh {
+       struct v4l2_fh             fh;
        struct cx8800_dev          *dev;
-       enum v4l2_buf_type         type;
-       int                        radio;
        unsigned int               resources;
 
-       /* video overlay */
-       struct v4l2_window         win;
-       struct v4l2_clip           *clips;
-       unsigned int               nclips;
-
        /* video capture */
-       const struct cx8800_fmt    *fmt;
-       unsigned int               width,height;
        struct videobuf_queue      vidq;
 
        /* vbi capture */
@@ -468,6 +484,8 @@ struct cx8800_dev {
        struct pci_dev             *pci;
        unsigned char              pci_rev,pci_lat;
 
+       const struct cx8800_fmt    *fmt;
+       unsigned int               width, height;
 
        /* capture queues */
        struct cx88_dmaqueue       vidq;
@@ -488,6 +506,7 @@ struct cx8800_dev {
 /* function 2: mpeg stuff                                      */
 
 struct cx8802_fh {
+       struct v4l2_fh             fh;
        struct cx8802_dev          *dev;
        struct videobuf_queue      mpegq;
 };
@@ -552,7 +571,7 @@ struct cx8802_dev {
        unsigned char              mpeg_active; /* nonzero if mpeg encoder is active */
 
        /* mpeg params */
-       struct cx2341x_mpeg_params params;
+       struct cx2341x_handler     cxhdl;
 #endif
 
 #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
@@ -722,11 +741,8 @@ void cx8802_cancel_buffers(struct cx8802_dev *dev);
 
 /* ----------------------------------------------------------- */
 /* cx88-video.c*/
-extern const u32 cx88_user_ctrls[];
-extern int cx8800_ctrl_query(struct cx88_core *core,
-                            struct v4l2_queryctrl *qctrl);
 int cx88_enum_input (struct cx88_core  *core,struct v4l2_input *i);
 int cx88_set_freq (struct cx88_core  *core,struct v4l2_frequency *f);
-int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl);
-int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl);
 int cx88_video_mux(struct cx88_core *core, unsigned int input);
+void cx88_querycap(struct file *file, struct cx88_core *core,
+               struct v4l2_capability *cap);
index d7e2a3dc5525a758fb8effc554a4b1dc1c2ee231..07dc594e79f04bea706c8cebfba1b514a8a3623e 100644 (file)
@@ -42,6 +42,7 @@
 #include <sound/initval.h>
 #include <sound/control.h>
 #include <sound/tlv.h>
+#include <sound/ac97_codec.h>
 #include <media/v4l2-common.h>
 #include "em28xx.h"
 
@@ -679,19 +680,19 @@ static int em28xx_audio_init(struct em28xx *dev)
        INIT_WORK(&dev->wq_trigger, audio_trigger);
 
        if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
-               em28xx_cvol_new(card, dev, "Video", AC97_VIDEO_VOL);
-               em28xx_cvol_new(card, dev, "Line In", AC97_LINEIN_VOL);
-               em28xx_cvol_new(card, dev, "Phone", AC97_PHONE_VOL);
-               em28xx_cvol_new(card, dev, "Microphone", AC97_PHONE_VOL);
-               em28xx_cvol_new(card, dev, "CD", AC97_CD_VOL);
-               em28xx_cvol_new(card, dev, "AUX", AC97_AUX_VOL);
-               em28xx_cvol_new(card, dev, "PCM", AC97_PCM_OUT_VOL);
-
-               em28xx_cvol_new(card, dev, "Master", AC97_MASTER_VOL);
-               em28xx_cvol_new(card, dev, "Line", AC97_LINE_LEVEL_VOL);
-               em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO_VOL);
-               em28xx_cvol_new(card, dev, "LFE", AC97_LFE_MASTER_VOL);
-               em28xx_cvol_new(card, dev, "Surround", AC97_SURR_MASTER_VOL);
+               em28xx_cvol_new(card, dev, "Video", AC97_VIDEO);
+               em28xx_cvol_new(card, dev, "Line In", AC97_LINE);
+               em28xx_cvol_new(card, dev, "Phone", AC97_PHONE);
+               em28xx_cvol_new(card, dev, "Microphone", AC97_MIC);
+               em28xx_cvol_new(card, dev, "CD", AC97_CD);
+               em28xx_cvol_new(card, dev, "AUX", AC97_AUX);
+               em28xx_cvol_new(card, dev, "PCM", AC97_PCM);
+
+               em28xx_cvol_new(card, dev, "Master", AC97_MASTER);
+               em28xx_cvol_new(card, dev, "Line", AC97_HEADPHONE);
+               em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO);
+               em28xx_cvol_new(card, dev, "LFE", AC97_CENTER_LFE_MASTER);
+               em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
        }
 
        err = snd_card_register(card);
index 862c6575c55791fa7a6f4488d7cd933226fd02cb..ca62b9981380427b587efb684d36a60f88105a21 100644 (file)
@@ -975,12 +975,7 @@ struct em28xx_board em28xx_boards[] = {
                .name         = "Terratec Cinergy HTC Stick",
                .has_dvb      = 1,
                .ir_codes     = RC_MAP_NEC_TERRATEC_CINERGY_XS,
-#if 0
-               .tuner_type   = TUNER_PHILIPS_TDA8290,
-               .tuner_addr   = 0x41,
-               .dvb_gpio     = terratec_h5_digital, /* FIXME: probably wrong */
-               .tuner_gpio   = terratec_h5_gpio,
-#endif
+               .tuner_type   = TUNER_ABSENT,
                .i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
                                EM28XX_I2C_CLK_WAIT_ENABLE |
                                EM28XX_I2C_FREQ_400_KHZ,
index 5717bdee8f1bec6f7b344563482a6c064fdba60c..de2cb20ad2cc1d676c6aa0c532e36bc251c4273e 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
+#include <sound/ac97_codec.h>
 #include <media/v4l2-common.h>
 
 #include "em28xx.h"
@@ -326,13 +327,13 @@ struct em28xx_vol_itable {
 };
 
 static struct em28xx_vol_itable inputs[] = {
-       { EM28XX_AMUX_VIDEO,    AC97_VIDEO_VOL   },
-       { EM28XX_AMUX_LINE_IN,  AC97_LINEIN_VOL  },
-       { EM28XX_AMUX_PHONE,    AC97_PHONE_VOL   },
-       { EM28XX_AMUX_MIC,      AC97_MIC_VOL     },
-       { EM28XX_AMUX_CD,       AC97_CD_VOL      },
-       { EM28XX_AMUX_AUX,      AC97_AUX_VOL     },
-       { EM28XX_AMUX_PCM_OUT,  AC97_PCM_OUT_VOL },
+       { EM28XX_AMUX_VIDEO,    AC97_VIDEO      },
+       { EM28XX_AMUX_LINE_IN,  AC97_LINE       },
+       { EM28XX_AMUX_PHONE,    AC97_PHONE      },
+       { EM28XX_AMUX_MIC,      AC97_MIC        },
+       { EM28XX_AMUX_CD,       AC97_CD         },
+       { EM28XX_AMUX_AUX,      AC97_AUX        },
+       { EM28XX_AMUX_PCM_OUT,  AC97_PCM        },
 };
 
 static int set_ac97_input(struct em28xx *dev)
@@ -415,11 +416,11 @@ struct em28xx_vol_otable {
 };
 
 static const struct em28xx_vol_otable outputs[] = {
-       { EM28XX_AOUT_MASTER, AC97_MASTER_VOL      },
-       { EM28XX_AOUT_LINE,   AC97_LINE_LEVEL_VOL  },
-       { EM28XX_AOUT_MONO,   AC97_MASTER_MONO_VOL },
-       { EM28XX_AOUT_LFE,    AC97_LFE_MASTER_VOL  },
-       { EM28XX_AOUT_SURR,   AC97_SURR_MASTER_VOL },
+       { EM28XX_AOUT_MASTER, AC97_MASTER               },
+       { EM28XX_AOUT_LINE,   AC97_HEADPHONE            },
+       { EM28XX_AOUT_MONO,   AC97_MASTER_MONO          },
+       { EM28XX_AOUT_LFE,    AC97_CENTER_LFE_MASTER    },
+       { EM28XX_AOUT_SURR,   AC97_SURROUND_MASTER      },
 };
 
 int em28xx_audio_analog_set(struct em28xx *dev)
@@ -459,9 +460,9 @@ int em28xx_audio_analog_set(struct em28xx *dev)
        if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
                int vol;
 
-               em28xx_write_ac97(dev, AC97_POWER_DOWN_CTRL, 0x4200);
-               em28xx_write_ac97(dev, AC97_EXT_AUD_CTRL, 0x0031);
-               em28xx_write_ac97(dev, AC97_PCM_IN_SRATE, 0xbb80);
+               em28xx_write_ac97(dev, AC97_POWERDOWN, 0x4200);
+               em28xx_write_ac97(dev, AC97_EXTENDED_STATUS, 0x0031);
+               em28xx_write_ac97(dev, AC97_PCM_LR_ADC_RATE, 0xbb80);
 
                /* LSB: left channel - both channels with the same level */
                vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8);
@@ -487,7 +488,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
                           channels */
                        sel |= (sel << 8);
 
-                       em28xx_write_ac97(dev, AC97_RECORD_SELECT, sel);
+                       em28xx_write_ac97(dev, AC97_REC_SEL, sel);
                }
        }
 
index 16410ac20092272b894d7aeb4e98aba6705d80f4..a16531fa937a1ec395e3490e741e0d46d0a3cccd 100644 (file)
@@ -310,31 +310,47 @@ static struct drxd_config em28xx_drxd = {
        .disable_i2c_gate_ctrl = 1,
 };
 
-struct drxk_config terratec_h5_drxk = {
+static struct drxk_config terratec_h5_drxk = {
        .adr = 0x29,
        .single_master = 1,
        .no_i2c_bridge = 1,
        .microcode_name = "dvb-usb-terratec-h5-drxk.fw",
+       .qam_demod_parameter_count = 2,
 };
 
-struct drxk_config hauppauge_930c_drxk = {
+static struct drxk_config hauppauge_930c_drxk = {
        .adr = 0x29,
        .single_master = 1,
        .no_i2c_bridge = 1,
        .microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw",
        .chunk_size = 56,
+       .qam_demod_parameter_count = 2,
 };
 
-struct drxk_config maxmedia_ub425_tc_drxk = {
+struct drxk_config terratec_htc_stick_drxk = {
        .adr = 0x29,
        .single_master = 1,
        .no_i2c_bridge = 1,
+       .microcode_name = "dvb-usb-terratec-htc-stick-drxk.fw",
+       .chunk_size = 54,
+       .qam_demod_parameter_count = 2,
+       /* Required for the antenna_gpio to disable LNA. */
+       .antenna_dvbt = true,
+       /* The windows driver uses the same. This will disable LNA. */
+       .antenna_gpio = 0x6,
 };
 
-struct drxk_config pctv_520e_drxk = {
+static struct drxk_config maxmedia_ub425_tc_drxk = {
+       .adr = 0x29,
+       .single_master = 1,
+       .no_i2c_bridge = 1,
+};
+
+static struct drxk_config pctv_520e_drxk = {
        .adr = 0x29,
        .single_master = 1,
        .microcode_name = "dvb-demod-drxk-pctv.fw",
+       .qam_demod_parameter_count = 2,
        .chunk_size = 58,
        .antenna_dvbt = true, /* disable LNA */
        .antenna_gpio = (1 << 2), /* disable LNA */
@@ -473,6 +489,57 @@ static void terratec_h5_init(struct em28xx *dev)
        em28xx_gpio_set(dev, terratec_h5_end);
 };
 
+static void terratec_htc_stick_init(struct em28xx *dev)
+{
+       int i;
+
+       /*
+        * GPIO configuration:
+        * 0xff: unknown (does not affect DVB-T).
+        * 0xf6: DRX-K (demodulator).
+        * 0xe6: unknown (does not affect DVB-T).
+        * 0xb6: unknown (does not affect DVB-T).
+        */
+       struct em28xx_reg_seq terratec_htc_stick_init[] = {
+               {EM28XX_R08_GPIO,       0xff,   0xff,   10},
+               {EM2874_R80_GPIO,       0xf6,   0xff,   100},
+               {EM2874_R80_GPIO,       0xe6,   0xff,   50},
+               {EM2874_R80_GPIO,       0xf6,   0xff,   100},
+               { -1,                   -1,     -1,     -1},
+       };
+       struct em28xx_reg_seq terratec_htc_stick_end[] = {
+               {EM2874_R80_GPIO,       0xb6,   0xff,   100},
+               {EM2874_R80_GPIO,       0xf6,   0xff,   50},
+               { -1,                   -1,     -1,     -1},
+       };
+
+       /* Init the analog decoder? */
+       struct {
+               unsigned char r[4];
+               int len;
+       } regs[] = {
+               {{ 0x06, 0x02, 0x00, 0x31 }, 4},
+               {{ 0x01, 0x02 }, 2},
+               {{ 0x01, 0x02, 0x00, 0xc6 }, 4},
+               {{ 0x01, 0x00 }, 2},
+               {{ 0x01, 0x00, 0xff, 0xaf }, 4},
+       };
+
+       em28xx_gpio_set(dev, terratec_htc_stick_init);
+
+       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+       msleep(10);
+       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
+       msleep(10);
+
+       dev->i2c_client.addr = 0x82 >> 1;
+
+       for (i = 0; i < ARRAY_SIZE(regs); i++)
+               i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+
+       em28xx_gpio_set(dev, terratec_htc_stick_end);
+};
+
 static void pctv_520e_init(struct em28xx *dev)
 {
        /*
@@ -944,7 +1011,6 @@ static int em28xx_dvb_init(struct em28xx *dev)
                break;
        }
        case EM2884_BOARD_TERRATEC_H5:
-       case EM2884_BOARD_CINERGY_HTC_STICK:
                terratec_h5_init(dev);
 
                dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap);
@@ -1021,6 +1087,25 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        }
                }
                break;
+       case EM2884_BOARD_CINERGY_HTC_STICK:
+               terratec_htc_stick_init(dev);
+
+               /* attach demodulator */
+               dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk,
+                                       &dev->i2c_adap);
+               if (!dvb->fe[0]) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+
+               /* Attach the demodulator. */
+               if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+                               &dev->i2c_adap,
+                               &em28xx_cxd2820r_tda18271_config)) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+               break;
        default:
                em28xx_errdev("/2: The frontend of your DVB/ATSC card"
                                " isn't supported yet\n");
index 185db65b766ef5b58ab2f124d3c20491e8aaceeb..1683bd9d51eed67ecaef8832832bd1eafeaa1ca5 100644 (file)
@@ -475,6 +475,7 @@ static struct i2c_client em28xx_client_template = {
  */
 static char *i2c_devs[128] = {
        [0x4a >> 1] = "saa7113h",
+       [0x52 >> 1] = "drxk",
        [0x60 >> 1] = "remote IR sensor",
        [0x8e >> 1] = "remote IR sensor",
        [0x86 >> 1] = "tda9887",
index 5e30c4f3f248ac5427caf86201eaec09f83efc02..97d36b4f19db95094bda60d549888e6e564315cf 100644 (file)
@@ -345,7 +345,7 @@ static void em28xx_ir_stop(struct rc_dev *rc)
        cancel_delayed_work_sync(&ir->work);
 }
 
-int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
+static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
 {
        int rc = 0;
        struct em28xx_IR *ir = rc_dev->priv;
index 2f626850572643a18e6f5c79d41468f893fade2e..6ff368297f6eaef94f93b26528f59bacc6010a53 100644 (file)
@@ -211,58 +211,9 @@ enum em28xx_chip_id {
 };
 
 /*
- * Registers used by em202 and other AC97 chips
+ * Registers used by em202
  */
 
-/* Standard AC97 registers */
-#define AC97_RESET               0x00
-
-       /* Output volumes */
-#define AC97_MASTER_VOL          0x02
-#define AC97_LINE_LEVEL_VOL      0x04  /* Some devices use for headphones */
-#define AC97_MASTER_MONO_VOL     0x06
-
-       /* Input volumes */
-#define AC97_PC_BEEP_VOL         0x0a
-#define AC97_PHONE_VOL           0x0c
-#define AC97_MIC_VOL             0x0e
-#define AC97_LINEIN_VOL          0x10
-#define AC97_CD_VOL              0x12
-#define AC97_VIDEO_VOL           0x14
-#define AC97_AUX_VOL             0x16
-#define AC97_PCM_OUT_VOL         0x18
-
-       /* capture registers */
-#define AC97_RECORD_SELECT       0x1a
-#define AC97_RECORD_GAIN         0x1c
-
-       /* control registers */
-#define AC97_GENERAL_PURPOSE     0x20
-#define AC97_3D_CTRL             0x22
-#define AC97_AUD_INT_AND_PAG     0x24
-#define AC97_POWER_DOWN_CTRL     0x26
-#define AC97_EXT_AUD_ID          0x28
-#define AC97_EXT_AUD_CTRL        0x2a
-
-/* Supported rate varies for each AC97 device
-   if write an unsupported value, it will return the closest one
- */
-#define AC97_PCM_OUT_FRONT_SRATE 0x2c
-#define AC97_PCM_OUT_SURR_SRATE  0x2e
-#define AC97_PCM_OUT_LFE_SRATE   0x30
-#define AC97_PCM_IN_SRATE        0x32
-
-       /* For devices with more than 2 channels, extra output volumes */
-#define AC97_LFE_MASTER_VOL      0x36
-#define AC97_SURR_MASTER_VOL     0x38
-
-       /* Digital SPDIF output control */
-#define AC97_SPDIF_OUT_CTRL      0x3a
-
-       /* Vendor ID identifier */
-#define AC97_VENDOR_ID1          0x7c
-#define AC97_VENDOR_ID2          0x7e
-
 /* EMP202 vendor registers */
 #define EM202_EXT_MODEM_CTRL     0x3e
 #define EM202_GPIO_CONF          0x4c
diff --git a/drivers/media/video/ibmmpeg2.h b/drivers/media/video/ibmmpeg2.h
deleted file mode 100644 (file)
index 68e1038..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/* ibmmpeg2.h - IBM MPEGCD21 definitions */
-
-#ifndef __IBM_MPEG2__
-#define __IBM_MPEG2__
-
-/* Define all MPEG Decoder registers */
-/* Chip Control and Status */
-#define IBM_MP2_CHIP_CONTROL   0x200*2
-#define IBM_MP2_CHIP_MODE      0x201*2
-/* Timer Control and Status */
-#define IBM_MP2_SYNC_STC2      0x202*2
-#define IBM_MP2_SYNC_STC1      0x203*2
-#define IBM_MP2_SYNC_STC0      0x204*2
-#define IBM_MP2_SYNC_PTS2      0x205*2
-#define IBM_MP2_SYNC_PTS1      0x206*2
-#define IBM_MP2_SYNC_PTS0      0x207*2
-/* Video FIFO Control */
-#define IBM_MP2_FIFO           0x208*2
-#define IBM_MP2_FIFOW          0x100*2
-#define IBM_MP2_FIFO_STAT      0x209*2
-#define IBM_MP2_RB_THRESHOLD   0x22b*2
-/* Command buffer */
-#define IBM_MP2_COMMAND                0x20a*2
-#define IBM_MP2_CMD_DATA       0x20b*2
-#define IBM_MP2_CMD_STAT       0x20c*2
-#define IBM_MP2_CMD_ADDR       0x20d*2
-/* Internal Processor Control and Status */
-#define IBM_MP2_PROC_IADDR     0x20e*2
-#define IBM_MP2_PROC_IDATA     0x20f*2
-#define IBM_MP2_WR_PROT                0x235*2
-/* DRAM Access */
-#define IBM_MP2_DRAM_ADDR      0x210*2
-#define IBM_MP2_DRAM_DATA      0x212*2
-#define IBM_MP2_DRAM_CMD_STAT  0x213*2
-#define IBM_MP2_BLOCK_SIZE     0x23b*2
-#define IBM_MP2_SRC_ADDR       0x23c*2
-/* Onscreen Display */
-#define IBM_MP2_OSD_ADDR       0x214*2
-#define IBM_MP2_OSD_DATA       0x215*2
-#define IBM_MP2_OSD_MODE       0x217*2
-#define IBM_MP2_OSD_LINK_ADDR  0x229*2
-#define IBM_MP2_OSD_SIZE       0x22a*2
-/* Interrupt Control */
-#define IBM_MP2_HOST_INT       0x218*2
-#define IBM_MP2_MASK0          0x219*2
-#define IBM_MP2_HOST_INT1      0x23e*2
-#define IBM_MP2_MASK1          0x23f*2
-/* Audio Control */
-#define IBM_MP2_AUD_IADDR      0x21a*2
-#define IBM_MP2_AUD_IDATA      0x21b*2
-#define IBM_MP2_AUD_FIFO       0x21c*2
-#define IBM_MP2_AUD_FIFOW      0x101*2
-#define IBM_MP2_AUD_CTL                0x21d*2
-#define IBM_MP2_BEEP_CTL       0x21e*2
-#define IBM_MP2_FRNT_ATTEN     0x22d*2
-/* Display Control */
-#define IBM_MP2_DISP_MODE      0x220*2
-#define IBM_MP2_DISP_DLY       0x221*2
-#define IBM_MP2_VBI_CTL                0x222*2
-#define IBM_MP2_DISP_LBOR      0x223*2
-#define IBM_MP2_DISP_TBOR      0x224*2
-/* Polarity Control */
-#define IBM_MP2_INFC_CTL       0x22c*2
-
-/* control commands */
-#define IBM_MP2_PLAY           0
-#define IBM_MP2_PAUSE          1
-#define IBM_MP2_SINGLE_FRAME   2
-#define IBM_MP2_FAST_FORWARD   3
-#define IBM_MP2_SLOW_MOTION    4
-#define IBM_MP2_IMED_NORM_PLAY 5
-#define IBM_MP2_RESET_WINDOW   6
-#define IBM_MP2_FREEZE_FRAME   7
-#define IBM_MP2_RESET_VID_RATE 8
-#define IBM_MP2_CONFIG_DECODER 9
-#define IBM_MP2_CHANNEL_SWITCH 10
-#define IBM_MP2_RESET_AUD_RATE 11
-#define IBM_MP2_PRE_OP_CHN_SW  12
-#define IBM_MP2_SET_STILL_MODE 14
-
-/* Define Xilinx FPGA Internal Registers */
-
-/* general control register 0 */
-#define XILINX_CTL0            0x600
-/* genlock delay resister 1 */
-#define XILINX_GLDELAY         0x602
-/* send 16 bits to CS3310 port */
-#define XILINX_CS3310          0x604
-/* send 16 bits to CS3310 and complete */
-#define XILINX_CS3310_CMPLT    0x60c
-/* pulse width modulator control */
-#define XILINX_PWM             0x606
-
-#endif
index f7d57b3f28429dc0efeaa49eee89f6aebb348a34..32a591062d0b0b3b59f925c496d9cc60aa6ef230 100644 (file)
@@ -1830,18 +1830,6 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
        return 0;
 }
 
-long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
-       struct video_device *vfd = video_devdata(filp);
-       long ret;
-
-       if (ivtv_debug & IVTV_DBGFLG_IOCTL)
-               vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
-       ret = video_ioctl2(filp, cmd, arg);
-       vfd->debug = 0;
-       return ret;
-}
-
 static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
        .vidioc_querycap                    = ivtv_querycap,
        .vidioc_s_audio                     = ivtv_s_audio,
index 89185caeafae0a5c72c8423d6b3ad6b242947227..7c553d16579bec13adb67a6e8361be22c56f5ac9 100644 (file)
@@ -31,6 +31,5 @@ void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std);
 void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std);
 int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
 int ivtv_s_input(struct file *file, void *fh, unsigned int inp);
-long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
 
 #endif
index 6738592aa35d6c78bd30893c421a0adbe04eea52..87990c5f0910331d9f692fa7cbd828ada8325a77 100644 (file)
@@ -50,7 +50,7 @@ static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
        .read = ivtv_v4l2_read,
        .write = ivtv_v4l2_write,
        .open = ivtv_v4l2_open,
-       .unlocked_ioctl = ivtv_v4l2_ioctl,
+       .unlocked_ioctl = video_ioctl2,
        .release = ivtv_v4l2_close,
        .poll = ivtv_v4l2_enc_poll,
 };
@@ -60,7 +60,7 @@ static const struct v4l2_file_operations ivtv_v4l2_dec_fops = {
        .read = ivtv_v4l2_read,
        .write = ivtv_v4l2_write,
        .open = ivtv_v4l2_open,
-       .unlocked_ioctl = ivtv_v4l2_ioctl,
+       .unlocked_ioctl = video_ioctl2,
        .release = ivtv_v4l2_close,
        .poll = ivtv_v4l2_dec_poll,
 };
index 302dc3d70193f9718bd6ed7bda4e9260e33338e0..dc8c2505907e73b10a337743371bbf862c771a3f 100644 (file)
@@ -1,5 +1,6 @@
 config VIDEO_M5MOLS
        tristate "Fujitsu M-5MOLS 8MP sensor support"
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       depends on MEDIA_CAMERA_SUPPORT
        ---help---
          This driver supports Fujitsu M-5MOLS camera sensor with ISP
index 3945556f573384f77fb19752ac05b4bfdba23464..f08cf38a496da83cfc4a093493d6e331ed8761fa 100644 (file)
@@ -60,6 +60,10 @@ MODULE_VERSION("0.1.1");
 #define MEM2MEM_COLOR_STEP     (0xff >> 4)
 #define MEM2MEM_NUM_TILES      8
 
+/* Flags that indicate processing mode */
+#define MEM2MEM_HFLIP  (1 << 0)
+#define MEM2MEM_VFLIP  (1 << 1)
+
 #define dprintk(dev, fmt, arg...) \
        v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
 
@@ -115,6 +119,24 @@ enum {
 
 static struct v4l2_queryctrl m2mtest_ctrls[] = {
        {
+               .id             = V4L2_CID_HFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Mirror",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+               .flags          = 0,
+       }, {
+               .id             = V4L2_CID_VFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Vertical Mirror",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+               .flags          = 0,
+       }, {
                .id             = V4L2_CID_TRANS_TIME_MSEC,
                .type           = V4L2_CTRL_TYPE_INTEGER,
                .name           = "Transaction time (msec)",
@@ -181,6 +203,9 @@ struct m2mtest_ctx {
        /* Abort requested by m2m */
        int                     aborting;
 
+       /* Processing mode */
+       int                     mode;
+
        struct v4l2_m2m_ctx     *m2m_ctx;
 
        /* Source and destination queue data */
@@ -249,19 +274,84 @@ static int device_process(struct m2mtest_ctx *ctx,
        bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES;
        w = 0;
 
-       for (y = 0; y < height; ++y) {
-               for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
-                       if (w & 0x1) {
-                               for (x = 0; x < tile_w; ++x)
-                                       *p_out++ = *p_in++ + MEM2MEM_COLOR_STEP;
-                       } else {
-                               for (x = 0; x < tile_w; ++x)
-                                       *p_out++ = *p_in++ - MEM2MEM_COLOR_STEP;
+       switch (ctx->mode) {
+       case MEM2MEM_HFLIP | MEM2MEM_VFLIP:
+               p_out += bytesperline * height - bytes_left;
+               for (y = 0; y < height; ++y) {
+                       for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+                               if (w & 0x1) {
+                                       for (x = 0; x < tile_w; ++x)
+                                               *--p_out = *p_in++ +
+                                                       MEM2MEM_COLOR_STEP;
+                               } else {
+                                       for (x = 0; x < tile_w; ++x)
+                                               *--p_out = *p_in++ -
+                                                       MEM2MEM_COLOR_STEP;
+                               }
+                               ++w;
                        }
-                       ++w;
+                       p_in += bytes_left;
+                       p_out -= bytes_left;
+               }
+               break;
+
+       case MEM2MEM_HFLIP:
+               for (y = 0; y < height; ++y) {
+                       p_out += MEM2MEM_NUM_TILES * tile_w;
+                       for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+                               if (w & 0x01) {
+                                       for (x = 0; x < tile_w; ++x)
+                                               *--p_out = *p_in++ +
+                                                       MEM2MEM_COLOR_STEP;
+                               } else {
+                                       for (x = 0; x < tile_w; ++x)
+                                               *--p_out = *p_in++ -
+                                                       MEM2MEM_COLOR_STEP;
+                               }
+                               ++w;
+                       }
+                       p_in += bytes_left;
+                       p_out += bytesperline;
+               }
+               break;
+
+       case MEM2MEM_VFLIP:
+               p_out += bytesperline * (height - 1);
+               for (y = 0; y < height; ++y) {
+                       for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+                               if (w & 0x1) {
+                                       for (x = 0; x < tile_w; ++x)
+                                               *p_out++ = *p_in++ +
+                                                       MEM2MEM_COLOR_STEP;
+                               } else {
+                                       for (x = 0; x < tile_w; ++x)
+                                               *p_out++ = *p_in++ -
+                                                       MEM2MEM_COLOR_STEP;
+                               }
+                               ++w;
+                       }
+                       p_in += bytes_left;
+                       p_out += bytes_left - 2 * bytesperline;
+               }
+               break;
+
+       default:
+               for (y = 0; y < height; ++y) {
+                       for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
+                               if (w & 0x1) {
+                                       for (x = 0; x < tile_w; ++x)
+                                               *p_out++ = *p_in++ +
+                                                       MEM2MEM_COLOR_STEP;
+                               } else {
+                                       for (x = 0; x < tile_w; ++x)
+                                               *p_out++ = *p_in++ -
+                                                       MEM2MEM_COLOR_STEP;
+                               }
+                               ++w;
+                       }
+                       p_in += bytes_left;
+                       p_out += bytes_left;
                }
-               p_in += bytes_left;
-               p_out += bytes_left;
        }
 
        return 0;
@@ -648,6 +738,14 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
        struct m2mtest_ctx *ctx = priv;
 
        switch (ctrl->id) {
+       case V4L2_CID_HFLIP:
+               ctrl->value = (ctx->mode & MEM2MEM_HFLIP) ? 1 : 0;
+               break;
+
+       case V4L2_CID_VFLIP:
+               ctrl->value = (ctx->mode & MEM2MEM_VFLIP) ? 1 : 0;
+               break;
+
        case V4L2_CID_TRANS_TIME_MSEC:
                ctrl->value = ctx->transtime;
                break;
@@ -691,6 +789,20 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
                return ret;
 
        switch (ctrl->id) {
+       case V4L2_CID_HFLIP:
+               if (ctrl->value)
+                       ctx->mode |= MEM2MEM_HFLIP;
+               else
+                       ctx->mode &= ~MEM2MEM_HFLIP;
+               break;
+
+       case V4L2_CID_VFLIP:
+               if (ctrl->value)
+                       ctx->mode |= MEM2MEM_VFLIP;
+               else
+                       ctx->mode &= ~MEM2MEM_VFLIP;
+               break;
+
        case V4L2_CID_TRANS_TIME_MSEC:
                ctx->transtime = ctrl->value;
                break;
@@ -861,6 +973,7 @@ static int m2mtest_open(struct file *file)
        ctx->translen = MEM2MEM_DEF_TRANSLEN;
        ctx->transtime = MEM2MEM_DEF_TRANSTIME;
        ctx->num_processed = 0;
+       ctx->mode = 0;
 
        ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0];
        ctx->q_data[V4L2_M2M_DST].fmt = &formats[0];
index 7e648183f15778b3db83b904b76c63c899e30899..00583f5fd26bbc26c6dcd9861ff4fcf774118597 100644 (file)
@@ -22,7 +22,7 @@
 
 /*
  * mt9m001 i2c address 0x5d
- * The platform has to define ctruct i2c_board_info objects and link to them
+ * The platform has to define struct i2c_board_info objects and link to them
  * from struct soc_camera_link
  */
 
index 3c1e626139b79e06353062e9e65c7e279e3d95a7..445359c961136cd1595e59138c3e3a3b24ee90e2 100644 (file)
@@ -688,11 +688,17 @@ static const struct v4l2_subdev_ops mt9m032_ops = {
 static int mt9m032_probe(struct i2c_client *client,
                         const struct i2c_device_id *devid)
 {
+       struct mt9m032_platform_data *pdata = client->dev.platform_data;
        struct i2c_adapter *adapter = client->adapter;
        struct mt9m032 *sensor;
        int chip_version;
        int ret;
 
+       if (pdata == NULL) {
+               dev_err(&client->dev, "No platform data\n");
+               return -EINVAL;
+       }
+
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
                dev_warn(&client->dev,
                         "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
@@ -708,7 +714,7 @@ static int mt9m032_probe(struct i2c_client *client,
 
        mutex_init(&sensor->lock);
 
-       sensor->pdata = client->dev.platform_data;
+       sensor->pdata = pdata;
 
        v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops);
        sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -738,7 +744,7 @@ static int mt9m032_probe(struct i2c_client *client,
        sensor->format.field = V4L2_FIELD_NONE;
        sensor->format.colorspace = V4L2_COLORSPACE_SRGB;
 
-       v4l2_ctrl_handler_init(&sensor->ctrls, 4);
+       v4l2_ctrl_handler_init(&sensor->ctrls, 5);
 
        v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
                          V4L2_CID_GAIN, 0, 127, 1, 64);
@@ -754,6 +760,9 @@ static int mt9m032_probe(struct i2c_client *client,
                          V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN,
                          MT9M032_SHUTTER_WIDTH_MAX, 1,
                          MT9M032_SHUTTER_WIDTH_DEF);
+       v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
+                         V4L2_CID_PIXEL_RATE, pdata->pix_clock,
+                         pdata->pix_clock, 1, pdata->pix_clock);
 
        if (sensor->ctrls.error) {
                ret = sensor->ctrls.error;
index b0c5299643290a1e417d1cf75289185ff10f3ba7..863d722dda06ebf25440c0f2fbb491c7eb3d2ce9 100644 (file)
@@ -214,7 +214,6 @@ struct mt9m111 {
        int power_count;
        const struct mt9m111_datafmt *fmt;
        int lastpage;   /* PageMap cache value */
-       unsigned char datawidth;
 };
 
 /* Find a data format by a pixel code */
index 8f061d9ac4436e0c62d05a888f75b89c4d95c669..3be537ef22d2f4138067ca9d09d48ffe65fb7cda 100644 (file)
@@ -950,7 +950,7 @@ static int mt9p031_probe(struct i2c_client *client,
        mt9p031->model = did->driver_data;
        mt9p031->reset = -1;
 
-       v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 4);
+       v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 5);
 
        v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
                          V4L2_CID_EXPOSURE, MT9P031_SHUTTER_WIDTH_MIN,
@@ -963,6 +963,9 @@ static int mt9p031_probe(struct i2c_client *client,
                          V4L2_CID_HFLIP, 0, 1, 1, 0);
        v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
                          V4L2_CID_VFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
+                         V4L2_CID_PIXEL_RATE, pdata->target_freq,
+                         pdata->target_freq, 1, pdata->target_freq);
 
        for (i = 0; i < ARRAY_SIZE(mt9p031_ctrls); ++i)
                v4l2_ctrl_new_custom(&mt9p031->ctrls, &mt9p031_ctrls[i], NULL);
index 49ca3cbfc6f12da882a47fc1352aee443a59c61b..6d343adf891d1a5497b4cb4a4ecebaaf9328d1d0 100644 (file)
@@ -691,7 +691,7 @@ static int mt9t001_video_probe(struct i2c_client *client)
                return ret;
 
        /* Configure the pixel clock polarity */
-       if (pdata && pdata->clk_pol) {
+       if (pdata->clk_pol) {
                ret  = mt9t001_write(client, MT9T001_PIXEL_CLOCK,
                                     MT9T001_PIXEL_CLOCK_INVERT);
                if (ret < 0)
@@ -715,10 +715,16 @@ static int mt9t001_video_probe(struct i2c_client *client)
 static int mt9t001_probe(struct i2c_client *client,
                         const struct i2c_device_id *did)
 {
+       struct mt9t001_platform_data *pdata = client->dev.platform_data;
        struct mt9t001 *mt9t001;
        unsigned int i;
        int ret;
 
+       if (pdata == NULL) {
+               dev_err(&client->dev, "No platform data\n");
+               return -EINVAL;
+       }
+
        if (!i2c_check_functionality(client->adapter,
                                     I2C_FUNC_SMBUS_WORD_DATA)) {
                dev_warn(&client->adapter->dev,
@@ -735,7 +741,7 @@ static int mt9t001_probe(struct i2c_client *client,
                return -ENOMEM;
 
        v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) +
-                                               ARRAY_SIZE(mt9t001_gains) + 2);
+                                               ARRAY_SIZE(mt9t001_gains) + 3);
 
        v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
                          V4L2_CID_EXPOSURE, MT9T001_SHUTTER_WIDTH_MIN,
@@ -743,6 +749,9 @@ static int mt9t001_probe(struct i2c_client *client,
                          MT9T001_SHUTTER_WIDTH_DEF);
        v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
                          V4L2_CID_BLACK_LEVEL, 1, 1, 1, 1);
+       v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops,
+                         V4L2_CID_PIXEL_RATE, pdata->ext_clk, pdata->ext_clk,
+                         1, pdata->ext_clk);
 
        for (i = 0; i < ARRAY_SIZE(mt9t001_ctrls); ++i)
                v4l2_ctrl_new_custom(&mt9t001->ctrls, &mt9t001_ctrls[i], NULL);
index bf63417adb8fa5514c7ca22b870795a107ae6e03..72479247522a8fe923235a88b342145ed0d39cf3 100644 (file)
@@ -23,7 +23,7 @@
 
 /*
  * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
- * The platform has to define ctruct i2c_board_info objects and link to them
+ * The platform has to define struct i2c_board_info objects and link to them
  * from struct soc_camera_link
  */
 
index 7e32331b60fb0e8362b7cd50ea38680a59638336..f1220d3d4970d75fb2dec5c91ce77fc2f01f7aae 100644 (file)
@@ -2014,7 +2014,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
                return -EINVAL;
 
        switch (sel->target) {
-       case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
                sel->r.left = 0;
                sel->r.top = 0;
                sel->r.width = INT_MAX;
@@ -2024,7 +2024,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
                ccdc_try_crop(ccdc, format, &sel->r);
                break;
 
-       case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+       case V4L2_SEL_TGT_CROP:
                sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
                break;
 
@@ -2052,7 +2052,7 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
        struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
+       if (sel->target != V4L2_SEL_TGT_CROP ||
            sel->pad != CCDC_PAD_SOURCE_OF)
                return -EINVAL;
 
@@ -2064,7 +2064,7 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
         * pad. If the KEEP_CONFIG flag is set, just return the current crop
         * rectangle.
         */
-       if (sel->flags & V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG) {
+       if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
                sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
                return 0;
        }
index dd91da26f1b088f66bdb40b212fa9b1c84a46b5a..53f5a703e31abd218692a679cd4b0ccf9b16d98a 100644 (file)
@@ -1949,7 +1949,7 @@ static int preview_get_selection(struct v4l2_subdev *sd,
                return -EINVAL;
 
        switch (sel->target) {
-       case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
                sel->r.left = 0;
                sel->r.top = 0;
                sel->r.width = INT_MAX;
@@ -1960,7 +1960,7 @@ static int preview_get_selection(struct v4l2_subdev *sd,
                preview_try_crop(prev, format, &sel->r);
                break;
 
-       case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+       case V4L2_SEL_TGT_CROP:
                sel->r = *__preview_get_crop(prev, fh, sel->which);
                break;
 
@@ -1988,7 +1988,7 @@ static int preview_set_selection(struct v4l2_subdev *sd,
        struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
        struct v4l2_mbus_framefmt *format;
 
-       if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
+       if (sel->target != V4L2_SEL_TGT_CROP ||
            sel->pad != PREV_PAD_SINK)
                return -EINVAL;
 
@@ -2000,7 +2000,7 @@ static int preview_set_selection(struct v4l2_subdev *sd,
         * pad. If the KEEP_CONFIG flag is set, just return the current crop
         * rectangle.
         */
-       if (sel->flags & V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG) {
+       if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
                sel->r = *__preview_get_crop(prev, fh, sel->which);
                return 0;
        }
index 14041c9c8643fdd85d9c295facd2ff54983e53d6..ae17d917f77b3657ef4553e26ea039768b9bc3e3 100644 (file)
@@ -1249,7 +1249,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
                                             sel->which);
 
        switch (sel->target) {
-       case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
                sel->r.left = 0;
                sel->r.top = 0;
                sel->r.width = INT_MAX;
@@ -1259,7 +1259,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
                resizer_calc_ratios(res, &sel->r, format_source, &ratio);
                break;
 
-       case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+       case V4L2_SEL_TGT_CROP:
                sel->r = *__resizer_get_crop(res, fh, sel->which);
                resizer_calc_ratios(res, &sel->r, format_source, &ratio);
                break;
@@ -1293,7 +1293,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
        struct v4l2_mbus_framefmt *format_sink, *format_source;
        struct resizer_ratio ratio;
 
-       if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
+       if (sel->target != V4L2_SEL_TGT_CROP ||
            sel->pad != RESZ_PAD_SINK)
                return -EINVAL;
 
index f9b6001e1dd71dba3f901badcdc120643301d3f5..25e412ecad2cf7bfb05087f2b4f6639485627690 100644 (file)
@@ -1,7 +1,6 @@
 config VIDEO_PVRUSB2
        tristate "Hauppauge WinTV-PVR USB2 support"
        depends on VIDEO_V4L2 && I2C
-       depends on VIDEO_MEDIA  # Avoids pvrusb = Y / DVB = M
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
        select VIDEO_CX2341X
index 7bddfaeeafc30a775ac5e3319b958e32fe0df8fa..f344aed32a936cdcfcfd93c45c4ae377c79bdb7d 100644 (file)
@@ -226,13 +226,11 @@ static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi)
        struct v4l2_input tmp;
        unsigned int cnt;
        int val;
-       int ret;
 
        cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
 
        memset(&tmp, 0, sizeof(tmp));
        tmp.index = vi->index;
-       ret = 0;
        if (vi->index >= fh->input_cnt)
                return -EINVAL;
        val = fh->input_map[vi->index];
@@ -556,9 +554,7 @@ static int pvr2_queryctrl(struct file *file, void *priv,
        struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
        struct pvr2_ctrl *cptr;
        int val;
-       int ret;
 
-       ret = 0;
        if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
                cptr = pvr2_hdw_get_ctrl_nextv4l(
                                hdw, (vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
@@ -705,11 +701,9 @@ static int pvr2_try_ext_ctrls(struct file *file, void *priv,
        struct v4l2_ext_control *ctrl;
        struct pvr2_ctrl *pctl;
        unsigned int idx;
-       int ret;
 
        /* For the moment just validate that the requested control
           actually exists. */
-       ret = 0;
        for (idx = 0; idx < ctls->count; idx++) {
                ctrl = ctls->controls + idx;
                pctl = pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id);
@@ -770,12 +764,10 @@ static int pvr2_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
 {
        struct pvr2_v4l2_fh *fh = file->private_data;
        struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
-       struct v4l2_cropcap cap;
        int ret;
 
        if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        ret = pvr2_ctrl_set_value(
                        pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
                        crop->c.left);
@@ -965,7 +957,7 @@ static long pvr2_v4l2_ioctl(struct file *file,
        long ret = -EINVAL;
 
        if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL)
-               v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw), cmd);
+               v4l_printk_ioctl(pvr2_hdw_get_driver_name(hdw), cmd);
 
        if (!pvr2_hdw_dev_ok(hdw)) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
@@ -998,7 +990,7 @@ static long pvr2_v4l2_ioctl(struct file *file,
                                pvr2_trace(PVR2_TRACE_V4LIOCTL,
                                           "pvr2_v4l2_do_ioctl failure, ret=%ld"
                                           " command was:", ret);
-                               v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
+                               v4l_printk_ioctl(pvr2_hdw_get_driver_name(hdw),
                                                cmd);
                        }
                }
index ec4e2ef54e6570dc77121b0a7e650a35d2eb406e..de7c7ba99ef494bd60bf9ae659c0d1e72b80608b 100644 (file)
@@ -136,19 +136,13 @@ static int leds[2] = { 100, 0 };
 
 /***/
 
-static int pwc_video_close(struct file *file);
-static ssize_t pwc_video_read(struct file *file, char __user *buf,
-                         size_t count, loff_t *ppos);
-static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
-static int  pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
-
 static const struct v4l2_file_operations pwc_fops = {
        .owner =        THIS_MODULE,
        .open =         v4l2_fh_open,
-       .release =      pwc_video_close,
-       .read =         pwc_video_read,
-       .poll =         pwc_video_poll,
-       .mmap =         pwc_video_mmap,
+       .release =      vb2_fop_release,
+       .read =         vb2_fop_read,
+       .poll =         vb2_fop_poll,
+       .mmap =         vb2_fop_mmap,
        .unlocked_ioctl = video_ioctl2,
 };
 static struct video_device pwc_template = {
@@ -562,17 +556,6 @@ static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
 /***************************************************************************/
 /* Video4Linux functions */
 
-int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file)
-{
-       if (pdev->capt_file != NULL &&
-           pdev->capt_file != file)
-               return -EBUSY;
-
-       pdev->capt_file = file;
-
-       return 0;
-}
-
 static void pwc_video_release(struct v4l2_device *v)
 {
        struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
@@ -583,113 +566,6 @@ static void pwc_video_release(struct v4l2_device *v)
        kfree(pdev);
 }
 
-static int pwc_video_close(struct file *file)
-{
-       struct pwc_device *pdev = video_drvdata(file);
-
-       /*
-        * If we're still streaming vb2_queue_release will call stream_stop
-        * so we must take both the v4l2_lock and the vb_queue_lock.
-        */
-       if (mutex_lock_interruptible(&pdev->v4l2_lock))
-               return -ERESTARTSYS;
-       if (mutex_lock_interruptible(&pdev->vb_queue_lock)) {
-               mutex_unlock(&pdev->v4l2_lock);
-               return -ERESTARTSYS;
-       }
-
-       if (pdev->capt_file == file) {
-               vb2_queue_release(&pdev->vb_queue);
-               pdev->capt_file = NULL;
-       }
-
-       mutex_unlock(&pdev->vb_queue_lock);
-       mutex_unlock(&pdev->v4l2_lock);
-
-       return v4l2_fh_release(file);
-}
-
-static ssize_t pwc_video_read(struct file *file, char __user *buf,
-                             size_t count, loff_t *ppos)
-{
-       struct pwc_device *pdev = video_drvdata(file);
-       int lock_v4l2 = 0;
-       ssize_t ret;
-
-       if (mutex_lock_interruptible(&pdev->vb_queue_lock))
-               return -ERESTARTSYS;
-
-       ret = pwc_test_n_set_capt_file(pdev, file);
-       if (ret)
-               goto out;
-
-       /* stream_start will get called so we must take the v4l2_lock */
-       if (pdev->vb_queue.fileio == NULL)
-               lock_v4l2 = 1;
-
-       /* Use try_lock, since we're taking the locks in the *wrong* order! */
-       if (lock_v4l2 && !mutex_trylock(&pdev->v4l2_lock)) {
-               ret = -ERESTARTSYS;
-               goto out;
-       }
-       ret = vb2_read(&pdev->vb_queue, buf, count, ppos,
-                      file->f_flags & O_NONBLOCK);
-       if (lock_v4l2)
-               mutex_unlock(&pdev->v4l2_lock);
-out:
-       mutex_unlock(&pdev->vb_queue_lock);
-       return ret;
-}
-
-static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
-{
-       struct pwc_device *pdev = video_drvdata(file);
-       struct vb2_queue *q = &pdev->vb_queue;
-       unsigned long req_events = poll_requested_events(wait);
-       unsigned int ret = POLL_ERR;
-       int lock_v4l2 = 0;
-
-       if (mutex_lock_interruptible(&pdev->vb_queue_lock))
-               return POLL_ERR;
-
-       /* Will this start fileio and thus call start_stream? */
-       if ((req_events & (POLLIN | POLLRDNORM)) &&
-           q->num_buffers == 0 && !q->streaming && q->fileio == NULL) {
-               if (pwc_test_n_set_capt_file(pdev, file))
-                       goto out;
-               lock_v4l2 = 1;
-       }
-
-       /* Use try_lock, since we're taking the locks in the *wrong* order! */
-       if (lock_v4l2 && !mutex_trylock(&pdev->v4l2_lock))
-               goto out;
-       ret = vb2_poll(&pdev->vb_queue, file, wait);
-       if (lock_v4l2)
-               mutex_unlock(&pdev->v4l2_lock);
-
-out:
-       if (!pdev->udev)
-               ret |= POLLHUP;
-       mutex_unlock(&pdev->vb_queue_lock);
-       return ret;
-}
-
-static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct pwc_device *pdev = video_drvdata(file);
-       int ret;
-
-       if (mutex_lock_interruptible(&pdev->vb_queue_lock))
-               return -ERESTARTSYS;
-
-       ret = pwc_test_n_set_capt_file(pdev, file);
-       if (ret == 0)
-               ret = vb2_mmap(&pdev->vb_queue, vma);
-
-       mutex_unlock(&pdev->vb_queue_lock);
-       return ret;
-}
-
 /***************************************************************************/
 /* Videobuf2 operations */
 
@@ -782,6 +658,8 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
        if (!pdev->udev)
                return -ENODEV;
 
+       if (mutex_lock_interruptible(&pdev->v4l2_lock))
+               return -ERESTARTSYS;
        /* Turn on camera and set LEDS on */
        pwc_camera_power(pdev, 1);
        pwc_set_leds(pdev, leds[0], leds[1]);
@@ -794,6 +672,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
                /* And cleanup any queued bufs!! */
                pwc_cleanup_queued_bufs(pdev);
        }
+       mutex_unlock(&pdev->v4l2_lock);
 
        return r;
 }
@@ -802,6 +681,8 @@ static int stop_streaming(struct vb2_queue *vq)
 {
        struct pwc_device *pdev = vb2_get_drv_priv(vq);
 
+       if (mutex_lock_interruptible(&pdev->v4l2_lock))
+               return -ERESTARTSYS;
        if (pdev->udev) {
                pwc_set_leds(pdev, 0, 0);
                pwc_camera_power(pdev, 0);
@@ -809,22 +690,11 @@ static int stop_streaming(struct vb2_queue *vq)
        }
 
        pwc_cleanup_queued_bufs(pdev);
+       mutex_unlock(&pdev->v4l2_lock);
 
        return 0;
 }
 
-static void wait_prepare(struct vb2_queue *vq)
-{
-       struct pwc_device *pdev = vb2_get_drv_priv(vq);
-       mutex_unlock(&pdev->vb_queue_lock);
-}
-
-static void wait_finish(struct vb2_queue *vq)
-{
-       struct pwc_device *pdev = vb2_get_drv_priv(vq);
-       mutex_lock(&pdev->vb_queue_lock);
-}
-
 static struct vb2_ops pwc_vb_queue_ops = {
        .queue_setup            = queue_setup,
        .buf_init               = buffer_init,
@@ -834,8 +704,8 @@ static struct vb2_ops pwc_vb_queue_ops = {
        .buf_queue              = buffer_queue,
        .start_streaming        = start_streaming,
        .stop_streaming         = stop_streaming,
-       .wait_prepare           = wait_prepare,
-       .wait_finish            = wait_finish,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
 };
 
 /***************************************************************************/
@@ -1136,6 +1006,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        /* Init video_device structure */
        memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
        strcpy(pdev->vdev.name, name);
+       pdev->vdev.queue = &pdev->vb_queue;
+       pdev->vdev.queue->lock = &pdev->vb_queue_lock;
        set_bit(V4L2_FL_USE_FH_PRIO, &pdev->vdev.flags);
        video_set_drvdata(&pdev->vdev, pdev);
 
@@ -1190,15 +1062,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        pdev->vdev.v4l2_dev = &pdev->v4l2_dev;
        pdev->vdev.lock = &pdev->v4l2_lock;
 
-       /*
-        * Don't take v4l2_lock for these ioctls. This improves latency if
-        * v4l2_lock is taken for a long time, e.g. when changing a control
-        * value, and a new frame is ready to be dequeued.
-        */
-       v4l2_disable_ioctl_locking(&pdev->vdev, VIDIOC_DQBUF);
-       v4l2_disable_ioctl_locking(&pdev->vdev, VIDIOC_QBUF);
-       v4l2_disable_ioctl_locking(&pdev->vdev, VIDIOC_QUERYBUF);
-
        rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1);
        if (rc < 0) {
                PWC_ERROR("Failed to register as video device (%d).\n", rc);
@@ -1253,20 +1116,18 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
        struct v4l2_device *v = usb_get_intfdata(intf);
        struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
 
-       mutex_lock(&pdev->v4l2_lock);
-
        mutex_lock(&pdev->vb_queue_lock);
+       mutex_lock(&pdev->v4l2_lock);
        /* No need to keep the urbs around after disconnection */
        if (pdev->vb_queue.streaming)
                pwc_isoc_cleanup(pdev);
        pdev->udev = NULL;
        pwc_cleanup_queued_bufs(pdev);
-       mutex_unlock(&pdev->vb_queue_lock);
 
        v4l2_device_disconnect(&pdev->v4l2_dev);
        video_unregister_device(&pdev->vdev);
-
        mutex_unlock(&pdev->v4l2_lock);
+       mutex_unlock(pdev->vb_queue.lock);
 
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
        if (pdev->button_dev)
index c691e29cc36e69fc9ad4c0525eb0aba453a38609..545e9bbdeedef22540fa079d900218d0151530b0 100644 (file)
@@ -405,6 +405,7 @@ static void pwc_vidioc_fill_fmt(struct v4l2_format *f,
        f->fmt.pix.pixelformat  = pixfmt;
        f->fmt.pix.bytesperline = f->fmt.pix.width;
        f->fmt.pix.sizeimage    = f->fmt.pix.height * f->fmt.pix.width * 3 / 2;
+       f->fmt.pix.colorspace   = V4L2_COLORSPACE_SRGB;
        PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
                        "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
                        f->fmt.pix.width,
@@ -468,17 +469,8 @@ static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
        if (ret < 0)
                return ret;
 
-       if (mutex_lock_interruptible(&pdev->vb_queue_lock))
-               return -ERESTARTSYS;
-
-       ret = pwc_test_n_set_capt_file(pdev, file);
-       if (ret)
-               goto leave;
-
-       if (pdev->vb_queue.streaming) {
-               ret = -EBUSY;
-               goto leave;
-       }
+       if (vb2_is_busy(&pdev->vb_queue))
+               return -EBUSY;
 
        pixelformat = f->fmt.pix.pixelformat;
 
@@ -496,8 +488,6 @@ static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
        PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret);
 
        pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt);
-leave:
-       mutex_unlock(&pdev->vb_queue_lock);
        return ret;
 }
 
@@ -508,10 +498,9 @@ static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap
        strcpy(cap->driver, PWC_NAME);
        strlcpy(cap->card, pdev->vdev.name, sizeof(cap->card));
        usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info));
-       cap->capabilities =
-               V4L2_CAP_VIDEO_CAPTURE  |
-               V4L2_CAP_STREAMING      |
-               V4L2_CAP_READWRITE;
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+                                       V4L2_CAP_READWRITE;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
 
@@ -520,7 +509,8 @@ static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
        if (i->index)   /* Only one INPUT is supported */
                return -EINVAL;
 
-       strcpy(i->name, "usb");
+       strlcpy(i->name, "Camera", sizeof(i->name));
+       i->type = V4L2_INPUT_TYPE_CAMERA;
        return 0;
 }
 
@@ -933,104 +923,6 @@ static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *
        return pwc_vidioc_try_fmt(pdev, f);
 }
 
-static int pwc_reqbufs(struct file *file, void *fh,
-                      struct v4l2_requestbuffers *rb)
-{
-       struct pwc_device *pdev = video_drvdata(file);
-       int ret;
-
-       if (mutex_lock_interruptible(&pdev->vb_queue_lock))
-               return -ERESTARTSYS;
-
-       ret = pwc_test_n_set_capt_file(pdev, file);
-       if (ret == 0)
-               ret = vb2_reqbufs(&pdev->vb_queue, rb);
-
-       mutex_unlock(&pdev->vb_queue_lock);
-       return ret;
-}
-
-static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
-       struct pwc_device *pdev = video_drvdata(file);
-       int ret;
-
-       if (mutex_lock_interruptible(&pdev->vb_queue_lock))
-               return -ERESTARTSYS;
-
-       ret = pwc_test_n_set_capt_file(pdev, file);
-       if (ret == 0)
-               ret = vb2_querybuf(&pdev->vb_queue, buf);
-
-       mutex_unlock(&pdev->vb_queue_lock);
-       return ret;
-}
-
-static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
-       struct pwc_device *pdev = video_drvdata(file);
-       int ret;
-
-       if (mutex_lock_interruptible(&pdev->vb_queue_lock))
-               return -ERESTARTSYS;
-
-       ret = pwc_test_n_set_capt_file(pdev, file);
-       if (ret == 0)
-               ret = vb2_qbuf(&pdev->vb_queue, buf);
-
-       mutex_unlock(&pdev->vb_queue_lock);
-       return ret;
-}
-
-static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
-       struct pwc_device *pdev = video_drvdata(file);
-       int ret;
-
-       if (mutex_lock_interruptible(&pdev->vb_queue_lock))
-               return -ERESTARTSYS;
-
-       ret = pwc_test_n_set_capt_file(pdev, file);
-       if (ret == 0)
-               ret = vb2_dqbuf(&pdev->vb_queue, buf,
-                               file->f_flags & O_NONBLOCK);
-
-       mutex_unlock(&pdev->vb_queue_lock);
-       return ret;
-}
-
-static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
-{
-       struct pwc_device *pdev = video_drvdata(file);
-       int ret;
-
-       if (mutex_lock_interruptible(&pdev->vb_queue_lock))
-               return -ERESTARTSYS;
-
-       ret = pwc_test_n_set_capt_file(pdev, file);
-       if (ret == 0)
-               ret = vb2_streamon(&pdev->vb_queue, i);
-
-       mutex_unlock(&pdev->vb_queue_lock);
-       return ret;
-}
-
-static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
-{
-       struct pwc_device *pdev = video_drvdata(file);
-       int ret;
-
-       if (mutex_lock_interruptible(&pdev->vb_queue_lock))
-               return -ERESTARTSYS;
-
-       ret = pwc_test_n_set_capt_file(pdev, file);
-       if (ret == 0)
-               ret = vb2_streamoff(&pdev->vb_queue, i);
-
-       mutex_unlock(&pdev->vb_queue_lock);
-       return ret;
-}
-
 static int pwc_enum_framesizes(struct file *file, void *fh,
                                         struct v4l2_frmsizeenum *fsize)
 {
@@ -1112,32 +1004,27 @@ static int pwc_s_parm(struct file *file, void *fh,
        int compression = 0;
        int ret, fps;
 
-       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           parm->parm.capture.timeperframe.numerator == 0)
+       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       fps = parm->parm.capture.timeperframe.denominator /
-             parm->parm.capture.timeperframe.numerator;
-
-       if (mutex_lock_interruptible(&pdev->vb_queue_lock))
-               return -ERESTARTSYS;
+       /* If timeperframe == 0, then reset the framerate to the nominal value.
+          We pick a high framerate here, and let pwc_set_video_mode() figure
+          out the best match. */
+       if (parm->parm.capture.timeperframe.numerator == 0 ||
+           parm->parm.capture.timeperframe.denominator == 0)
+               fps = 30;
+       else
+               fps = parm->parm.capture.timeperframe.denominator /
+                     parm->parm.capture.timeperframe.numerator;
 
-       ret = pwc_test_n_set_capt_file(pdev, file);
-       if (ret)
-               goto leave;
-
-       if (pdev->vb_queue.streaming) {
-               ret = -EBUSY;
-               goto leave;
-       }
+       if (vb2_is_busy(&pdev->vb_queue))
+               return -EBUSY;
 
        ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt,
                                 fps, &compression, 0);
 
        pwc_g_parm(file, fh, parm);
 
-leave:
-       mutex_unlock(&pdev->vb_queue_lock);
        return ret;
 }
 
@@ -1150,12 +1037,12 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = {
        .vidioc_g_fmt_vid_cap               = pwc_g_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap               = pwc_s_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap             = pwc_try_fmt_vid_cap,
-       .vidioc_reqbufs                     = pwc_reqbufs,
-       .vidioc_querybuf                    = pwc_querybuf,
-       .vidioc_qbuf                        = pwc_qbuf,
-       .vidioc_dqbuf                       = pwc_dqbuf,
-       .vidioc_streamon                    = pwc_streamon,
-       .vidioc_streamoff                   = pwc_streamoff,
+       .vidioc_reqbufs                     = vb2_ioctl_reqbufs,
+       .vidioc_querybuf                    = vb2_ioctl_querybuf,
+       .vidioc_qbuf                        = vb2_ioctl_qbuf,
+       .vidioc_dqbuf                       = vb2_ioctl_dqbuf,
+       .vidioc_streamon                    = vb2_ioctl_streamon,
+       .vidioc_streamoff                   = vb2_ioctl_streamoff,
        .vidioc_log_status                  = v4l2_ctrl_log_status,
        .vidioc_enum_framesizes             = pwc_enum_framesizes,
        .vidioc_enum_frameintervals         = pwc_enum_frameintervals,
index d6b5b216b9d60d873922161fa90f6a021b7110b3..7a6a0d39c2c669777d8aa7cbd61ff57de4ff865c 100644 (file)
@@ -239,7 +239,6 @@ struct pwc_device
        int features;           /* feature bits */
 
        /*** Video data ***/
-       struct file *capt_file; /* file doing video capture */
        int vendpoint;          /* video isoc endpoint */
        int vcinterface;        /* video control interface */
        int valternate;         /* alternate interface needed */
@@ -355,8 +354,6 @@ struct pwc_device
 extern int pwc_trace;
 #endif
 
-int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file);
-
 /** Functions in pwc-misc.c */
 /* sizes in pixels */
 extern const int pwc_image_sizes[PSZ_MAX][2];
index 725812aa0c3044f5ffa31190a734e75ffcc9c01b..6a34183564d217b9fd0b594cd09bfe69fab5a78c 100644 (file)
@@ -658,7 +658,7 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx,
                r->left   = r->top = 0;
                return;
        }
-       if (target == V4L2_SEL_TGT_COMPOSE_ACTIVE) {
+       if (target == V4L2_SEL_TGT_COMPOSE) {
                if (ctx->rotation != 90 && ctx->rotation != 270)
                        align_h = 1;
                max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3));
@@ -685,7 +685,7 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx,
                      rotate ? sink->f_height : sink->f_width);
        max_h = min_t(u32, FIMC_CAMIF_MAX_HEIGHT, sink->f_height);
 
-       if (target == V4L2_SEL_TGT_COMPOSE_ACTIVE) {
+       if (target == V4L2_SEL_TGT_COMPOSE) {
                min_w = min_t(u32, max_w, sink->f_width / max_sc_h);
                min_h = min_t(u32, max_h, sink->f_height / max_sc_v);
                if (rotate) {
@@ -1146,9 +1146,9 @@ static int fimc_cap_g_selection(struct file *file, void *fh,
                s->r.height = f->o_height;
                return 0;
 
-       case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+       case V4L2_SEL_TGT_COMPOSE:
                f = &ctx->d_frame;
-       case V4L2_SEL_TGT_CROP_ACTIVE:
+       case V4L2_SEL_TGT_CROP:
                s->r.left = f->offs_h;
                s->r.top = f->offs_v;
                s->r.width = f->width;
@@ -1160,7 +1160,7 @@ static int fimc_cap_g_selection(struct file *file, void *fh,
 }
 
 /* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
-int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
+static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
 {
        if (a->left < b->left || a->top < b->top)
                return 0;
@@ -1184,9 +1184,9 @@ static int fimc_cap_s_selection(struct file *file, void *fh,
        if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
                return -EINVAL;
 
-       if (s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE)
+       if (s->target == V4L2_SEL_TGT_COMPOSE)
                f = &ctx->d_frame;
-       else if (s->target == V4L2_SEL_TGT_CROP_ACTIVE)
+       else if (s->target == V4L2_SEL_TGT_CROP)
                f = &ctx->s_frame;
        else
                return -EINVAL;
@@ -1428,9 +1428,9 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
        mutex_lock(&fimc->lock);
 
        switch (sel->target) {
-       case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
                f = &ctx->d_frame;
-       case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
                r->width = f->o_width;
                r->height = f->o_height;
                r->left = 0;
@@ -1438,10 +1438,10 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
                mutex_unlock(&fimc->lock);
                return 0;
 
-       case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+       case V4L2_SEL_TGT_CROP:
                try_sel = v4l2_subdev_get_try_crop(fh, sel->pad);
                break;
-       case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+       case V4L2_SEL_TGT_COMPOSE:
                try_sel = v4l2_subdev_get_try_compose(fh, sel->pad);
                f = &ctx->d_frame;
                break;
@@ -1482,12 +1482,12 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
                return -EINVAL;
 
        mutex_lock(&fimc->lock);
-       fimc_capture_try_selection(ctx, r, V4L2_SEL_TGT_CROP_ACTIVE);
+       fimc_capture_try_selection(ctx, r, V4L2_SEL_TGT_CROP);
 
        switch (sel->target) {
-       case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
                f = &ctx->d_frame;
-       case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
                r->width = f->o_width;
                r->height = f->o_height;
                r->left = 0;
@@ -1495,10 +1495,10 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
                mutex_unlock(&fimc->lock);
                return 0;
 
-       case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+       case V4L2_SEL_TGT_CROP:
                try_sel = v4l2_subdev_get_try_crop(fh, sel->pad);
                break;
-       case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+       case V4L2_SEL_TGT_COMPOSE:
                try_sel = v4l2_subdev_get_try_compose(fh, sel->pad);
                f = &ctx->d_frame;
                break;
@@ -1514,7 +1514,7 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
                set_frame_crop(f, r->left, r->top, r->width, r->height);
                set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
                spin_unlock_irqrestore(&fimc->slock, flags);
-               if (sel->target == V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL)
+               if (sel->target == V4L2_SEL_TGT_COMPOSE)
                        ctx->state |= FIMC_COMPOSE;
        }
 
index a4646ca1d56f31fb30eb35d7cd9829fa5aa9f46a..1a445404e73d2bea57a2e788e21717a7f21fb6ac 100644 (file)
@@ -463,7 +463,7 @@ void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
            f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v);
 }
 
-int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx)
+static int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx)
 {
        struct fimc_effect *effect = &ctx->effect;
 
index 419adfb7cdf9a18d9e5ba66130127a42c8150111..f996e94873f68d3d03803997497ff4458c9166bb 100644 (file)
@@ -215,7 +215,7 @@ void flite_hw_set_camera_bus(struct fimc_lite *dev,
        flite_hw_set_camera_port(dev, s_info->mux_id);
 }
 
-void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
+static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
 {
        static const u32 pixcode[4][2] = {
                { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR },
index 74ff310db30cd6755393b5b6eaf2a933495fa0e9..c5b57e805b683d072577ddfa242ea6f9a365583c 100644 (file)
@@ -902,7 +902,7 @@ static int fimc_lite_g_selection(struct file *file, void *fh,
                sel->r.height = f->f_height;
                return 0;
 
-       case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+       case V4L2_SEL_TGT_COMPOSE:
                sel->r = f->rect;
                return 0;
        }
@@ -919,7 +919,7 @@ static int fimc_lite_s_selection(struct file *file, void *fh,
        unsigned long flags;
 
        if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
-           sel->target != V4L2_SEL_TGT_COMPOSE_ACTIVE)
+           sel->target != V4L2_SEL_TGT_COMPOSE)
                return -EINVAL;
 
        fimc_lite_try_compose(fimc, &rect);
@@ -1117,9 +1117,9 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
        struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
        struct flite_frame *f = &fimc->inp_frame;
 
-       if ((sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL &&
-            sel->target != V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS) ||
-           sel->pad != FLITE_SD_PAD_SINK)
+       if ((sel->target != V4L2_SEL_TGT_CROP &&
+            sel->target != V4L2_SEL_TGT_CROP_BOUNDS) ||
+            sel->pad != FLITE_SD_PAD_SINK)
                return -EINVAL;
 
        if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
@@ -1128,7 +1128,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
        }
 
        mutex_lock(&fimc->lock);
-       if (sel->target == V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL) {
+       if (sel->target == V4L2_SEL_TGT_CROP) {
                sel->r = f->rect;
        } else {
                sel->r.left = 0;
@@ -1153,8 +1153,7 @@ static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
        struct flite_frame *f = &fimc->inp_frame;
        int ret = 0;
 
-       if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
-           sel->pad != FLITE_SD_PAD_SINK)
+       if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != FLITE_SD_PAD_SINK)
                return -EINVAL;
 
        mutex_lock(&fimc->lock);
index 52cef4865423ef2be451df098d0c2ada3412fe21..e65bb283fd8abfede983e8146d59df6085619aea 100644 (file)
@@ -180,7 +180,7 @@ EXPORT_SYMBOL_GPL(fimc_pipeline_initialize);
  * sensor clock.
  * Called with the graph mutex held.
  */
-int __fimc_pipeline_shutdown(struct fimc_pipeline *p)
+static int __fimc_pipeline_shutdown(struct fimc_pipeline *p)
 {
        int ret = 0;
 
@@ -1010,7 +1010,7 @@ static struct platform_driver fimc_md_driver = {
        }
 };
 
-int __init fimc_md_init(void)
+static int __init fimc_md_init(void)
 {
        int ret;
 
@@ -1021,7 +1021,8 @@ int __init fimc_md_init(void)
 
        return platform_driver_register(&fimc_md_driver);
 }
-void __exit fimc_md_exit(void)
+
+static void __exit fimc_md_exit(void)
 {
        platform_driver_unregister(&fimc_md_driver);
        fimc_unregister_driver();
index 28b5225d94f588bfc5387ec62a41a6ee960eec50..95f23024b17dd447110ea7ee7606048554454a5a 100644 (file)
@@ -824,10 +824,10 @@ static int s5p_jpeg_g_selection(struct file *file, void *priv,
 
        /* For JPEG blob active == default == bounds */
        switch (s->target) {
-       case V4L2_SEL_TGT_CROP_ACTIVE:
+       case V4L2_SEL_TGT_CROP:
        case V4L2_SEL_TGT_CROP_BOUNDS:
        case V4L2_SEL_TGT_CROP_DEFAULT:
-       case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+       case V4L2_SEL_TGT_COMPOSE:
        case V4L2_SEL_TGT_COMPOSE_DEFAULT:
                s->r.width = ctx->out_q.w;
                s->r.height = ctx->out_q.h;
@@ -1503,29 +1503,7 @@ static struct platform_driver s5p_jpeg_driver = {
        },
 };
 
-static int __init
-s5p_jpeg_register(void)
-{
-       int ret;
-
-       pr_info("S5P JPEG V4L2 Driver, (c) 2011 Samsung Electronics\n");
-
-       ret = platform_driver_register(&s5p_jpeg_driver);
-
-       if (ret)
-               pr_err("%s: failed to register jpeg driver\n", __func__);
-
-       return ret;
-}
-
-static void __exit
-s5p_jpeg_unregister(void)
-{
-       platform_driver_unregister(&s5p_jpeg_driver);
-}
-
-module_init(s5p_jpeg_register);
-module_exit(s5p_jpeg_unregister);
+module_platform_driver(s5p_jpeg_driver);
 
 MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
 MODULE_DESCRIPTION("Samsung JPEG codec driver");
index 33fde2a763ecf57da6549ffdd24900f97fc1e710..6c74b05d1f95382e691feb48f863e96b175d1a4b 100644 (file)
@@ -367,7 +367,7 @@ static int mxr_g_selection(struct file *file, void *fh,
                return -EINVAL;
 
        switch (s->target) {
-       case V4L2_SEL_TGT_CROP_ACTIVE:
+       case V4L2_SEL_TGT_CROP:
                s->r.left = geo->src.x_offset;
                s->r.top = geo->src.y_offset;
                s->r.width = geo->src.width;
@@ -380,7 +380,7 @@ static int mxr_g_selection(struct file *file, void *fh,
                s->r.width = geo->src.full_width;
                s->r.height = geo->src.full_height;
                break;
-       case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+       case V4L2_SEL_TGT_COMPOSE:
        case V4L2_SEL_TGT_COMPOSE_PADDED:
                s->r.left = geo->dst.x_offset;
                s->r.top = geo->dst.y_offset;
@@ -449,11 +449,11 @@ static int mxr_s_selection(struct file *file, void *fh,
                res.height = geo->dst.full_height;
                break;
 
-       case V4L2_SEL_TGT_CROP_ACTIVE:
+       case V4L2_SEL_TGT_CROP:
                target = &geo->src;
                stage = MXR_GEOMETRY_CROP;
                break;
-       case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+       case V4L2_SEL_TGT_COMPOSE:
        case V4L2_SEL_TGT_COMPOSE_PADDED:
                target = &geo->dst;
                stage = MXR_GEOMETRY_COMPOSE;
index 0f31eccd7b80e462c678368047294f8c8027f24a..6d348f90237af244c6d4436d7f094ba2d973dab3 100644 (file)
@@ -419,14 +419,4 @@ static struct i2c_driver sii9234_driver = {
        .id_table = sii9234_id,
 };
 
-static int __init sii9234_init(void)
-{
-       return i2c_add_driver(&sii9234_driver);
-}
-module_init(sii9234_init);
-
-static void __exit sii9234_exit(void)
-{
-       i2c_del_driver(&sii9234_driver);
-}
-module_exit(sii9234_exit);
+module_i2c_driver(sii9234_driver);
diff --git a/drivers/media/video/saa7121.h b/drivers/media/video/saa7121.h
deleted file mode 100644 (file)
index 66967ae..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/* saa7121.h - saa7121 initializations
-   Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-#ifndef __SAA7121_H__
-#define __SAA7121_H__
-
-#define NTSC_BURST_START       0x19    /* 28 */
-#define NTSC_BURST_END         0x1d    /* 29 */
-#define NTSC_CHROMA_PHASE      0x67    /* 5a */
-#define NTSC_GAINU             0x76    /* 5b */
-#define NTSC_GAINV             0xa5    /* 5c */
-#define NTSC_BLACK_LEVEL       0x2a    /* 5d */
-#define NTSC_BLANKING_LEVEL    0x2e    /* 5e */
-#define NTSC_VBI_BLANKING      0x2e    /* 5f */
-#define NTSC_DAC_CONTROL       0x11    /* 61 */
-#define NTSC_BURST_AMP         0x3f    /* 62 */
-#define NTSC_SUBC3             0x1f    /* 63 */
-#define NTSC_SUBC2             0x7c    /* 64 */
-#define NTSC_SUBC1             0xf0    /* 65 */
-#define NTSC_SUBC0             0x21    /* 66 */
-#define NTSC_HTRIG             0x72    /* 6c */
-#define NTSC_VTRIG             0x00    /* 6c */
-#define NTSC_MULTI             0x30    /* 6e */
-#define NTSC_CCTTX             0x11    /* 6f */
-#define NTSC_FIRST_ACTIVE      0x12    /* 7a */
-#define NTSC_LAST_ACTIVE       0x02    /* 7b */
-#define NTSC_MSB_VERTICAL      0x40    /* 7c */
-
-#define PAL_BURST_START                0x21    /* 28 */
-#define PAL_BURST_END          0x1d    /* 29 */
-#define PAL_CHROMA_PHASE       0x3f    /* 5a */
-#define PAL_GAINU              0x7d    /* 5b */
-#define PAL_GAINV              0xaf    /* 5c */
-#define PAL_BLACK_LEVEL                0x23    /* 5d */
-#define PAL_BLANKING_LEVEL     0x35    /* 5e */
-#define PAL_VBI_BLANKING       0x35    /* 5f */
-#define PAL_DAC_CONTROL                0x02    /* 61 */
-#define PAL_BURST_AMP          0x2f    /* 62 */
-#define PAL_SUBC3              0xcb    /* 63 */
-#define PAL_SUBC2              0x8a    /* 64 */
-#define PAL_SUBC1              0x09    /* 65 */
-#define PAL_SUBC0              0x2a    /* 66 */
-#define PAL_HTRIG              0x86    /* 6c */
-#define PAL_VTRIG              0x04    /* 6d */
-#define PAL_MULTI              0x20    /* 6e */
-#define PAL_CCTTX              0x15    /* 6f */
-#define PAL_FIRST_ACTIVE       0x16    /* 7a */
-#define PAL_LAST_ACTIVE                0x36    /* 7b */
-#define PAL_MSB_VERTICAL       0x40    /* 7c */
-
-/* Initialization Sequence */
-
-static __u8 init7121ntsc[] = {
-       0x26, 0x0,      0x27, 0x0,
-       0x28, NTSC_BURST_START,         0x29, NTSC_BURST_END,
-       0x2a, 0x0,      0x2b, 0x0,      0x2c, 0x0,      0x2d, 0x0,
-       0x2e, 0x0,      0x2f, 0x0,      0x30, 0x0,      0x31, 0x0,
-       0x32, 0x0,      0x33, 0x0,      0x34, 0x0,      0x35, 0x0,
-       0x36, 0x0,      0x37, 0x0,      0x38, 0x0,      0x39, 0x0,
-       0x3a, 0x03,     0x3b, 0x0,      0x3c, 0x0,      0x3d, 0x0,
-       0x3e, 0x0,      0x3f, 0x0,      0x40, 0x0,      0x41, 0x0,
-       0x42, 0x0,      0x43, 0x0,      0x44, 0x0,      0x45, 0x0,
-       0x46, 0x0,      0x47, 0x0,      0x48, 0x0,      0x49, 0x0,
-       0x4a, 0x0,      0x4b, 0x0,      0x4c, 0x0,      0x4d, 0x0,
-       0x4e, 0x0,      0x4f, 0x0,      0x50, 0x0,      0x51, 0x0,
-       0x52, 0x0,      0x53, 0x0,      0x54, 0x0,      0x55, 0x0,
-       0x56, 0x0,      0x57, 0x0,      0x58, 0x0,      0x59, 0x0,
-       0x5a, NTSC_CHROMA_PHASE,        0x5b, NTSC_GAINU,
-       0x5c, NTSC_GAINV,               0x5d, NTSC_BLACK_LEVEL,
-       0x5e, NTSC_BLANKING_LEVEL,      0x5f, NTSC_VBI_BLANKING,
-       0x60, 0x0,                      0x61, NTSC_DAC_CONTROL,
-       0x62, NTSC_BURST_AMP,           0x63, NTSC_SUBC3,
-       0x64, NTSC_SUBC2,               0x65, NTSC_SUBC1,
-       0x66, NTSC_SUBC0,               0x67, 0x80,     0x68, 0x80,
-       0x69, 0x80,     0x6a, 0x80,     0x6b, 0x29,
-       0x6c, NTSC_HTRIG,               0x6d, NTSC_VTRIG,
-       0x6e, NTSC_MULTI,               0x6f, NTSC_CCTTX,
-       0x70, 0xc9,     0x71, 0x68,     0x72, 0x60,     0x73, 0x0,
-       0x74, 0x0,      0x75, 0x0,      0x76, 0x0,      0x77, 0x0,
-       0x78, 0x0,      0x79, 0x0,      0x7a, NTSC_FIRST_ACTIVE,
-       0x7b, NTSC_LAST_ACTIVE,         0x7c, NTSC_MSB_VERTICAL,
-       0x7d, 0x0,      0x7e, 0x0,      0x7f, 0x0
-};
-#define INIT7121LEN    (sizeof(init7121ntsc)/2)
-
-static __u8 init7121pal[] = {
-       0x26, 0x0,      0x27, 0x0,
-       0x28, PAL_BURST_START,          0x29, PAL_BURST_END,
-       0x2a, 0x0,      0x2b, 0x0,      0x2c, 0x0,      0x2d, 0x0,
-       0x2e, 0x0,      0x2f, 0x0,      0x30, 0x0,      0x31, 0x0,
-       0x32, 0x0,      0x33, 0x0,      0x34, 0x0,      0x35, 0x0,
-       0x36, 0x0,      0x37, 0x0,      0x38, 0x0,      0x39, 0x0,
-       0x3a, 0x03,     0x3b, 0x0,      0x3c, 0x0,      0x3d, 0x0,
-       0x3e, 0x0,      0x3f, 0x0,      0x40, 0x0,      0x41, 0x0,
-       0x42, 0x0,      0x43, 0x0,      0x44, 0x0,      0x45, 0x0,
-       0x46, 0x0,      0x47, 0x0,      0x48, 0x0,      0x49, 0x0,
-       0x4a, 0x0,      0x4b, 0x0,      0x4c, 0x0,      0x4d, 0x0,
-       0x4e, 0x0,      0x4f, 0x0,      0x50, 0x0,      0x51, 0x0,
-       0x52, 0x0,      0x53, 0x0,      0x54, 0x0,      0x55, 0x0,
-       0x56, 0x0,      0x57, 0x0,      0x58, 0x0,      0x59, 0x0,
-       0x5a, PAL_CHROMA_PHASE,         0x5b, PAL_GAINU,
-       0x5c, PAL_GAINV,                0x5d, PAL_BLACK_LEVEL,
-       0x5e, PAL_BLANKING_LEVEL,       0x5f, PAL_VBI_BLANKING,
-       0x60, 0x0,                      0x61, PAL_DAC_CONTROL,
-       0x62, PAL_BURST_AMP,            0x63, PAL_SUBC3,
-       0x64, PAL_SUBC2,                0x65, PAL_SUBC1,
-       0x66, PAL_SUBC0,                0x67, 0x80,     0x68, 0x80,
-       0x69, 0x80,     0x6a, 0x80,     0x6b, 0x29,
-       0x6c, PAL_HTRIG,                0x6d, PAL_VTRIG,
-       0x6e, PAL_MULTI,                0x6f, PAL_CCTTX,
-       0x70, 0xc9,     0x71, 0x68,     0x72, 0x60,     0x73, 0x0,
-       0x74, 0x0,      0x75, 0x0,      0x76, 0x0,      0x77, 0x0,
-       0x78, 0x0,      0x79, 0x0,      0x7a, PAL_FIRST_ACTIVE,
-       0x7b, PAL_LAST_ACTIVE,          0x7c, PAL_MSB_VERTICAL,
-       0x7d, 0x0,      0x7e, 0x0,      0x7f, 0x0
-};
-#endif
index 5dfd826d734e82cffb9c791b790b5c9d8d373a36..cc7f3d6ee966f955cbaac74dfa3670d453e7c963 100644 (file)
@@ -1282,7 +1282,7 @@ static int dvb_init(struct saa7134_dev *dev)
        case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
                if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
                                         &tda827x_cfg_0) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_PHILIPS_EUROPA:
        case SAA7134_BOARD_VIDEOMATE_DVBT_300:
@@ -1322,7 +1322,7 @@ static int dvb_init(struct saa7134_dev *dev)
        case SAA7134_BOARD_KWORLD_DVBT_210:
                if (configure_tda827x_fe(dev, &kworld_dvb_t_210_config,
                                         &tda827x_cfg_2) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_HAUPPAUGE_HVR1120:
                fe0->dvb.frontend = dvb_attach(tda10048_attach,
@@ -1340,17 +1340,17 @@ static int dvb_init(struct saa7134_dev *dev)
        case SAA7134_BOARD_PHILIPS_TIGER:
                if (configure_tda827x_fe(dev, &philips_tiger_config,
                                         &tda827x_cfg_0) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_PINNACLE_PCTV_310i:
                if (configure_tda827x_fe(dev, &pinnacle_pctv_310i_config,
                                         &tda827x_cfg_1) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_HAUPPAUGE_HVR1110:
                if (configure_tda827x_fe(dev, &hauppauge_hvr_1110_config,
                                         &tda827x_cfg_1) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_HAUPPAUGE_HVR1150:
                fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
@@ -1368,30 +1368,30 @@ static int dvb_init(struct saa7134_dev *dev)
        case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
                if (configure_tda827x_fe(dev, &asus_p7131_dual_config,
                                         &tda827x_cfg_0) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_FLYDVBT_LR301:
                if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
                                         &tda827x_cfg_0) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_FLYDVB_TRIO:
                if (!use_frontend) {    /* terrestrial */
                        if (configure_tda827x_fe(dev, &lifeview_trio_config,
                                                 &tda827x_cfg_0) < 0)
-                               goto dettach_frontend;
+                               goto detach_frontend;
                } else {                /* satellite */
                        fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
                        if (fe0->dvb.frontend) {
                                if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63,
                                                                        &dev->i2c_adap, 0) == NULL) {
                                        wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
-                                       goto dettach_frontend;
+                                       goto detach_frontend;
                                }
                                if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap,
                                                                                0x08, 0, 0) == NULL) {
                                        wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
-                                       goto dettach_frontend;
+                                       goto detach_frontend;
                                }
                        }
                }
@@ -1407,7 +1407,7 @@ static int dvb_init(struct saa7134_dev *dev)
                                                                &ads_duo_cfg) == NULL) {
                                wprintk("no tda827x tuner found at addr: %02x\n",
                                        ads_tech_duo_config.tuner_address);
-                               goto dettach_frontend;
+                               goto detach_frontend;
                        }
                } else
                        wprintk("failed to attach tda10046\n");
@@ -1415,13 +1415,13 @@ static int dvb_init(struct saa7134_dev *dev)
        case SAA7134_BOARD_TEVION_DVBT_220RF:
                if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config,
                                         &tda827x_cfg_0) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_MEDION_MD8800_QUADRO:
                if (!use_frontend) {     /* terrestrial */
                        if (configure_tda827x_fe(dev, &md8800_dvbt_config,
                                                 &tda827x_cfg_0) < 0)
-                               goto dettach_frontend;
+                               goto detach_frontend;
                } else {        /* satellite */
                        fe0->dvb.frontend = dvb_attach(tda10086_attach,
                                                        &flydvbs, &dev->i2c_adap);
@@ -1435,7 +1435,7 @@ static int dvb_init(struct saa7134_dev *dev)
                                                0x60, &dev->i2c_adap, 0) == NULL) {
                                        wprintk("%s: Medion Quadro, no tda826x "
                                                "found !\n", __func__);
-                                       goto dettach_frontend;
+                                       goto detach_frontend;
                                }
                                if (dev_id != 0x08) {
                                        /* we need to open the i2c gate (we know it exists) */
@@ -1444,7 +1444,7 @@ static int dvb_init(struct saa7134_dev *dev)
                                                        &dev->i2c_adap, 0x08, 0, 0) == NULL) {
                                                wprintk("%s: Medion Quadro, no ISL6405 "
                                                        "found !\n", __func__);
-                                               goto dettach_frontend;
+                                               goto detach_frontend;
                                        }
                                        if (dev_id == 0x07) {
                                                /* fire up the 2nd section of the LNB supply since
@@ -1503,12 +1503,12 @@ static int dvb_init(struct saa7134_dev *dev)
                        if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
                                       &dev->i2c_adap, 0) == NULL) {
                                wprintk("%s: No tda826x found!\n", __func__);
-                               goto dettach_frontend;
+                               goto detach_frontend;
                        }
                        if (dvb_attach(isl6421_attach, fe0->dvb.frontend,
                                       &dev->i2c_adap, 0x08, 0, 0) == NULL) {
                                wprintk("%s: No ISL6421 found!\n", __func__);
-                               goto dettach_frontend;
+                               goto detach_frontend;
                        }
                }
                break;
@@ -1537,37 +1537,37 @@ static int dvb_init(struct saa7134_dev *dev)
        case SAA7134_BOARD_CINERGY_HT_PCMCIA:
                if (configure_tda827x_fe(dev, &cinergy_ht_config,
                                         &tda827x_cfg_0) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_CINERGY_HT_PCI:
                if (configure_tda827x_fe(dev, &cinergy_ht_pci_config,
                                         &tda827x_cfg_0) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_PHILIPS_TIGER_S:
                if (configure_tda827x_fe(dev, &philips_tiger_s_config,
                                         &tda827x_cfg_2) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_ASUS_P7131_4871:
                if (configure_tda827x_fe(dev, &asus_p7131_4871_config,
                                         &tda827x_cfg_2) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
                if (configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config,
                                         &tda827x_cfg_2) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_AVERMEDIA_SUPER_007:
                if (configure_tda827x_fe(dev, &avermedia_super_007_config,
                                         &tda827x_cfg_0) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
                if (configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config,
                                         &tda827x_cfg_2_sw42) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_PHILIPS_SNAKE:
                fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
@@ -1576,24 +1576,24 @@ static int dvb_init(struct saa7134_dev *dev)
                        if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
                                        &dev->i2c_adap, 0) == NULL) {
                                wprintk("%s: No tda826x found!\n", __func__);
-                               goto dettach_frontend;
+                               goto detach_frontend;
                        }
                        if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
                                        &dev->i2c_adap, 0, 0) == NULL) {
                                wprintk("%s: No lnbp21 found!\n", __func__);
-                               goto dettach_frontend;
+                               goto detach_frontend;
                        }
                }
                break;
        case SAA7134_BOARD_CREATIX_CTX953:
                if (configure_tda827x_fe(dev, &md8800_dvbt_config,
                                         &tda827x_cfg_0) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_MSI_TVANYWHERE_AD11:
                if (configure_tda827x_fe(dev, &philips_tiger_s_config,
                                         &tda827x_cfg_2) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
                dprintk("AverMedia E506R dvb setup\n");
@@ -1614,7 +1614,7 @@ static int dvb_init(struct saa7134_dev *dev)
                                  &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) {
                                wprintk("%s: MD7134 DVB-S, no SD1878 "
                                        "found !\n", __func__);
-                               goto dettach_frontend;
+                               goto detach_frontend;
                        }
                        /* we need to open the i2c gate (we know it exists) */
                        fe = fe0->dvb.frontend;
@@ -1623,7 +1623,7 @@ static int dvb_init(struct saa7134_dev *dev)
                                        &dev->i2c_adap, 0x08, 0, 0) == NULL) {
                                wprintk("%s: MD7134 DVB-S, no ISL6405 "
                                        "found !\n", __func__);
-                               goto dettach_frontend;
+                               goto detach_frontend;
                        }
                        fe->ops.i2c_gate_ctrl(fe, 0);
                        dev->original_set_voltage = fe->ops.set_voltage;
@@ -1645,7 +1645,7 @@ static int dvb_init(struct saa7134_dev *dev)
                if (!use_frontend) {     /* terrestrial */
                        if (configure_tda827x_fe(dev, &asus_tiger_3in1_config,
                                                        &tda827x_cfg_2) < 0)
-                               goto dettach_frontend;
+                               goto detach_frontend;
                } else {                /* satellite */
                        fe0->dvb.frontend = dvb_attach(tda10086_attach,
                                                &flydvbs, &dev->i2c_adap);
@@ -1655,13 +1655,13 @@ static int dvb_init(struct saa7134_dev *dev)
                                                &dev->i2c_adap, 0) == NULL) {
                                        wprintk("%s: Asus Tiger 3in1, no "
                                                "tda826x found!\n", __func__);
-                                       goto dettach_frontend;
+                                       goto detach_frontend;
                                }
                                if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
                                                &dev->i2c_adap, 0, 0) == NULL) {
                                        wprintk("%s: Asus Tiger 3in1, no lnbp21"
                                                " found!\n", __func__);
-                                      goto dettach_frontend;
+                                      goto detach_frontend;
                               }
                       }
               }
@@ -1670,7 +1670,7 @@ static int dvb_init(struct saa7134_dev *dev)
                if (!use_frontend) {     /* terrestrial */
                        if (configure_tda827x_fe(dev, &asus_ps3_100_config,
                                                 &tda827x_cfg_2) < 0)
-                               goto dettach_frontend;
+                               goto detach_frontend;
               } else {                /* satellite */
                        fe0->dvb.frontend = dvb_attach(tda10086_attach,
                                                       &flydvbs, &dev->i2c_adap);
@@ -1680,13 +1680,13 @@ static int dvb_init(struct saa7134_dev *dev)
                                               &dev->i2c_adap, 0) == NULL) {
                                        wprintk("%s: Asus My Cinema PS3-100, no "
                                                "tda826x found!\n", __func__);
-                                       goto dettach_frontend;
+                                       goto detach_frontend;
                                }
                                if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
                                               &dev->i2c_adap, 0, 0) == NULL) {
                                        wprintk("%s: Asus My Cinema PS3-100, no lnbp21"
                                                " found!\n", __func__);
-                                       goto dettach_frontend;
+                                       goto detach_frontend;
                                }
                        }
                }
@@ -1694,7 +1694,7 @@ static int dvb_init(struct saa7134_dev *dev)
        case SAA7134_BOARD_ASUSTeK_TIGER:
                if (configure_tda827x_fe(dev, &philips_tiger_config,
                                         &tda827x_cfg_0) < 0)
-                       goto dettach_frontend;
+                       goto detach_frontend;
                break;
        case SAA7134_BOARD_BEHOLD_H6:
                fe0->dvb.frontend = dvb_attach(zl10353_attach,
@@ -1830,19 +1830,19 @@ static int dvb_init(struct saa7134_dev *dev)
                };
 
                if (!fe0->dvb.frontend)
-                       goto dettach_frontend;
+                       goto detach_frontend;
 
                fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
                if (!fe) {
                        printk(KERN_ERR "%s/2: xc3028 attach failed\n",
                               dev->name);
-                       goto dettach_frontend;
+                       goto detach_frontend;
                }
        }
 
        if (NULL == fe0->dvb.frontend) {
                printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
-               goto dettach_frontend;
+               goto detach_frontend;
        }
        /* define general-purpose callback pointer */
        fe0->dvb.frontend->callback = saa7134_tuner_callback;
@@ -1864,7 +1864,7 @@ static int dvb_init(struct saa7134_dev *dev)
        }
        return ret;
 
-dettach_frontend:
+detach_frontend:
        videobuf_dvb_dealloc_frontends(&dev->frontends);
        return -EINVAL;
 }
diff --git a/drivers/media/video/saa7146.h b/drivers/media/video/saa7146.h
deleted file mode 100644 (file)
index 9fadb33..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
-    saa7146.h - definitions philips saa7146 based cards
-    Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __SAA7146__
-#define __SAA7146__
-
-#define SAA7146_VERSION_CODE 0x000101
-
-#include <linux/types.h>
-#include <linux/wait.h>
-
-#ifndef O_NONCAP
-#define O_NONCAP       O_TRUNC
-#endif
-
-#define MAX_GBUFFERS   2
-#define FBUF_SIZE      0x190000
-
-#ifdef __KERNEL__
-
-struct saa7146_window
-{
-       int x, y;
-       ushort width, height;
-       ushort bpp, bpl;
-       ushort swidth, sheight;
-       short cropx, cropy;
-       ushort cropwidth, cropheight;
-       unsigned long vidadr;
-       int color_fmt;
-       ushort depth;
-};
-
-/*  Per-open data for handling multiple opens on one device */
-struct device_open
-{
-       int          isopen;
-       int          noncapturing;
-       struct saa7146  *dev;
-};
-#define MAX_OPENS 3
-
-struct saa7146
-{
-       struct video_device video_dev;
-       struct video_picture picture;
-       struct video_audio audio_dev;
-       struct video_info vidinfo;
-       int user;
-       int cap;
-       int capuser;
-       int irqstate;           /* irq routine is state driven */
-       int writemode;
-       int playmode;
-       unsigned int nr;
-       unsigned long irq;          /* IRQ used by SAA7146 card */
-       unsigned short id;
-       unsigned char revision;
-       unsigned char boardcfg[64];     /* 64 bytes of config from eeprom */
-       unsigned long saa7146_adr;   /* bus address of IO mem from PCI BIOS */
-       struct saa7146_window win;
-       unsigned char __iomem *saa7146_mem; /* pointer to mapped IO memory */
-       struct device_open open_data[MAX_OPENS];
-#define MAX_MARKS 16
-       /* for a/v sync */
-       int endmark[MAX_MARKS], endmarkhead, endmarktail;
-       u32 *dmaRPS1, *pageRPS1, *dmaRPS2, *pageRPS2, *dmavid1, *dmavid2,
-               *dmavid3, *dmaa1in, *dmaa1out, *dmaa2in, *dmaa2out,
-               *pagedebi, *pagevid1, *pagevid2, *pagevid3, *pagea1in,
-               *pagea1out, *pagea2in, *pagea2out;
-       wait_queue_head_t i2cq, debiq, audq, vidq;
-       u8  *vidbuf, *audbuf, *osdbuf, *dmadebi;
-       int audhead, vidhead, osdhead, audtail, vidtail, osdtail;
-       spinlock_t lock;        /* the device lock */
-};
-#endif
-
-#ifdef _ALPHA_SAA7146
-#define saawrite(dat,adr)    writel((dat), saa->saa7146_adr+(adr))
-#define saaread(adr)         readl(saa->saa7146_adr+(adr))
-#else
-#define saawrite(dat,adr)    writel((dat), saa->saa7146_mem+(adr))
-#define saaread(adr)         readl(saa->saa7146_mem+(adr))
-#endif
-
-#define saaand(dat,adr)      saawrite((dat) & saaread(adr), adr)
-#define saaor(dat,adr)       saawrite((dat) | saaread(adr), adr)
-#define saaaor(dat,mask,adr) saawrite((dat) | ((mask) & saaread(adr)), adr)
-
-/* bitmask of attached hardware found */
-#define SAA7146_UNKNOWN                0x00000000
-#define SAA7146_SAA7111                0x00000001
-#define SAA7146_SAA7121                0x00000002
-#define SAA7146_IBMMPEG                0x00000004
-
-#endif
diff --git a/drivers/media/video/saa7146reg.h b/drivers/media/video/saa7146reg.h
deleted file mode 100644 (file)
index 80ec2c1..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
-    saa7146.h - definitions philips saa7146 based cards
-    Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __SAA7146_REG__
-#define __SAA7146_REG__
-#define SAA7146_BASE_ODD1      0x00
-#define SAA7146_BASE_EVEN1     0x04
-#define SAA7146_PROT_ADDR1     0x08
-#define SAA7146_PITCH1         0x0c
-#define SAA7146_PAGE1          0x10
-#define SAA7146_NUM_LINE_BYTE1 0x14
-#define SAA7146_BASE_ODD2      0x18
-#define SAA7146_BASE_EVEN2     0x1c
-#define SAA7146_PROT_ADDR2     0x20
-#define SAA7146_PITCH2         0x24
-#define SAA7146_PAGE2          0x28
-#define SAA7146_NUM_LINE_BYTE2 0x2c
-#define SAA7146_BASE_ODD3      0x30
-#define SAA7146_BASE_EVEN3     0x34
-#define SAA7146_PROT_ADDR3     0x38
-#define SAA7146_PITCH3         0x3c
-#define SAA7146_PAGE3          0x40
-#define SAA7146_NUM_LINE_BYTE3 0x44
-#define SAA7146_PCI_BT_V1      0x48
-#define SAA7146_PCI_BT_V2      0x49
-#define SAA7146_PCI_BT_V3      0x4a
-#define SAA7146_PCI_BT_DEBI    0x4b
-#define SAA7146_PCI_BT_A       0x4c
-#define SAA7146_DD1_INIT       0x50
-#define SAA7146_DD1_STREAM_B   0x54
-#define SAA7146_DD1_STREAM_A   0x56
-#define SAA7146_BRS_CTRL       0x58
-#define SAA7146_HPS_CTRL       0x5c
-#define SAA7146_HPS_V_SCALE    0x60
-#define SAA7146_HPS_V_GAIN     0x64
-#define SAA7146_HPS_H_PRESCALE 0x68
-#define SAA7146_HPS_H_SCALE    0x6c
-#define SAA7146_BCS_CTRL       0x70
-#define SAA7146_CHROMA_KEY_RANGE       0x74
-#define SAA7146_CLIP_FORMAT_CTRL       0x78
-#define SAA7146_DEBI_CONFIG    0x7c
-#define SAA7146_DEBI_COMMAND   0x80
-#define SAA7146_DEBI_PAGE      0x84
-#define SAA7146_DEBI_AD                0x88
-#define SAA7146_I2C_TRANSFER   0x8c
-#define SAA7146_I2C_STATUS     0x90
-#define SAA7146_BASE_A1_IN     0x94
-#define SAA7146_PROT_A1_IN     0x98
-#define SAA7146_PAGE_A1_IN     0x9C
-#define SAA7146_BASE_A1_OUT    0xa0
-#define SAA7146_PROT_A1_OUT    0xa4
-#define SAA7146_PAGE_A1_OUT    0xa8
-#define SAA7146_BASE_A2_IN     0xac
-#define SAA7146_PROT_A2_IN     0xb0
-#define SAA7146_PAGE_A2_IN     0xb4
-#define SAA7146_BASE_A2_OUT    0xb8
-#define SAA7146_PROT_A2_OUT    0xbc
-#define SAA7146_PAGE_A2_OUT    0xc0
-#define SAA7146_RPS_PAGE0      0xc4
-#define SAA7146_RPS_PAGE1      0xc8
-#define SAA7146_RPS_THRESH0    0xcc
-#define SAA7146_RPS_THRESH1    0xd0
-#define SAA7146_RPS_TOV0       0xd4
-#define SAA7146_RPS_TOV1       0xd8
-#define SAA7146_IER            0xdc
-#define SAA7146_GPIO_CTRL      0xe0
-#define SAA7146_EC1SSR         0xe4
-#define SAA7146_EC2SSR         0xe8
-#define SAA7146_ECT1R          0xec
-#define SAA7146_ECT2R          0xf0
-#define SAA7146_ACON1          0xf4
-#define SAA7146_ACON2          0xf8
-#define SAA7146_MC1            0xfc
-#define SAA7146_MC2            0x100
-#define SAA7146_RPS_ADDR0      0x104
-#define SAA7146_RPS_ADDR1      0x108
-#define SAA7146_ISR            0x10c
-#define SAA7146_PSR            0x110
-#define SAA7146_SSR            0x114
-#define SAA7146_EC1R           0x118
-#define SAA7146_EC2R           0x11c
-#define SAA7146_VDP1           0x120
-#define SAA7146_VDP2           0x124
-#define SAA7146_VDP3           0x128
-#define SAA7146_ADP1           0x12c
-#define SAA7146_ADP2           0x130
-#define SAA7146_ADP3           0x134
-#define SAA7146_ADP4           0x138
-#define SAA7146_DDP            0x13c
-#define SAA7146_LEVEL_REP      0x140
-#define SAA7146_FB_BUFFER1     0x144
-#define SAA7146_FB_BUFFER2     0x148
-#define SAA7146_A_TIME_SLOT1   0x180
-#define SAA7146_A_TIME_SLOT2   0x1C0
-
-/* bitfield defines */
-#define MASK_31                        0x80000000
-#define MASK_30                        0x40000000
-#define MASK_29                        0x20000000
-#define MASK_28                        0x10000000
-#define MASK_27                        0x08000000
-#define MASK_26                        0x04000000
-#define MASK_25                        0x02000000
-#define MASK_24                        0x01000000
-#define MASK_23                        0x00800000
-#define MASK_22                        0x00400000
-#define MASK_21                        0x00200000
-#define MASK_20                        0x00100000
-#define MASK_19                        0x00080000
-#define MASK_18                        0x00040000
-#define MASK_17                        0x00020000
-#define MASK_16                        0x00010000
-#define MASK_15                        0x00008000
-#define MASK_14                        0x00004000
-#define MASK_13                        0x00002000
-#define MASK_12                        0x00001000
-#define MASK_11                        0x00000800
-#define MASK_10                        0x00000400
-#define MASK_09                        0x00000200
-#define MASK_08                        0x00000100
-#define MASK_07                        0x00000080
-#define MASK_06                        0x00000040
-#define MASK_05                        0x00000020
-#define MASK_04                        0x00000010
-#define MASK_03                        0x00000008
-#define MASK_02                        0x00000004
-#define MASK_01                        0x00000002
-#define MASK_00                        0x00000001
-#define MASK_B0                        0x000000ff
-#define MASK_B1                        0x0000ff00
-#define MASK_B2                        0x00ff0000
-#define MASK_B3                        0xff000000
-#define MASK_W0                        0x0000ffff
-#define MASK_W1                        0xffff0000
-#define MASK_PA                        0xfffffffc
-#define MASK_PR                        0xfffffffe
-#define MASK_ER                        0xffffffff
-#define MASK_NONE              0x00000000
-
-#define SAA7146_PAGE_MAP_EN    MASK_11
-/* main control register 1 */
-#define SAA7146_MC1_MRST_N     MASK_15
-#define SAA7146_MC1_ERPS1      MASK_13
-#define SAA7146_MC1_ERPS0      MASK_12
-#define SAA7146_MC1_EDP                MASK_11
-#define SAA7146_MC1_EVP                MASK_10
-#define SAA7146_MC1_EAP                MASK_09
-#define SAA7146_MC1_EI2C       MASK_08
-#define SAA7146_MC1_TR_E_DEBI  MASK_07
-#define SAA7146_MC1_TR_E_1     MASK_06
-#define SAA7146_MC1_TR_E_2     MASK_05
-#define SAA7146_MC1_TR_E_3     MASK_04
-#define SAA7146_MC1_TR_E_A2_OUT        MASK_03
-#define SAA7146_MC1_TR_E_A2_IN MASK_02
-#define SAA7146_MC1_TR_E_A1_OUT        MASK_01
-#define SAA7146_MC1_TR_E_A1_IN MASK_00
-/* main control register 2 */
-#define SAA7146_MC2_RPS_SIG4   MASK_15
-#define SAA7146_MC2_RPS_SIG3   MASK_14
-#define SAA7146_MC2_RPS_SIG2   MASK_13
-#define SAA7146_MC2_RPS_SIG1   MASK_12
-#define SAA7146_MC2_RPS_SIG0   MASK_11
-#define SAA7146_MC2_UPLD_D1_B  MASK_10
-#define SAA7146_MC2_UPLD_D1_A  MASK_09
-#define SAA7146_MC2_UPLD_BRS   MASK_08
-#define SAA7146_MC2_UPLD_HPS_H MASK_06
-#define SAA7146_MC2_UPLD_HPS_V MASK_05
-#define SAA7146_MC2_UPLD_DMA3  MASK_04
-#define SAA7146_MC2_UPLD_DMA2  MASK_03
-#define SAA7146_MC2_UPLD_DMA1  MASK_02
-#define SAA7146_MC2_UPLD_DEBI  MASK_01
-#define SAA7146_MC2_UPLD_I2C   MASK_00
-/* Primary Status Register and Interrupt Enable/Status Registers */
-#define SAA7146_PSR_PPEF       MASK_31
-#define SAA7146_PSR_PABO       MASK_30
-#define SAA7146_PSR_PPED       MASK_29
-#define SAA7146_PSR_RPS_I1     MASK_28
-#define SAA7146_PSR_RPS_I0     MASK_27
-#define SAA7146_PSR_RPS_LATE1  MASK_26
-#define SAA7146_PSR_RPS_LATE0  MASK_25
-#define SAA7146_PSR_RPS_E1     MASK_24
-#define SAA7146_PSR_RPS_E0     MASK_23
-#define SAA7146_PSR_RPS_TO1    MASK_22
-#define SAA7146_PSR_RPS_TO0    MASK_21
-#define SAA7146_PSR_UPLD       MASK_20
-#define SAA7146_PSR_DEBI_S     MASK_19
-#define SAA7146_PSR_DEBI_E     MASK_18
-#define SAA7146_PSR_I2C_S      MASK_17
-#define SAA7146_PSR_I2C_E      MASK_16
-#define SAA7146_PSR_A2_IN      MASK_15
-#define SAA7146_PSR_A2_OUT     MASK_14
-#define SAA7146_PSR_A1_IN      MASK_13
-#define SAA7146_PSR_A1_OUT     MASK_12
-#define SAA7146_PSR_AFOU       MASK_11
-#define SAA7146_PSR_V_PE       MASK_10
-#define SAA7146_PSR_VFOU       MASK_09
-#define SAA7146_PSR_FIDA       MASK_08
-#define SAA7146_PSR_FIDB       MASK_07
-#define SAA7146_PSR_PIN3       MASK_06
-#define SAA7146_PSR_PIN2       MASK_05
-#define SAA7146_PSR_PIN1       MASK_04
-#define SAA7146_PSR_PIN0       MASK_03
-#define SAA7146_PSR_ECS                MASK_02
-#define SAA7146_PSR_EC3S       MASK_01
-#define SAA7146_PSR_EC0S       MASK_00
-/* Secondary Status Register */
-#define SAA7146_SSR_PRQ                MASK_31
-#define SAA7146_SSR_PMA                MASK_30
-#define SAA7146_SSR_RPS_RE1    MASK_29
-#define SAA7146_SSR_RPS_PE1    MASK_28
-#define SAA7146_SSR_RPS_A1     MASK_27
-#define SAA7146_SSR_RPS_RE0    MASK_26
-#define SAA7146_SSR_RPS_PE0    MASK_25
-#define SAA7146_SSR_RPS_A0     MASK_24
-#define SAA7146_SSR_DEBI_TO    MASK_23
-#define SAA7146_SSR_DEBI_EF    MASK_22
-#define SAA7146_SSR_I2C_EA     MASK_21
-#define SAA7146_SSR_I2C_EW     MASK_20
-#define SAA7146_SSR_I2C_ER     MASK_19
-#define SAA7146_SSR_I2C_EL     MASK_18
-#define SAA7146_SSR_I2C_EF     MASK_17
-#define SAA7146_SSR_V3P                MASK_16
-#define SAA7146_SSR_V2P                MASK_15
-#define SAA7146_SSR_V1P                MASK_14
-#define SAA7146_SSR_VF3                MASK_13
-#define SAA7146_SSR_VF2                MASK_12
-#define SAA7146_SSR_VF1                MASK_11
-#define SAA7146_SSR_AF2_IN     MASK_10
-#define SAA7146_SSR_AF2_OUT    MASK_09
-#define SAA7146_SSR_AF1_IN     MASK_08
-#define SAA7146_SSR_AF1_OUT    MASK_07
-#define SAA7146_SSR_VGT                MASK_05
-#define SAA7146_SSR_LNQG       MASK_04
-#define SAA7146_SSR_EC5S       MASK_03
-#define SAA7146_SSR_EC4S       MASK_02
-#define SAA7146_SSR_EC2S       MASK_01
-#define SAA7146_SSR_EC1S       MASK_00
-/* I2C status register */
-#define SAA7146_I2C_ABORT      MASK_07
-#define SAA7146_I2C_SPERR      MASK_06
-#define SAA7146_I2C_APERR      MASK_05
-#define SAA7146_I2C_DTERR      MASK_04
-#define SAA7146_I2C_DRERR      MASK_03
-#define SAA7146_I2C_AL         MASK_02
-#define SAA7146_I2C_ERR                MASK_01
-#define SAA7146_I2C_BUSY       MASK_00
-/* output formats */
-#define SAA7146_YUV422 0
-#define SAA7146_RGB16  0
-#define SAA7146_YUV444 1
-#define SAA7146_RGB24  1
-#define SAA7146_ARGB32 2
-#define SAA7146_YUV411 3
-#define SAA7146_ARGB15  3
-#define SAA7146_YUV2   4
-#define SAA7146_RGAB15 4
-#define SAA7146_Y8     6
-#define SAA7146_YUV8   7
-#define SAA7146_RGB8   7
-#define SAA7146_YUV444p        8
-#define SAA7146_YUV422p        9
-#define SAA7146_YUV420p        10
-#define SAA7146_YUV1620        11
-#define SAA7146_Y1     13
-#define SAA7146_Y2     14
-#define SAA7146_YUV1   15
-#endif
index 8a98ab68239e10ee5f1155f4fa31e678b58f7e48..c8799fdaae67d074e0bdbe64ea2bac4f752edb2f 100644 (file)
@@ -1367,7 +1367,6 @@ int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
        struct saa7164_dev *dev = bus->dev;
        u16 len = 0;
        int unitid;
-       u32 regval;
        u8 buf[256];
        int ret;
 
@@ -1376,19 +1375,6 @@ int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
        if (reglen > 4)
                return -EIO;
 
-       if (reglen == 1)
-               regval = *(reg);
-       else
-       if (reglen == 2)
-               regval = ((*(reg) << 8) || *(reg+1));
-       else
-       if (reglen == 3)
-               regval = ((*(reg) << 16) | (*(reg+1) << 8) | *(reg+2));
-       else
-       if (reglen == 4)
-               regval = ((*(reg) << 24) | (*(reg+1) << 16) |
-                       (*(reg+2) << 8) | *(reg+3));
-
        /* Prepare the send buffer */
        /* Bytes 00-03 source register length
         *       04-07 source bytes to read
index fb99ff18be077255810f43e71fd0a9163ee883b5..3149cda1d0dbb8202923ac4550b80f03becd2b9c 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_SMIAPP
        tristate "SMIA++/SMIA sensor support"
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAVE_CLK
+       depends on MEDIA_CAMERA_SUPPORT
        select VIDEO_SMIAPP_PLL
        ---help---
          This is a generic driver for SMIA++/SMIA camera modules.
index 9cf5bda35fbe1cfe332e8b18ae3d9218b3e8f54b..f466a7edcb2a8381378439b57abfa61327c526ab 100644 (file)
@@ -39,9 +39,9 @@
 
 #include "smiapp.h"
 
-#define SMIAPP_ALIGN_DIM(dim, flags)           \
-       ((flags) & V4L2_SUBDEV_SEL_FLAG_SIZE_GE \
-        ? ALIGN((dim), 2)                      \
+#define SMIAPP_ALIGN_DIM(dim, flags)   \
+       ((flags) & V4L2_SEL_FLAG_GE     \
+        ? ALIGN((dim), 2)              \
         : (dim) & ~1)
 
 /*
@@ -1631,7 +1631,7 @@ static void smiapp_propagate(struct v4l2_subdev *subdev,
        smiapp_get_crop_compose(subdev, fh, crops, &comp, which);
 
        switch (target) {
-       case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+       case V4L2_SEL_TGT_CROP:
                comp->width = crops[SMIAPP_PAD_SINK]->width;
                comp->height = crops[SMIAPP_PAD_SINK]->height;
                if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
@@ -1647,7 +1647,7 @@ static void smiapp_propagate(struct v4l2_subdev *subdev,
                        }
                }
                /* Fall through */
-       case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+       case V4L2_SEL_TGT_COMPOSE:
                *crops[SMIAPP_PAD_SRC] = *comp;
                break;
        default:
@@ -1723,7 +1723,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev,
        if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
                ssd->sink_fmt = *crops[ssd->sink_pad];
        smiapp_propagate(subdev, fh, fmt->which,
-                        V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL);
+                        V4L2_SEL_TGT_CROP);
 
        mutex_unlock(&sensor->mutex);
 
@@ -1748,14 +1748,14 @@ static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
        h &= ~1;
        ask_h &= ~1;
 
-       if (flags & V4L2_SUBDEV_SEL_FLAG_SIZE_GE) {
+       if (flags & V4L2_SEL_FLAG_GE) {
                if (w < ask_w)
                        val -= SCALING_GOODNESS;
                if (h < ask_h)
                        val -= SCALING_GOODNESS;
        }
 
-       if (flags & V4L2_SUBDEV_SEL_FLAG_SIZE_LE) {
+       if (flags & V4L2_SEL_FLAG_LE) {
                if (w > ask_w)
                        val -= SCALING_GOODNESS;
                if (h > ask_h)
@@ -1958,7 +1958,7 @@ static int smiapp_set_compose(struct v4l2_subdev *subdev,
 
        *comp = sel->r;
        smiapp_propagate(subdev, fh, sel->which,
-                        V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL);
+                        V4L2_SEL_TGT_COMPOSE);
 
        if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
                return smiapp_update_mode(sensor);
@@ -1974,8 +1974,8 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
 
        /* We only implement crop in three places. */
        switch (sel->target) {
-       case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
-       case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
                if (ssd == sensor->pixel_array
                    && sel->pad == SMIAPP_PA_PAD_SRC)
                        return 0;
@@ -1988,8 +1988,8 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
                    == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP)
                        return 0;
                return -EINVAL;
-       case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
-       case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+       case V4L2_SEL_TGT_COMPOSE:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
                if (sel->pad == ssd->source_pad)
                        return -EINVAL;
                if (ssd == sensor->binner)
@@ -2051,7 +2051,7 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev,
 
        if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK)
                smiapp_propagate(subdev, fh, sel->which,
-                                V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL);
+                                V4L2_SEL_TGT_CROP);
 
        return 0;
 }
@@ -2085,7 +2085,7 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev,
        }
 
        switch (sel->target) {
-       case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
                if (ssd == sensor->pixel_array) {
                        sel->r.width =
                                sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
@@ -2097,11 +2097,11 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev,
                        sel->r = *comp;
                }
                break;
-       case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
-       case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+       case V4L2_SEL_TGT_CROP:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
                sel->r = *crops[sel->pad];
                break;
-       case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+       case V4L2_SEL_TGT_COMPOSE:
                sel->r = *comp;
                break;
        }
@@ -2148,10 +2148,10 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev,
                              sel->r.height);
 
        switch (sel->target) {
-       case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+       case V4L2_SEL_TGT_CROP:
                ret = smiapp_set_crop(subdev, fh, sel);
                break;
-       case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+       case V4L2_SEL_TGT_COMPOSE:
                ret = smiapp_set_compose(subdev, fh, sel);
                break;
        default:
index 22ea211ab54f144cfb656c2080a17896c93d9538..2bc153e869befb7ab21df85ce809e2f0fde5efe9 100644 (file)
@@ -182,7 +182,7 @@ do {                                                                          \
 #      define V4LDBG(level, name, cmd)                                       \
 do {                                                                          \
        if (debug >= (level))                                                 \
-               v4l_print_ioctl(name, cmd);                                   \
+               v4l_printk_ioctl(name, cmd);                                  \
 } while (0)
 #      define KDBG(level, fmt, args...)                                      \
 do {                                                                          \
index 1ad5ab6ce5cf9ea46187d2ac03224033957b1247..b5a819af2b8c4c3c36ae00fdf2eb7334863de030 100644 (file)
@@ -228,6 +228,16 @@ static int fe_has_signal(struct dvb_frontend *fe)
        return strength;
 }
 
+static int fe_get_afc(struct dvb_frontend *fe)
+{
+       s32 afc = 0;
+
+       if (fe->ops.tuner_ops.get_afc)
+               fe->ops.tuner_ops.get_afc(fe, &afc);
+
+       return 0;
+}
+
 static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
 {
        struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
@@ -247,6 +257,7 @@ static struct analog_demod_ops tuner_analog_ops = {
        .set_params     = fe_set_params,
        .standby        = fe_standby,
        .has_signal     = fe_has_signal,
+       .get_afc        = fe_get_afc,
        .set_config     = fe_set_config,
        .tuner_status   = tuner_status
 };
@@ -1178,6 +1189,8 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
                return 0;
        if (vt->type == t->mode && analog_ops->get_afc)
                vt->afc = analog_ops->get_afc(&t->fe);
+       if (analog_ops->has_signal)
+               vt->signal = analog_ops->has_signal(&t->fe);
        if (vt->type != V4L2_TUNER_RADIO) {
                vt->capability |= V4L2_TUNER_CAP_NORM;
                vt->rangelow = tv_range[0] * 16;
@@ -1197,8 +1210,6 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
                                V4L2_TUNER_SUB_STEREO :
                                V4L2_TUNER_SUB_MONO;
                }
-               if (analog_ops->has_signal)
-                       vt->signal = analog_ops->has_signal(&t->fe);
                vt->audmode = t->audmode;
        }
        vt->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
index c5b1a7365e4f60efc174e1bad6be3aac3f535807..321b3153df87abe1537bab907121d98012d25838 100644 (file)
@@ -59,8 +59,8 @@ struct CHIPSTATE;
 typedef int  (*getvalue)(int);
 typedef int  (*checkit)(struct CHIPSTATE*);
 typedef int  (*initialize)(struct CHIPSTATE*);
-typedef int  (*getmode)(struct CHIPSTATE*);
-typedef void (*setmode)(struct CHIPSTATE*, int mode);
+typedef int  (*getrxsubchans)(struct CHIPSTATE *);
+typedef void (*setaudmode)(struct CHIPSTATE*, int mode);
 
 /* i2c command */
 typedef struct AUDIOCMD {
@@ -96,8 +96,8 @@ struct CHIPDESC {
        getvalue volfunc,treblefunc,bassfunc;
 
        /* get/set mode */
-       getmode  getmode;
-       setmode  setmode;
+       getrxsubchans   getrxsubchans;
+       setaudmode      setaudmode;
 
        /* input switch register + values for v4l inputs */
        int  inputreg;
@@ -118,7 +118,7 @@ struct CHIPSTATE {
        audiocmd   shadow;
 
        /* current settings */
-       __u16 left,right,treble,bass,muted,mode;
+       __u16 left, right, treble, bass, muted;
        int prevmode;
        int radio;
        int input;
@@ -126,7 +126,6 @@ struct CHIPSTATE {
        /* thread */
        struct task_struct   *thread;
        struct timer_list    wt;
-       int                  watch_stereo;
        int                  audmode;
 };
 
@@ -288,7 +287,7 @@ static int chip_thread(void *data)
        struct CHIPSTATE *chip = data;
        struct CHIPDESC  *desc = chip->desc;
        struct v4l2_subdev *sd = &chip->sd;
-       int mode;
+       int mode, selected;
 
        v4l2_dbg(1, debug, sd, "thread started\n");
        set_freezable();
@@ -302,12 +301,12 @@ static int chip_thread(void *data)
                        break;
                v4l2_dbg(1, debug, sd, "thread wakeup\n");
 
-               /* don't do anything for radio or if mode != auto */
-               if (chip->radio || chip->mode != 0)
+               /* don't do anything for radio */
+               if (chip->radio)
                        continue;
 
                /* have a look what's going on */
-               mode = desc->getmode(chip);
+               mode = desc->getrxsubchans(chip);
                if (mode == chip->prevmode)
                        continue;
 
@@ -316,16 +315,32 @@ static int chip_thread(void *data)
 
                chip->prevmode = mode;
 
-               if (mode & V4L2_TUNER_MODE_STEREO)
-                       desc->setmode(chip, V4L2_TUNER_MODE_STEREO);
-               if (mode & V4L2_TUNER_MODE_LANG1_LANG2)
-                       desc->setmode(chip, V4L2_TUNER_MODE_STEREO);
-               else if (mode & V4L2_TUNER_MODE_LANG1)
-                       desc->setmode(chip, V4L2_TUNER_MODE_LANG1);
-               else if (mode & V4L2_TUNER_MODE_LANG2)
-                       desc->setmode(chip, V4L2_TUNER_MODE_LANG2);
-               else
-                       desc->setmode(chip, V4L2_TUNER_MODE_MONO);
+               selected = V4L2_TUNER_MODE_MONO;
+               switch (chip->audmode) {
+               case V4L2_TUNER_MODE_MONO:
+                       if (mode & V4L2_TUNER_SUB_LANG1)
+                               selected = V4L2_TUNER_MODE_LANG1;
+                       break;
+               case V4L2_TUNER_MODE_STEREO:
+               case V4L2_TUNER_MODE_LANG1:
+                       if (mode & V4L2_TUNER_SUB_LANG1)
+                               selected = V4L2_TUNER_MODE_LANG1;
+                       else if (mode & V4L2_TUNER_SUB_STEREO)
+                               selected = V4L2_TUNER_MODE_STEREO;
+                       break;
+               case V4L2_TUNER_MODE_LANG2:
+                       if (mode & V4L2_TUNER_SUB_LANG2)
+                               selected = V4L2_TUNER_MODE_LANG2;
+                       else if (mode & V4L2_TUNER_SUB_STEREO)
+                               selected = V4L2_TUNER_MODE_STEREO;
+                       break;
+               case V4L2_TUNER_MODE_LANG1_LANG2:
+                       if (mode & V4L2_TUNER_SUB_LANG2)
+                               selected = V4L2_TUNER_MODE_LANG1_LANG2;
+                       else if (mode & V4L2_TUNER_SUB_STEREO)
+                               selected = V4L2_TUNER_MODE_STEREO;
+               }
+               desc->setaudmode(chip, selected);
 
                /* schedule next check */
                mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
@@ -358,24 +373,25 @@ static int chip_thread(void *data)
 #define TDA9840_TEST_INT1SN 0x1 /* Integration time 0.5s when set */
 #define TDA9840_TEST_INTFU 0x02 /* Disables integrator function */
 
-static int tda9840_getmode(struct CHIPSTATE *chip)
+static int tda9840_getrxsubchans(struct CHIPSTATE *chip)
 {
        struct v4l2_subdev *sd = &chip->sd;
        int val, mode;
 
        val = chip_read(chip);
-       mode = V4L2_TUNER_MODE_MONO;
+       mode = V4L2_TUNER_SUB_MONO;
        if (val & TDA9840_DS_DUAL)
-               mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+               mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
        if (val & TDA9840_ST_STEREO)
-               mode |= V4L2_TUNER_MODE_STEREO;
+               mode = V4L2_TUNER_SUB_STEREO;
 
-       v4l2_dbg(1, debug, sd, "tda9840_getmode(): raw chip read: %d, return: %d\n",
+       v4l2_dbg(1, debug, sd,
+               "tda9840_getrxsubchans(): raw chip read: %d, return: %d\n",
                val, mode);
        return mode;
 }
 
-static void tda9840_setmode(struct CHIPSTATE *chip, int mode)
+static void tda9840_setaudmode(struct CHIPSTATE *chip, int mode)
 {
        int update = 1;
        int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e;
@@ -393,6 +409,9 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode)
        case V4L2_TUNER_MODE_LANG2:
                t |= TDA9840_DUALB;
                break;
+       case V4L2_TUNER_MODE_LANG1_LANG2:
+               t |= TDA9840_DUALAB;
+               break;
        default:
                update = 0;
        }
@@ -477,6 +496,7 @@ static int tda9840_checkit(struct CHIPSTATE *chip)
 /* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */
 /* Common to TDA9855 and TDA9850: */
 #define TDA985x_SAP    3<<6 /* Selects SAP output, mute if not received */
+#define TDA985x_MONOSAP        2<<6 /* Selects Mono on left, SAP on right */
 #define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */
 #define TDA985x_MONO   0    /* Forces Mono output */
 #define TDA985x_LMU    1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */
@@ -513,18 +533,22 @@ static int tda9855_volume(int val) { return val/0x2e8+0x27; }
 static int tda9855_bass(int val)   { return val/0xccc+0x06; }
 static int tda9855_treble(int val) { return (val/0x1c71+0x3)<<1; }
 
-static int  tda985x_getmode(struct CHIPSTATE *chip)
+static int  tda985x_getrxsubchans(struct CHIPSTATE *chip)
 {
-       int mode;
+       int mode, val;
 
-       mode = ((TDA985x_STP | TDA985x_SAPP) &
-               chip_read(chip)) >> 4;
        /* Add mono mode regardless of SAP and stereo */
        /* Allows forced mono */
-       return mode | V4L2_TUNER_MODE_MONO;
+       mode = V4L2_TUNER_SUB_MONO;
+       val = chip_read(chip);
+       if (val & TDA985x_STP)
+               mode = V4L2_TUNER_SUB_STEREO;
+       if (val & TDA985x_SAPP)
+               mode |= V4L2_TUNER_SUB_SAP;
+       return mode;
 }
 
-static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
+static void tda985x_setaudmode(struct CHIPSTATE *chip, int mode)
 {
        int update = 1;
        int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f;
@@ -534,11 +558,15 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
                c6 |= TDA985x_MONO;
                break;
        case V4L2_TUNER_MODE_STEREO:
+       case V4L2_TUNER_MODE_LANG1:
                c6 |= TDA985x_STEREO;
                break;
-       case V4L2_TUNER_MODE_LANG1:
+       case V4L2_TUNER_MODE_SAP:
                c6 |= TDA985x_SAP;
                break;
+       case V4L2_TUNER_MODE_LANG1_LANG2:
+               c6 |= TDA985x_MONOSAP;
+               break;
        default:
                update = 0;
        }
@@ -583,9 +611,10 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
 #define TDA9873_TR_MASK     (7 << 2)
 #define TDA9873_TR_MONO     4
 #define TDA9873_TR_STEREO   1 << 4
-#define TDA9873_TR_REVERSE  (1 << 3) & (1 << 2)
+#define TDA9873_TR_REVERSE  ((1 << 3) | (1 << 2))
 #define TDA9873_TR_DUALA    1 << 2
 #define TDA9873_TR_DUALB    1 << 3
+#define TDA9873_TR_DUALAB   0
 
 /* output level controls
  * B5:  output level switch (0 = reduced gain, 1 = normal gain)
@@ -653,46 +682,51 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
 #define TDA9873_MOUT_DUALA  0
 #define TDA9873_MOUT_DUALB  1 << 3
 #define TDA9873_MOUT_ST     1 << 4
-#define TDA9873_MOUT_EXTM   (1 << 4 ) & (1 << 3)
+#define TDA9873_MOUT_EXTM   ((1 << 4) | (1 << 3))
 #define TDA9873_MOUT_EXTL   1 << 5
-#define TDA9873_MOUT_EXTR   (1 << 5 ) & (1 << 3)
-#define TDA9873_MOUT_EXTLR  (1 << 5 ) & (1 << 4)
-#define TDA9873_MOUT_MUTE   (1 << 5 ) & (1 << 4) & (1 << 3)
+#define TDA9873_MOUT_EXTR   ((1 << 5) | (1 << 3))
+#define TDA9873_MOUT_EXTLR  ((1 << 5) | (1 << 4))
+#define TDA9873_MOUT_MUTE   ((1 << 5) | (1 << 4) | (1 << 3))
 
 /* Status bits: (chip read) */
 #define TDA9873_PONR        0 /* Power-on reset detected if = 1 */
 #define TDA9873_STEREO      2 /* Stereo sound is identified     */
 #define TDA9873_DUAL        4 /* Dual sound is identified       */
 
-static int tda9873_getmode(struct CHIPSTATE *chip)
+static int tda9873_getrxsubchans(struct CHIPSTATE *chip)
 {
        struct v4l2_subdev *sd = &chip->sd;
        int val,mode;
 
        val = chip_read(chip);
-       mode = V4L2_TUNER_MODE_MONO;
+       mode = V4L2_TUNER_SUB_MONO;
        if (val & TDA9873_STEREO)
-               mode |= V4L2_TUNER_MODE_STEREO;
+               mode = V4L2_TUNER_SUB_STEREO;
        if (val & TDA9873_DUAL)
-               mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
-       v4l2_dbg(1, debug, sd, "tda9873_getmode(): raw chip read: %d, return: %d\n",
+               mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+       v4l2_dbg(1, debug, sd,
+               "tda9873_getrxsubchans(): raw chip read: %d, return: %d\n",
                val, mode);
        return mode;
 }
 
-static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
+static void tda9873_setaudmode(struct CHIPSTATE *chip, int mode)
 {
        struct v4l2_subdev *sd = &chip->sd;
        int sw_data  = chip->shadow.bytes[TDA9873_SW+1] & ~ TDA9873_TR_MASK;
        /*      int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
 
        if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
-               v4l2_dbg(1, debug, sd, "tda9873_setmode(): external input\n");
+               v4l2_dbg(1, debug, sd,
+                        "tda9873_setaudmode(): external input\n");
                return;
        }
 
-       v4l2_dbg(1, debug, sd, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
-       v4l2_dbg(1, debug, sd, "tda9873_setmode(): sw_data  = %d\n", sw_data);
+       v4l2_dbg(1, debug, sd,
+                "tda9873_setaudmode(): chip->shadow.bytes[%d] = %d\n",
+                TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
+       v4l2_dbg(1, debug, sd, "tda9873_setaudmode(): sw_data  = %d\n",
+                sw_data);
 
        switch (mode) {
        case V4L2_TUNER_MODE_MONO:
@@ -707,13 +741,16 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
        case V4L2_TUNER_MODE_LANG2:
                sw_data |= TDA9873_TR_DUALB;
                break;
+       case V4L2_TUNER_MODE_LANG1_LANG2:
+               sw_data |= TDA9873_TR_DUALAB;
+               break;
        default:
-               chip->mode = 0;
                return;
        }
 
        chip_write(chip, TDA9873_SW, sw_data);
-       v4l2_dbg(1, debug, sd, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
+       v4l2_dbg(1, debug, sd,
+               "tda9873_setaudmode(): req. mode %d; chip_write: %d\n",
                mode, sw_data);
 }
 
@@ -859,13 +896,13 @@ static int tda9874a_setup(struct CHIPSTATE *chip)
        return 1;
 }
 
-static int tda9874a_getmode(struct CHIPSTATE *chip)
+static int tda9874a_getrxsubchans(struct CHIPSTATE *chip)
 {
        struct v4l2_subdev *sd = &chip->sd;
        int dsr,nsr,mode;
        int necr; /* just for debugging */
 
-       mode = V4L2_TUNER_MODE_MONO;
+       mode = V4L2_TUNER_SUB_MONO;
 
        if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR)))
                return mode;
@@ -888,22 +925,23 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
                 * external 4052 multiplexer in audio_hook().
                 */
                if(nsr & 0x02) /* NSR.S/MB=1 */
-                       mode |= V4L2_TUNER_MODE_STEREO;
+                       mode = V4L2_TUNER_SUB_STEREO;
                if(nsr & 0x01) /* NSR.D/SB=1 */
-                       mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+                       mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
        } else {
                if(dsr & 0x02) /* DSR.IDSTE=1 */
-                       mode |= V4L2_TUNER_MODE_STEREO;
+                       mode = V4L2_TUNER_SUB_STEREO;
                if(dsr & 0x04) /* DSR.IDDUA=1 */
-                       mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+                       mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
        }
 
-       v4l2_dbg(1, debug, sd, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
+       v4l2_dbg(1, debug, sd,
+                "tda9874a_getrxsubchans(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
                 dsr, nsr, necr, mode);
        return mode;
 }
 
-static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
+static void tda9874a_setaudmode(struct CHIPSTATE *chip, int mode)
 {
        struct v4l2_subdev *sd = &chip->sd;
 
@@ -939,14 +977,18 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
                        aosr = 0xa0; /* auto-select, dual B/B */
                        mdacosr = (tda9874a_mode) ? 0x83:0x81;
                        break;
+               case V4L2_TUNER_MODE_LANG1_LANG2:
+                       aosr = 0x00; /* always route L to L and R to R */
+                       mdacosr = (tda9874a_mode) ? 0x82:0x80;
+                       break;
                default:
-                       chip->mode = 0;
                        return;
                }
                chip_write(chip, TDA9874A_AOSR, aosr);
                chip_write(chip, TDA9874A_MDACOSR, mdacosr);
 
-               v4l2_dbg(1, debug, sd, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
+               v4l2_dbg(1, debug, sd,
+                       "tda9874a_setaudmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
                        mode, aosr, mdacosr);
 
        } else { /* dic == 0x07 */
@@ -974,14 +1016,18 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
                        fmmr = 0x02; /* dual */
                        aosr = 0x20; /* dual B/B */
                        break;
+               case V4L2_TUNER_MODE_LANG1_LANG2:
+                       fmmr = 0x02; /* dual */
+                       aosr = 0x00; /* dual A/B */
+                       break;
                default:
-                       chip->mode = 0;
                        return;
                }
                chip_write(chip, TDA9874A_FMMR, fmmr);
                chip_write(chip, TDA9874A_AOSR, aosr);
 
-               v4l2_dbg(1, debug, sd, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
+               v4l2_dbg(1, debug, sd,
+                       "tda9874a_setaudmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
                        mode, fmmr, aosr);
        }
 }
@@ -1226,25 +1272,33 @@ static int tea6320_initialize(struct CHIPSTATE * chip)
 static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; }
 static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
 
-static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
+static void tda8425_setaudmode(struct CHIPSTATE *chip, int mode)
 {
        int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
 
-       if (mode & V4L2_TUNER_MODE_LANG1) {
+       switch (mode) {
+       case V4L2_TUNER_MODE_LANG1:
                s1 |= TDA8425_S1_ML_SOUND_A;
                s1 |= TDA8425_S1_STEREO_PSEUDO;
-
-       } else if (mode & V4L2_TUNER_MODE_LANG2) {
+               break;
+       case V4L2_TUNER_MODE_LANG2:
                s1 |= TDA8425_S1_ML_SOUND_B;
                s1 |= TDA8425_S1_STEREO_PSEUDO;
-
-       } else {
+               break;
+       case V4L2_TUNER_MODE_LANG1_LANG2:
                s1 |= TDA8425_S1_ML_STEREO;
-
-               if (mode & V4L2_TUNER_MODE_MONO)
-                       s1 |= TDA8425_S1_STEREO_MONO;
-               if (mode & V4L2_TUNER_MODE_STEREO)
-                       s1 |= TDA8425_S1_STEREO_SPATIAL;
+               s1 |= TDA8425_S1_STEREO_LINEAR;
+               break;
+       case V4L2_TUNER_MODE_MONO:
+               s1 |= TDA8425_S1_ML_STEREO;
+               s1 |= TDA8425_S1_STEREO_MONO;
+               break;
+       case V4L2_TUNER_MODE_STEREO:
+               s1 |= TDA8425_S1_ML_STEREO;
+               s1 |= TDA8425_S1_STEREO_SPATIAL;
+               break;
+       default:
+               return;
        }
        chip_write(chip,TDA8425_S1,s1);
 }
@@ -1297,18 +1351,20 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
  * stereo  L  L
  * BIL     H  L
  */
-static int ta8874z_getmode(struct CHIPSTATE *chip)
+static int ta8874z_getrxsubchans(struct CHIPSTATE *chip)
 {
        int val, mode;
 
        val = chip_read(chip);
-       mode = V4L2_TUNER_MODE_MONO;
+       mode = V4L2_TUNER_SUB_MONO;
        if (val & TA8874Z_B1){
-               mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+               mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
        }else if (!(val & TA8874Z_B0)){
-               mode |= V4L2_TUNER_MODE_STEREO;
+               mode = V4L2_TUNER_SUB_STEREO;
        }
-       /* v4l_dbg(1, debug, chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
+       /* v4l2_dbg(1, debug, &chip->sd,
+                "ta8874z_getrxsubchans(): raw chip read: 0x%02x, return: 0x%02x\n",
+                val, mode); */
        return mode;
 }
 
@@ -1316,14 +1372,15 @@ static audiocmd ta8874z_stereo = { 2, {0, TA8874Z_SEPARATION_DEFAULT}};
 static audiocmd ta8874z_mono = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}};
 static audiocmd ta8874z_main = {2, { 0, TA8874Z_SEPARATION_DEFAULT}};
 static audiocmd ta8874z_sub = {2, { TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}};
+static audiocmd ta8874z_both = {2, { TA8874Z_MODE_MAIN | TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}};
 
-static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
+static void ta8874z_setaudmode(struct CHIPSTATE *chip, int mode)
 {
        struct v4l2_subdev *sd = &chip->sd;
        int update = 1;
        audiocmd *t = NULL;
 
-       v4l2_dbg(1, debug, sd, "ta8874z_setmode(): mode: 0x%02x\n", mode);
+       v4l2_dbg(1, debug, sd, "ta8874z_setaudmode(): mode: 0x%02x\n", mode);
 
        switch(mode){
        case V4L2_TUNER_MODE_MONO:
@@ -1338,6 +1395,9 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
        case V4L2_TUNER_MODE_LANG2:
                t = &ta8874z_sub;
                break;
+       case V4L2_TUNER_MODE_LANG1_LANG2:
+               t = &ta8874z_both;
+               break;
        default:
                update = 0;
        }
@@ -1394,8 +1454,8 @@ static struct CHIPDESC chiplist[] = {
 
                /* callbacks */
                .checkit    = tda9840_checkit,
-               .getmode    = tda9840_getmode,
-               .setmode    = tda9840_setmode,
+               .getrxsubchans = tda9840_getrxsubchans,
+               .setaudmode = tda9840_setaudmode,
 
                .init       = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
                                /* ,TDA9840_SW, TDA9840_MONO */} }
@@ -1410,8 +1470,8 @@ static struct CHIPDESC chiplist[] = {
 
                /* callbacks */
                .checkit    = tda9873_checkit,
-               .getmode    = tda9873_getmode,
-               .setmode    = tda9873_setmode,
+               .getrxsubchans = tda9873_getrxsubchans,
+               .setaudmode = tda9873_setaudmode,
 
                .init       = { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
                .inputreg   = TDA9873_SW,
@@ -1430,8 +1490,8 @@ static struct CHIPDESC chiplist[] = {
                /* callbacks */
                .initialize = tda9874a_initialize,
                .checkit    = tda9874a_checkit,
-               .getmode    = tda9874a_getmode,
-               .setmode    = tda9874a_setmode,
+               .getrxsubchans = tda9874a_getrxsubchans,
+               .setaudmode = tda9874a_setaudmode,
        },
        {
                .name       = "tda9875",
@@ -1460,8 +1520,8 @@ static struct CHIPDESC chiplist[] = {
                .addr_hi    = I2C_ADDR_TDA985x_H >> 1,
                .registers  = 11,
 
-               .getmode    = tda985x_getmode,
-               .setmode    = tda985x_setmode,
+               .getrxsubchans = tda985x_getrxsubchans,
+               .setaudmode = tda985x_setaudmode,
 
                .init       = { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } }
        },
@@ -1482,8 +1542,8 @@ static struct CHIPDESC chiplist[] = {
                .volfunc    = tda9855_volume,
                .bassfunc   = tda9855_bass,
                .treblefunc = tda9855_treble,
-               .getmode    = tda985x_getmode,
-               .setmode    = tda985x_setmode,
+               .getrxsubchans = tda985x_getrxsubchans,
+               .setaudmode = tda985x_setaudmode,
 
                .init       = { 12, { 0, 0x6f, 0x6f, 0x0e, 0x07<<1, 0x8<<2,
                                    TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT,
@@ -1564,7 +1624,7 @@ static struct CHIPDESC chiplist[] = {
                .volfunc    = tda8425_shift10,
                .bassfunc   = tda8425_shift12,
                .treblefunc = tda8425_shift12,
-               .setmode    = tda8425_setmode,
+               .setaudmode = tda8425_setaudmode,
 
                .inputreg   = TDA8425_S1,
                .inputmap   = { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },
@@ -1593,11 +1653,10 @@ static struct CHIPDESC chiplist[] = {
                .addr_lo    = I2C_ADDR_TDA9840 >> 1,
                .addr_hi    = I2C_ADDR_TDA9840 >> 1,
                .registers  = 2,
-               .flags      = CHIP_NEED_CHECKMODE,
 
                /* callbacks */
-               .getmode    = ta8874z_getmode,
-               .setmode    = ta8874z_setmode,
+               .getrxsubchans = ta8874z_getrxsubchans,
+               .setaudmode = ta8874z_setaudmode,
 
                .init       = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
        },
@@ -1736,7 +1795,6 @@ static int tvaudio_s_radio(struct v4l2_subdev *sd)
        struct CHIPSTATE *chip = to_state(sd);
 
        chip->radio = 1;
-       chip->watch_stereo = 0;
        /* del_timer(&chip->wt); */
        return 0;
 }
@@ -1793,9 +1851,8 @@ static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 {
        struct CHIPSTATE *chip = to_state(sd);
        struct CHIPDESC *desc = chip->desc;
-       int mode = 0;
 
-       if (!desc->setmode)
+       if (!desc->setaudmode)
                return 0;
        if (chip->radio)
                return 0;
@@ -1805,22 +1862,18 @@ static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        case V4L2_TUNER_MODE_STEREO:
        case V4L2_TUNER_MODE_LANG1:
        case V4L2_TUNER_MODE_LANG2:
-               mode = vt->audmode;
-               break;
        case V4L2_TUNER_MODE_LANG1_LANG2:
-               mode = V4L2_TUNER_MODE_STEREO;
                break;
        default:
                return -EINVAL;
        }
        chip->audmode = vt->audmode;
 
-       if (mode) {
-               chip->watch_stereo = 0;
-               /* del_timer(&chip->wt); */
-               chip->mode = mode;
-               desc->setmode(chip, mode);
-       }
+       if (chip->thread)
+               wake_up_process(chip->thread);
+       else
+               desc->setaudmode(chip, vt->audmode);
+
        return 0;
 }
 
@@ -1828,30 +1881,17 @@ static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 {
        struct CHIPSTATE *chip = to_state(sd);
        struct CHIPDESC *desc = chip->desc;
-       int mode = V4L2_TUNER_MODE_MONO;
 
-       if (!desc->getmode)
+       if (!desc->getrxsubchans)
                return 0;
        if (chip->radio)
                return 0;
 
        vt->audmode = chip->audmode;
-       vt->rxsubchans = 0;
+       vt->rxsubchans = desc->getrxsubchans(chip);
        vt->capability = V4L2_TUNER_CAP_STEREO |
                V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
 
-       mode = desc->getmode(chip);
-
-       if (mode & V4L2_TUNER_MODE_MONO)
-               vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
-       if (mode & V4L2_TUNER_MODE_STEREO)
-               vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
-       /* Note: for SAP it should be mono/lang2 or stereo/lang2.
-          When this module is converted fully to v4l2, then this
-          should change for those chips that can detect SAP. */
-       if (mode & V4L2_TUNER_MODE_LANG1)
-               vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
-                       V4L2_TUNER_SUB_LANG2;
        return 0;
 }
 
@@ -1868,9 +1908,7 @@ static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fr
        struct CHIPSTATE *chip = to_state(sd);
        struct CHIPDESC *desc = chip->desc;
 
-       chip->mode = 0; /* automatic */
-
-       /* For chips that provide getmode and setmode, and doesn't
+       /* For chips that provide getrxsubchans and setaudmode, and doesn't
           automatically follows the stereo carrier, a kthread is
           created to set the audio standard. In this case, when then
           the video channel is changed, tvaudio starts on MONO mode.
@@ -1879,9 +1917,8 @@ static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fr
           audio carrier.
         */
        if (chip->thread) {
-               desc->setmode(chip, V4L2_TUNER_MODE_MONO);
-               if (chip->prevmode != V4L2_TUNER_MODE_MONO)
-                       chip->prevmode = -1; /* reset previous mode */
+               desc->setaudmode(chip, V4L2_TUNER_MODE_MONO);
+               chip->prevmode = -1; /* reset previous mode */
                mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
        }
        return 0;
@@ -2023,7 +2060,7 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
        chip->thread = NULL;
        init_timer(&chip->wt);
        if (desc->flags & CHIP_NEED_CHECKMODE) {
-               if (!desc->getmode || !desc->setmode) {
+               if (!desc->getrxsubchans || !desc->setaudmode) {
                        /* This shouldn't be happen. Warn user, but keep working
                           without kthread
                         */
index b7867427e5c4a03673789ed80b9ac67643cbfa7e..0d897cb1774a7bc5dd4b10951202f0b8d973955f 100644 (file)
@@ -61,13 +61,20 @@ static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
        int rc;
 
        buffer[0] = addr;
-       if (1 != (rc = i2c_master_send(c, buffer, 1)))
-               v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+       rc = i2c_master_send(c, buffer, 1);
+       if (rc < 0) {
+               v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
+               return rc;
+       }
 
        msleep(10);
 
-       if (1 != (rc = i2c_master_recv(c, buffer, 1)))
-               v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
+       rc = i2c_master_recv(c, buffer, 1);
+       if (rc < 0) {
+               v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
+               return rc;
+       }
 
        v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
 
@@ -279,6 +286,11 @@ static inline void tvp5150_selmux(struct v4l2_subdev *sd)
         * For Composite and TV, it should be the reverse
         */
        val = tvp5150_read(sd, TVP5150_MISC_CTL);
+       if (val < 0) {
+               v4l2_err(sd, "%s: failed with error = %d\n", __func__, val);
+               return;
+       }
+
        if (decoder->input == TVP5150_SVIDEO)
                val = (val & ~0x40) | 0x10;
        else
@@ -676,6 +688,7 @@ static int tvp5150_get_vbi(struct v4l2_subdev *sd,
        v4l2_std_id std = decoder->norm;
        u8 reg;
        int pos, type = 0;
+       int i, ret = 0;
 
        if (std == V4L2_STD_ALL) {
                v4l2_err(sd, "VBI can't be configured without knowing number of lines\n");
@@ -690,13 +703,17 @@ static int tvp5150_get_vbi(struct v4l2_subdev *sd,
 
        reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI;
 
-       pos = tvp5150_read(sd, reg) & 0x0f;
-       if (pos < 0x0f)
-               type = regs[pos].type.vbi_type;
-
-       pos = tvp5150_read(sd, reg + 1) & 0x0f;
-       if (pos < 0x0f)
-               type |= regs[pos].type.vbi_type;
+       for (i = 0; i <= 1; i++) {
+               ret = tvp5150_read(sd, reg + i);
+               if (ret < 0) {
+                       v4l2_err(sd, "%s: failed with error = %d\n",
+                                __func__, ret);
+                       return 0;
+               }
+               pos = ret & 0x0f;
+               if (pos < 0x0f)
+                       type |= regs[pos].type.vbi_type;
+       }
 
        return type;
 }
@@ -1031,13 +1048,21 @@ static int tvp5150_g_chip_ident(struct v4l2_subdev *sd,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
+       int res;
+
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (!v4l2_chip_match_i2c_client(client, &reg->match))
                return -EINVAL;
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
-       reg->val = tvp5150_read(sd, reg->reg & 0xff);
+       res = tvp5150_read(sd, reg->reg & 0xff);
+       if (res < 0) {
+               v4l2_err(sd, "%s: failed with error = %d\n", __func__, res);
+               return res;
+       }
+
+       reg->val = res;
        reg->size = 1;
        return 0;
 }
@@ -1126,7 +1151,8 @@ static int tvp5150_probe(struct i2c_client *c,
 {
        struct tvp5150 *core;
        struct v4l2_subdev *sd;
-       u8 msb_id, lsb_id, msb_rom, lsb_rom;
+       int tvp5150_id[4];
+       int i, res;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(c->adapter,
@@ -1139,26 +1165,37 @@ static int tvp5150_probe(struct i2c_client *c,
        }
        sd = &core->sd;
        v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
+
+       /* 
+        * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID,
+        * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER 
+        */
+       for (i = 0; i < 4; i++) {
+               res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i);
+               if (res < 0)
+                       goto free_core;
+               tvp5150_id[i] = res;
+       }
+
        v4l_info(c, "chip found @ 0x%02x (%s)\n",
                 c->addr << 1, c->adapter->name);
 
-       msb_id = tvp5150_read(sd, TVP5150_MSB_DEV_ID);
-       lsb_id = tvp5150_read(sd, TVP5150_LSB_DEV_ID);
-       msb_rom = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER);
-       lsb_rom = tvp5150_read(sd, TVP5150_ROM_MINOR_VER);
-
-       if (msb_rom == 4 && lsb_rom == 0) { /* Is TVP5150AM1 */
-               v4l2_info(sd, "tvp%02x%02xam1 detected.\n", msb_id, lsb_id);
+       if (tvp5150_id[2] == 4 && tvp5150_id[3] == 0) { /* Is TVP5150AM1 */
+               v4l2_info(sd, "tvp%02x%02xam1 detected.\n",
+                         tvp5150_id[0], tvp5150_id[1]);
 
                /* ITU-T BT.656.4 timing */
                tvp5150_write(sd, TVP5150_REV_SELECT, 0);
        } else {
-               if (msb_rom == 3 || lsb_rom == 0x21) { /* Is TVP5150A */
-                       v4l2_info(sd, "tvp%02x%02xa detected.\n", msb_id, lsb_id);
+               /* Is TVP5150A */
+               if (tvp5150_id[2] == 3 || tvp5150_id[3] == 0x21) {
+                       v4l2_info(sd, "tvp%02x%02xa detected.\n",
+                                 tvp5150_id[2], tvp5150_id[3]);
                } else {
                        v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n",
-                                       msb_id, lsb_id);
-                       v4l2_info(sd, "*** Rom ver is %d.%d\n", msb_rom, lsb_rom);
+                                 tvp5150_id[2], tvp5150_id[3]);
+                       v4l2_info(sd, "*** Rom ver is %d.%d\n",
+                                 tvp5150_id[2], tvp5150_id[3]);
                }
        }
 
@@ -1177,11 +1214,9 @@ static int tvp5150_probe(struct i2c_client *c,
                        V4L2_CID_HUE, -128, 127, 1, 0);
        sd->ctrl_handler = &core->hdl;
        if (core->hdl.error) {
-               int err = core->hdl.error;
-
+               res = core->hdl.error;
                v4l2_ctrl_handler_free(&core->hdl);
-               kfree(core);
-               return err;
+               goto free_core;
        }
        v4l2_ctrl_handler_setup(&core->hdl);
 
@@ -1197,6 +1232,10 @@ static int tvp5150_probe(struct i2c_client *c,
        if (debug > 1)
                tvp5150_log_status(sd);
        return 0;
+
+free_core:
+       kfree(core);
+       return res;
 }
 
 static int tvp5150_remove(struct i2c_client *c)
index 6c197da531b239b7dcc9c38058842c1b9af93c1c..541c9f1e4c6a0dc0667597d527b2a0763ecdc668 100644 (file)
@@ -10,6 +10,7 @@ config USB_VIDEO_CLASS
 config USB_VIDEO_CLASS_INPUT_EVDEV
        bool "UVC input events device support"
        default y
+       depends on USB_VIDEO_CLASS
        depends on USB_VIDEO_CLASS=INPUT || INPUT=y
        ---help---
          This option makes USB Video Class devices register an input device
index af26bbe6f76ecba9726dc01983bda49f36b22c9a..f7061a5ef1d2a1c424c78f486d4348fc96b9b8ff 100644 (file)
@@ -2083,7 +2083,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
        /* Walk the entities list and instantiate controls */
        list_for_each_entry(entity, &dev->entities, list) {
                struct uvc_control *ctrl;
-               unsigned int bControlSize = 0, ncontrols = 0;
+               unsigned int bControlSize = 0, ncontrols;
                __u8 *bmControls = NULL;
 
                if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
@@ -2101,8 +2101,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
                uvc_ctrl_prune_entity(dev, entity);
 
                /* Count supported controls and allocate the controls array */
-               for (i = 0; i < bControlSize; ++i)
-                       ncontrols += hweight8(bmControls[i]);
+               ncontrols = memweight(bmControls, bControlSize);
                if (ncontrols == 0)
                        continue;
 
index 759bef8897e9d9d4645d837a451b2b2c96fee92d..f00db3060e0e36e005b306a53f393cc55071b101 100644 (file)
@@ -1051,7 +1051,7 @@ static long uvc_v4l2_ioctl(struct file *file,
 {
        if (uvc_trace_param & UVC_TRACE_IOCTL) {
                uvc_printk(KERN_DEBUG, "uvc_v4l2_ioctl(");
-               v4l_printk_ioctl(cmd);
+               v4l_printk_ioctl(NULL, cmd);
                printk(")\n");
        }
 
index b76b0ac0958f8d2d27a5a7193c623badfac5ee67..7ac4347ca09e72dc4bb2abb751779f3053a338c7 100644 (file)
@@ -1188,7 +1188,11 @@ static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
        u8 *mem;
        int len, ret;
 
-       if (urb->actual_length == 0)
+       /*
+        * Ignore ZLPs if they're not part of a frame, otherwise process them
+        * to trigger the end of payload detection.
+        */
+       if (urb->actual_length == 0 && stream->bulk.header_size == 0)
                return;
 
        mem = urb->transfer_buffer;
@@ -1594,7 +1598,7 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
                        psize = le16_to_cpu(ep->desc.wMaxPacketSize);
                        psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
                        if (psize >= bandwidth && psize <= best_psize) {
-                               altsetting = i;
+                               altsetting = alts->desc.bAlternateSetting;
                                best_psize = psize;
                                best_ep = ep;
                        }
index 5327ad3a63907a87f3da587812269b60edef5880..ac365cfb3706b16a66f8df7deb9e28fe52f72737 100644 (file)
@@ -327,7 +327,7 @@ struct v4l2_buffer32 {
                compat_caddr_t  planes;
        } m;
        __u32                   length;
-       __u32                   input;
+       __u32                   reserved2;
        __u32                   reserved;
 };
 
@@ -387,8 +387,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                get_user(kp->index, &up->index) ||
                get_user(kp->type, &up->type) ||
                get_user(kp->flags, &up->flags) ||
-               get_user(kp->memory, &up->memory) ||
-               get_user(kp->input, &up->input))
+               get_user(kp->memory, &up->memory))
                        return -EFAULT;
 
        if (V4L2_TYPE_IS_OUTPUT(kp->type))
@@ -472,8 +471,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                put_user(kp->index, &up->index) ||
                put_user(kp->type, &up->type) ||
                put_user(kp->flags, &up->flags) ||
-               put_user(kp->memory, &up->memory) ||
-               put_user(kp->input, &up->input))
+               put_user(kp->memory, &up->memory))
                        return -EFAULT;
 
        if (put_user(kp->bytesused, &up->bytesused) ||
@@ -482,6 +480,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
                copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
                put_user(kp->sequence, &up->sequence) ||
+               put_user(kp->reserved2, &up->reserved2) ||
                put_user(kp->reserved, &up->reserved))
                        return -EFAULT;
 
index 0cbada18f6f57376d980d34345335279499fec03..af70f931727c3803ac4739ff101342b3882cdd4d 100644 (file)
@@ -46,6 +46,29 @@ static ssize_t show_index(struct device *cd,
        return sprintf(buf, "%i\n", vdev->index);
 }
 
+static ssize_t show_debug(struct device *cd,
+                        struct device_attribute *attr, char *buf)
+{
+       struct video_device *vdev = to_video_device(cd);
+
+       return sprintf(buf, "%i\n", vdev->debug);
+}
+
+static ssize_t set_debug(struct device *cd, struct device_attribute *attr,
+                  const char *buf, size_t len)
+{
+       struct video_device *vdev = to_video_device(cd);
+       int res = 0;
+       u16 value;
+
+       res = kstrtou16(buf, 0, &value);
+       if (res)
+               return res;
+
+       vdev->debug = value;
+       return len;
+}
+
 static ssize_t show_name(struct device *cd,
                         struct device_attribute *attr, char *buf)
 {
@@ -56,6 +79,7 @@ static ssize_t show_name(struct device *cd,
 
 static struct device_attribute video_device_attrs[] = {
        __ATTR(name, S_IRUGO, show_name, NULL),
+       __ATTR(debug, 0644, show_debug, set_debug),
        __ATTR(index, S_IRUGO, show_index, NULL),
        __ATTR_NULL
 };
@@ -281,6 +305,9 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf,
                ret = vdev->fops->read(filp, buf, sz, off);
        if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
                mutex_unlock(vdev->lock);
+       if (vdev->debug)
+               printk(KERN_DEBUG "%s: read: %zd (%d)\n",
+                       video_device_node_name(vdev), sz, ret);
        return ret;
 }
 
@@ -299,6 +326,9 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf,
                ret = vdev->fops->write(filp, buf, sz, off);
        if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
                mutex_unlock(vdev->lock);
+       if (vdev->debug)
+               printk(KERN_DEBUG "%s: write: %zd (%d)\n",
+                       video_device_node_name(vdev), sz, ret);
        return ret;
 }
 
@@ -315,6 +345,9 @@ static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
                ret = vdev->fops->poll(filp, poll);
        if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
                mutex_unlock(vdev->lock);
+       if (vdev->debug)
+               printk(KERN_DEBUG "%s: poll: %08x\n",
+                       video_device_node_name(vdev), ret);
        return ret;
 }
 
@@ -324,20 +357,14 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        int ret = -ENODEV;
 
        if (vdev->fops->unlocked_ioctl) {
-               bool locked = false;
+               struct mutex *lock = v4l2_ioctl_get_lock(vdev, cmd);
 
-               if (vdev->lock) {
-                       /* always lock unless the cmd is marked as "don't use lock" */
-                       locked = !v4l2_is_known_ioctl(cmd) ||
-                                !test_bit(_IOC_NR(cmd), vdev->disable_locking);
-
-                       if (locked && mutex_lock_interruptible(vdev->lock))
-                               return -ERESTARTSYS;
-               }
+               if (lock && mutex_lock_interruptible(lock))
+                       return -ERESTARTSYS;
                if (video_is_registered(vdev))
                        ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
-               if (locked)
-                       mutex_unlock(vdev->lock);
+               if (lock)
+                       mutex_unlock(lock);
        } else if (vdev->fops->ioctl) {
                /* This code path is a replacement for the BKL. It is a major
                 * hack but it will have to do for those drivers that are not
@@ -385,12 +412,17 @@ static unsigned long v4l2_get_unmapped_area(struct file *filp,
                unsigned long flags)
 {
        struct video_device *vdev = video_devdata(filp);
+       int ret;
 
        if (!vdev->fops->get_unmapped_area)
                return -ENOSYS;
        if (!video_is_registered(vdev))
                return -ENODEV;
-       return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
+       ret = vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
+       if (vdev->debug)
+               printk(KERN_DEBUG "%s: get_unmapped_area (%d)\n",
+                       video_device_node_name(vdev), ret);
+       return ret;
 }
 #endif
 
@@ -408,6 +440,9 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
                ret = vdev->fops->mmap(filp, vm);
        if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
                mutex_unlock(vdev->lock);
+       if (vdev->debug)
+               printk(KERN_DEBUG "%s: mmap (%d)\n",
+                       video_device_node_name(vdev), ret);
        return ret;
 }
 
@@ -446,6 +481,9 @@ err:
        /* decrease the refcount in case of an error */
        if (ret)
                video_put(vdev);
+       if (vdev->debug)
+               printk(KERN_DEBUG "%s: open (%d)\n",
+                       video_device_node_name(vdev), ret);
        return ret;
 }
 
@@ -465,6 +503,9 @@ static int v4l2_release(struct inode *inode, struct file *filp)
        /* decrease the refcount unconditionally since the release()
           return value is ignored. */
        video_put(vdev);
+       if (vdev->debug)
+               printk(KERN_DEBUG "%s: release\n",
+                       video_device_node_name(vdev));
        return ret;
 }
 
index d7fa8962d8b3129940514cb487d0d75a8931dbdd..70e0efb127a6d6a3b6933cb703bb3c3f50f004d0 100644 (file)
 #include <media/v4l2-event.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
-
-#define dbgarg(cmd, fmt, arg...) \
-               do {                                                    \
-                   if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {            \
-                       printk(KERN_DEBUG "%s: ",  vfd->name);          \
-                       v4l_printk_ioctl(cmd);                          \
-                       printk(" " fmt,  ## arg);                       \
-                   }                                                   \
-               } while (0)
-
-#define dbgarg2(fmt, arg...) \
-               do {                                                    \
-                   if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)              \
-                       printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\
-               } while (0)
-
-#define dbgarg3(fmt, arg...) \
-               do {                                                    \
-                   if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)              \
-                       printk(KERN_CONT "%s: " fmt, vfd->name, ## arg);\
-               } while (0)
+#include <media/videobuf2-core.h>
 
 /* Zero out the end of the struct pointed to by p.  Everything after, but
  * not including, the specified field is cleared. */
@@ -183,207 +163,507 @@ static const char *v4l2_memory_names[] = {
 /* ------------------------------------------------------------------ */
 /* debug help functions                                               */
 
-struct v4l2_ioctl_info {
-       unsigned int ioctl;
-       u16 flags;
-       const char * const name;
-};
+static void v4l_print_querycap(const void *arg, bool write_only)
+{
+       const struct v4l2_capability *p = arg;
 
-/* This control needs a priority check */
-#define INFO_FL_PRIO   (1 << 0)
-/* This control can be valid if the filehandle passes a control handler. */
-#define INFO_FL_CTRL   (1 << 1)
+       pr_cont("driver=%s, card=%s, bus=%s, version=0x%08x, "
+               "capabilities=0x%08x, device_caps=0x%08x\n",
+               p->driver, p->card, p->bus_info,
+               p->version, p->capabilities, p->device_caps);
+}
+
+static void v4l_print_enuminput(const void *arg, bool write_only)
+{
+       const struct v4l2_input *p = arg;
 
-#define IOCTL_INFO(_ioctl, _flags) [_IOC_NR(_ioctl)] = {       \
-       .ioctl = _ioctl,                                        \
-       .flags = _flags,                                        \
-       .name = #_ioctl,                                        \
+       pr_cont("index=%u, name=%s, type=%u, audioset=0x%x, tuner=%u, "
+               "std=0x%08Lx, status=0x%x, capabilities=0x%x\n",
+               p->index, p->name, p->type, p->audioset, p->tuner,
+               (unsigned long long)p->std, p->status, p->capabilities);
 }
 
-static struct v4l2_ioctl_info v4l2_ioctls[] = {
-       IOCTL_INFO(VIDIOC_QUERYCAP, 0),
-       IOCTL_INFO(VIDIOC_ENUM_FMT, 0),
-       IOCTL_INFO(VIDIOC_G_FMT, 0),
-       IOCTL_INFO(VIDIOC_S_FMT, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_REQBUFS, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_QUERYBUF, 0),
-       IOCTL_INFO(VIDIOC_G_FBUF, 0),
-       IOCTL_INFO(VIDIOC_S_FBUF, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_OVERLAY, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_QBUF, 0),
-       IOCTL_INFO(VIDIOC_DQBUF, 0),
-       IOCTL_INFO(VIDIOC_STREAMON, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_STREAMOFF, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_G_PARM, 0),
-       IOCTL_INFO(VIDIOC_S_PARM, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_G_STD, 0),
-       IOCTL_INFO(VIDIOC_S_STD, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_ENUMSTD, 0),
-       IOCTL_INFO(VIDIOC_ENUMINPUT, 0),
-       IOCTL_INFO(VIDIOC_G_CTRL, INFO_FL_CTRL),
-       IOCTL_INFO(VIDIOC_S_CTRL, INFO_FL_PRIO | INFO_FL_CTRL),
-       IOCTL_INFO(VIDIOC_G_TUNER, 0),
-       IOCTL_INFO(VIDIOC_S_TUNER, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_G_AUDIO, 0),
-       IOCTL_INFO(VIDIOC_S_AUDIO, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_QUERYCTRL, INFO_FL_CTRL),
-       IOCTL_INFO(VIDIOC_QUERYMENU, INFO_FL_CTRL),
-       IOCTL_INFO(VIDIOC_G_INPUT, 0),
-       IOCTL_INFO(VIDIOC_S_INPUT, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_G_OUTPUT, 0),
-       IOCTL_INFO(VIDIOC_S_OUTPUT, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_ENUMOUTPUT, 0),
-       IOCTL_INFO(VIDIOC_G_AUDOUT, 0),
-       IOCTL_INFO(VIDIOC_S_AUDOUT, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_G_MODULATOR, 0),
-       IOCTL_INFO(VIDIOC_S_MODULATOR, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_G_FREQUENCY, 0),
-       IOCTL_INFO(VIDIOC_S_FREQUENCY, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_CROPCAP, 0),
-       IOCTL_INFO(VIDIOC_G_CROP, 0),
-       IOCTL_INFO(VIDIOC_S_CROP, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_G_SELECTION, 0),
-       IOCTL_INFO(VIDIOC_S_SELECTION, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_G_JPEGCOMP, 0),
-       IOCTL_INFO(VIDIOC_S_JPEGCOMP, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_QUERYSTD, 0),
-       IOCTL_INFO(VIDIOC_TRY_FMT, 0),
-       IOCTL_INFO(VIDIOC_ENUMAUDIO, 0),
-       IOCTL_INFO(VIDIOC_ENUMAUDOUT, 0),
-       IOCTL_INFO(VIDIOC_G_PRIORITY, 0),
-       IOCTL_INFO(VIDIOC_S_PRIORITY, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_G_SLICED_VBI_CAP, 0),
-       IOCTL_INFO(VIDIOC_LOG_STATUS, 0),
-       IOCTL_INFO(VIDIOC_G_EXT_CTRLS, INFO_FL_CTRL),
-       IOCTL_INFO(VIDIOC_S_EXT_CTRLS, INFO_FL_PRIO | INFO_FL_CTRL),
-       IOCTL_INFO(VIDIOC_TRY_EXT_CTRLS, 0),
-       IOCTL_INFO(VIDIOC_ENUM_FRAMESIZES, 0),
-       IOCTL_INFO(VIDIOC_ENUM_FRAMEINTERVALS, 0),
-       IOCTL_INFO(VIDIOC_G_ENC_INDEX, 0),
-       IOCTL_INFO(VIDIOC_ENCODER_CMD, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_TRY_ENCODER_CMD, 0),
-       IOCTL_INFO(VIDIOC_DECODER_CMD, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_TRY_DECODER_CMD, 0),
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       IOCTL_INFO(VIDIOC_DBG_S_REGISTER, 0),
-       IOCTL_INFO(VIDIOC_DBG_G_REGISTER, 0),
-#endif
-       IOCTL_INFO(VIDIOC_DBG_G_CHIP_IDENT, 0),
-       IOCTL_INFO(VIDIOC_S_HW_FREQ_SEEK, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_ENUM_DV_PRESETS, 0),
-       IOCTL_INFO(VIDIOC_S_DV_PRESET, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_G_DV_PRESET, 0),
-       IOCTL_INFO(VIDIOC_QUERY_DV_PRESET, 0),
-       IOCTL_INFO(VIDIOC_S_DV_TIMINGS, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_G_DV_TIMINGS, 0),
-       IOCTL_INFO(VIDIOC_DQEVENT, 0),
-       IOCTL_INFO(VIDIOC_SUBSCRIBE_EVENT, 0),
-       IOCTL_INFO(VIDIOC_UNSUBSCRIBE_EVENT, 0),
-       IOCTL_INFO(VIDIOC_CREATE_BUFS, INFO_FL_PRIO),
-       IOCTL_INFO(VIDIOC_PREPARE_BUF, 0),
-       IOCTL_INFO(VIDIOC_ENUM_DV_TIMINGS, 0),
-       IOCTL_INFO(VIDIOC_QUERY_DV_TIMINGS, 0),
-       IOCTL_INFO(VIDIOC_DV_TIMINGS_CAP, 0),
-};
-#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+static void v4l_print_enumoutput(const void *arg, bool write_only)
+{
+       const struct v4l2_output *p = arg;
 
-bool v4l2_is_known_ioctl(unsigned int cmd)
+       pr_cont("index=%u, name=%s, type=%u, audioset=0x%x, "
+               "modulator=%u, std=0x%08Lx, capabilities=0x%x\n",
+               p->index, p->name, p->type, p->audioset, p->modulator,
+               (unsigned long long)p->std, p->capabilities);
+}
+
+static void v4l_print_audio(const void *arg, bool write_only)
 {
-       if (_IOC_NR(cmd) >= V4L2_IOCTLS)
-               return false;
-       return v4l2_ioctls[_IOC_NR(cmd)].ioctl == cmd;
+       const struct v4l2_audio *p = arg;
+
+       if (write_only)
+               pr_cont("index=%u, mode=0x%x\n", p->index, p->mode);
+       else
+               pr_cont("index=%u, name=%s, capability=0x%x, mode=0x%x\n",
+                       p->index, p->name, p->capability, p->mode);
 }
 
-/* Common ioctl debug function. This function can be used by
-   external ioctl messages as well as internal V4L ioctl */
-void v4l_printk_ioctl(unsigned int cmd)
+static void v4l_print_audioout(const void *arg, bool write_only)
 {
-       char *dir, *type;
+       const struct v4l2_audioout *p = arg;
 
-       switch (_IOC_TYPE(cmd)) {
-       case 'd':
-               type = "v4l2_int";
+       if (write_only)
+               pr_cont("index=%u\n", p->index);
+       else
+               pr_cont("index=%u, name=%s, capability=0x%x, mode=0x%x\n",
+                       p->index, p->name, p->capability, p->mode);
+}
+
+static void v4l_print_fmtdesc(const void *arg, bool write_only)
+{
+       const struct v4l2_fmtdesc *p = arg;
+
+       pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%c%c%c%c, description='%s'\n",
+               p->index, prt_names(p->type, v4l2_type_names),
+               p->flags, (p->pixelformat & 0xff),
+               (p->pixelformat >>  8) & 0xff,
+               (p->pixelformat >> 16) & 0xff,
+               (p->pixelformat >> 24) & 0xff,
+               p->description);
+}
+
+static void v4l_print_format(const void *arg, bool write_only)
+{
+       const struct v4l2_format *p = arg;
+       const struct v4l2_pix_format *pix;
+       const struct v4l2_pix_format_mplane *mp;
+       const struct v4l2_vbi_format *vbi;
+       const struct v4l2_sliced_vbi_format *sliced;
+       const struct v4l2_window *win;
+       const struct v4l2_clip *clip;
+       unsigned i;
+
+       pr_cont("type=%s", prt_names(p->type, v4l2_type_names));
+       switch (p->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               pix = &p->fmt.pix;
+               pr_cont(", width=%u, height=%u, "
+                       "pixelformat=%c%c%c%c, field=%s, "
+                       "bytesperline=%u sizeimage=%u, colorspace=%d\n",
+                       pix->width, pix->height,
+                       (pix->pixelformat & 0xff),
+                       (pix->pixelformat >>  8) & 0xff,
+                       (pix->pixelformat >> 16) & 0xff,
+                       (pix->pixelformat >> 24) & 0xff,
+                       prt_names(pix->field, v4l2_field_names),
+                       pix->bytesperline, pix->sizeimage,
+                       pix->colorspace);
                break;
-       case 'V':
-               if (_IOC_NR(cmd) >= V4L2_IOCTLS) {
-                       type = "v4l2";
-                       break;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               mp = &p->fmt.pix_mp;
+               pr_cont(", width=%u, height=%u, "
+                       "format=%c%c%c%c, field=%s, "
+                       "colorspace=%d, num_planes=%u\n",
+                       mp->width, mp->height,
+                       (mp->pixelformat & 0xff),
+                       (mp->pixelformat >>  8) & 0xff,
+                       (mp->pixelformat >> 16) & 0xff,
+                       (mp->pixelformat >> 24) & 0xff,
+                       prt_names(mp->field, v4l2_field_names),
+                       mp->colorspace, mp->num_planes);
+               for (i = 0; i < mp->num_planes; i++)
+                       printk(KERN_DEBUG "plane %u: bytesperline=%u sizeimage=%u\n", i,
+                                       mp->plane_fmt[i].bytesperline,
+                                       mp->plane_fmt[i].sizeimage);
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+               win = &p->fmt.win;
+               pr_cont(", wxh=%dx%d, x,y=%d,%d, field=%s, "
+                       "chromakey=0x%08x, bitmap=%p, "
+                       "global_alpha=0x%02x\n",
+                       win->w.width, win->w.height,
+                       win->w.left, win->w.top,
+                       prt_names(win->field, v4l2_field_names),
+                       win->chromakey, win->bitmap, win->global_alpha);
+               clip = win->clips;
+               for (i = 0; i < win->clipcount; i++) {
+                       printk(KERN_DEBUG "clip %u: wxh=%dx%d, x,y=%d,%d\n",
+                                       i, clip->c.width, clip->c.height,
+                                       clip->c.left, clip->c.top);
+                       clip = clip->next;
                }
-               printk("%s", v4l2_ioctls[_IOC_NR(cmd)].name);
-               return;
-       default:
-               type = "unknown";
+               break;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+               vbi = &p->fmt.vbi;
+               pr_cont(", sampling_rate=%u, offset=%u, samples_per_line=%u, "
+                       "sample_format=%c%c%c%c, start=%u,%u, count=%u,%u\n",
+                       vbi->sampling_rate, vbi->offset,
+                       vbi->samples_per_line,
+                       (vbi->sample_format & 0xff),
+                       (vbi->sample_format >>  8) & 0xff,
+                       (vbi->sample_format >> 16) & 0xff,
+                       (vbi->sample_format >> 24) & 0xff,
+                       vbi->start[0], vbi->start[1],
+                       vbi->count[0], vbi->count[1]);
+               break;
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+               sliced = &p->fmt.sliced;
+               pr_cont(", service_set=0x%08x, io_size=%d\n",
+                               sliced->service_set, sliced->io_size);
+               for (i = 0; i < 24; i++)
+                       printk(KERN_DEBUG "line[%02u]=0x%04x, 0x%04x\n", i,
+                               sliced->service_lines[0][i],
+                               sliced->service_lines[1][i]);
+               break;
+       case V4L2_BUF_TYPE_PRIVATE:
+               pr_cont("\n");
+               break;
        }
+}
 
-       switch (_IOC_DIR(cmd)) {
-       case _IOC_NONE:              dir = "--"; break;
-       case _IOC_READ:              dir = "r-"; break;
-       case _IOC_WRITE:             dir = "-w"; break;
-       case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
-       default:                     dir = "*ERR*"; break;
-       }
-       printk("%s ioctl '%c', dir=%s, #%d (0x%08x)",
-               type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
+static void v4l_print_framebuffer(const void *arg, bool write_only)
+{
+       const struct v4l2_framebuffer *p = arg;
+
+       pr_cont("capability=0x%x, flags=0x%x, base=0x%p, width=%u, "
+               "height=%u, pixelformat=%c%c%c%c, "
+               "bytesperline=%u sizeimage=%u, colorspace=%d\n",
+                       p->capability, p->flags, p->base,
+                       p->fmt.width, p->fmt.height,
+                       (p->fmt.pixelformat & 0xff),
+                       (p->fmt.pixelformat >>  8) & 0xff,
+                       (p->fmt.pixelformat >> 16) & 0xff,
+                       (p->fmt.pixelformat >> 24) & 0xff,
+                       p->fmt.bytesperline, p->fmt.sizeimage,
+                       p->fmt.colorspace);
+}
+
+static void v4l_print_buftype(const void *arg, bool write_only)
+{
+       pr_cont("type=%s\n", prt_names(*(u32 *)arg, v4l2_type_names));
+}
+
+static void v4l_print_modulator(const void *arg, bool write_only)
+{
+       const struct v4l2_modulator *p = arg;
+
+       if (write_only)
+               pr_cont("index=%u, txsubchans=0x%x", p->index, p->txsubchans);
+       else
+               pr_cont("index=%u, name=%s, capability=0x%x, "
+                       "rangelow=%u, rangehigh=%u, txsubchans=0x%x\n",
+                       p->index, p->name, p->capability,
+                       p->rangelow, p->rangehigh, p->txsubchans);
+}
+
+static void v4l_print_tuner(const void *arg, bool write_only)
+{
+       const struct v4l2_tuner *p = arg;
+
+       if (write_only)
+               pr_cont("index=%u, audmode=%u\n", p->index, p->audmode);
+       else
+               pr_cont("index=%u, name=%s, type=%u, capability=0x%x, "
+                       "rangelow=%u, rangehigh=%u, signal=%u, afc=%d, "
+                       "rxsubchans=0x%x, audmode=%u\n",
+                       p->index, p->name, p->type,
+                       p->capability, p->rangelow,
+                       p->rangehigh, p->signal, p->afc,
+                       p->rxsubchans, p->audmode);
+}
+
+static void v4l_print_frequency(const void *arg, bool write_only)
+{
+       const struct v4l2_frequency *p = arg;
+
+       pr_cont("tuner=%u, type=%u, frequency=%u\n",
+                               p->tuner, p->type, p->frequency);
+}
+
+static void v4l_print_standard(const void *arg, bool write_only)
+{
+       const struct v4l2_standard *p = arg;
+
+       pr_cont("index=%u, id=0x%Lx, name=%s, fps=%u/%u, "
+               "framelines=%u\n", p->index,
+               (unsigned long long)p->id, p->name,
+               p->frameperiod.numerator,
+               p->frameperiod.denominator,
+               p->framelines);
+}
+
+static void v4l_print_std(const void *arg, bool write_only)
+{
+       pr_cont("std=0x%08Lx\n", *(const long long unsigned *)arg);
+}
+
+static void v4l_print_hw_freq_seek(const void *arg, bool write_only)
+{
+       const struct v4l2_hw_freq_seek *p = arg;
+
+       pr_cont("tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u\n",
+               p->tuner, p->type, p->seek_upward, p->wrap_around, p->spacing);
 }
-EXPORT_SYMBOL(v4l_printk_ioctl);
 
-static void dbgbuf(unsigned int cmd, struct video_device *vfd,
-                                       struct v4l2_buffer *p)
+static void v4l_print_requestbuffers(const void *arg, bool write_only)
 {
-       struct v4l2_timecode *tc = &p->timecode;
-       struct v4l2_plane *plane;
+       const struct v4l2_requestbuffers *p = arg;
+
+       pr_cont("count=%d, type=%s, memory=%s\n",
+               p->count,
+               prt_names(p->type, v4l2_type_names),
+               prt_names(p->memory, v4l2_memory_names));
+}
+
+static void v4l_print_buffer(const void *arg, bool write_only)
+{
+       const struct v4l2_buffer *p = arg;
+       const struct v4l2_timecode *tc = &p->timecode;
+       const struct v4l2_plane *plane;
        int i;
 
-       dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
-               "flags=0x%08d, field=%0d, sequence=%d, memory=%s\n",
+       pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, "
+               "flags=0x%08x, field=%s, sequence=%d, memory=%s",
                        p->timestamp.tv_sec / 3600,
                        (int)(p->timestamp.tv_sec / 60) % 60,
                        (int)(p->timestamp.tv_sec % 60),
                        (long)p->timestamp.tv_usec,
                        p->index,
                        prt_names(p->type, v4l2_type_names),
-                       p->flags, p->field, p->sequence,
-                       prt_names(p->memory, v4l2_memory_names));
+                       p->flags, prt_names(p->field, v4l2_field_names),
+                       p->sequence, prt_names(p->memory, v4l2_memory_names));
 
        if (V4L2_TYPE_IS_MULTIPLANAR(p->type) && p->m.planes) {
+               pr_cont("\n");
                for (i = 0; i < p->length; ++i) {
                        plane = &p->m.planes[i];
-                       dbgarg2("plane %d: bytesused=%d, data_offset=0x%08x "
-                               "offset/userptr=0x%08lx, length=%d\n",
+                       printk(KERN_DEBUG
+                               "plane %d: bytesused=%d, data_offset=0x%08x "
+                               "offset/userptr=0x%lx, length=%d\n",
                                i, plane->bytesused, plane->data_offset,
                                plane->m.userptr, plane->length);
                }
        } else {
-               dbgarg2("bytesused=%d, offset/userptr=0x%08lx, length=%d\n",
+               pr_cont("bytesused=%d, offset/userptr=0x%lx, length=%d\n",
                        p->bytesused, p->m.userptr, p->length);
        }
 
-       dbgarg2("timecode=%02d:%02d:%02d type=%d, "
-               "flags=0x%08d, frames=%d, userbits=0x%08x\n",
+       printk(KERN_DEBUG "timecode=%02d:%02d:%02d type=%d, "
+               "flags=0x%08x, frames=%d, userbits=0x%08x\n",
                        tc->hours, tc->minutes, tc->seconds,
                        tc->type, tc->flags, tc->frames, *(__u32 *)tc->userbits);
 }
 
-static inline void dbgrect(struct video_device *vfd, char *s,
-                                                       struct v4l2_rect *r)
+static void v4l_print_create_buffers(const void *arg, bool write_only)
 {
-       dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top,
-                                               r->width, r->height);
-};
+       const struct v4l2_create_buffers *p = arg;
+
+       pr_cont("index=%d, count=%d, memory=%s, ",
+                       p->index, p->count,
+                       prt_names(p->memory, v4l2_memory_names));
+       v4l_print_format(&p->format, write_only);
+}
+
+static void v4l_print_streamparm(const void *arg, bool write_only)
+{
+       const struct v4l2_streamparm *p = arg;
+
+       pr_cont("type=%s", prt_names(p->type, v4l2_type_names));
+
+       if (p->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           p->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               const struct v4l2_captureparm *c = &p->parm.capture;
+
+               pr_cont(", capability=0x%x, capturemode=0x%x, timeperframe=%d/%d, "
+                       "extendedmode=%d, readbuffers=%d\n",
+                       c->capability, c->capturemode,
+                       c->timeperframe.numerator, c->timeperframe.denominator,
+                       c->extendedmode, c->readbuffers);
+       } else if (p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+                  p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               const struct v4l2_outputparm *c = &p->parm.output;
+
+               pr_cont(", capability=0x%x, outputmode=0x%x, timeperframe=%d/%d, "
+                       "extendedmode=%d, writebuffers=%d\n",
+                       c->capability, c->outputmode,
+                       c->timeperframe.numerator, c->timeperframe.denominator,
+                       c->extendedmode, c->writebuffers);
+       }
+}
+
+static void v4l_print_queryctrl(const void *arg, bool write_only)
+{
+       const struct v4l2_queryctrl *p = arg;
+
+       pr_cont("id=0x%x, type=%d, name=%s, min/max=%d/%d, "
+               "step=%d, default=%d, flags=0x%08x\n",
+                       p->id, p->type, p->name,
+                       p->minimum, p->maximum,
+                       p->step, p->default_value, p->flags);
+}
+
+static void v4l_print_querymenu(const void *arg, bool write_only)
+{
+       const struct v4l2_querymenu *p = arg;
+
+       pr_cont("id=0x%x, index=%d\n", p->id, p->index);
+}
+
+static void v4l_print_control(const void *arg, bool write_only)
+{
+       const struct v4l2_control *p = arg;
+
+       pr_cont("id=0x%x, value=%d\n", p->id, p->value);
+}
+
+static void v4l_print_ext_controls(const void *arg, bool write_only)
+{
+       const struct v4l2_ext_controls *p = arg;
+       int i;
 
-static void dbgtimings(struct video_device *vfd,
-                       const struct v4l2_dv_timings *p)
+       pr_cont("class=0x%x, count=%d, error_idx=%d",
+                       p->ctrl_class, p->count, p->error_idx);
+       for (i = 0; i < p->count; i++) {
+               if (p->controls[i].size)
+                       pr_cont(", id/val=0x%x/0x%x",
+                               p->controls[i].id, p->controls[i].value);
+               else
+                       pr_cont(", id/size=0x%x/%u",
+                               p->controls[i].id, p->controls[i].size);
+       }
+       pr_cont("\n");
+}
+
+static void v4l_print_cropcap(const void *arg, bool write_only)
+{
+       const struct v4l2_cropcap *p = arg;
+
+       pr_cont("type=%s, bounds wxh=%dx%d, x,y=%d,%d, "
+               "defrect wxh=%dx%d, x,y=%d,%d\n, "
+               "pixelaspect %d/%d\n",
+               prt_names(p->type, v4l2_type_names),
+               p->bounds.width, p->bounds.height,
+               p->bounds.left, p->bounds.top,
+               p->defrect.width, p->defrect.height,
+               p->defrect.left, p->defrect.top,
+               p->pixelaspect.numerator, p->pixelaspect.denominator);
+}
+
+static void v4l_print_crop(const void *arg, bool write_only)
+{
+       const struct v4l2_crop *p = arg;
+
+       pr_cont("type=%s, wxh=%dx%d, x,y=%d,%d\n",
+               prt_names(p->type, v4l2_type_names),
+               p->c.width, p->c.height,
+               p->c.left, p->c.top);
+}
+
+static void v4l_print_selection(const void *arg, bool write_only)
+{
+       const struct v4l2_selection *p = arg;
+
+       pr_cont("type=%s, target=%d, flags=0x%x, wxh=%dx%d, x,y=%d,%d\n",
+               prt_names(p->type, v4l2_type_names),
+               p->target, p->flags,
+               p->r.width, p->r.height, p->r.left, p->r.top);
+}
+
+static void v4l_print_jpegcompression(const void *arg, bool write_only)
+{
+       const struct v4l2_jpegcompression *p = arg;
+
+       pr_cont("quality=%d, APPn=%d, APP_len=%d, "
+               "COM_len=%d, jpeg_markers=0x%x\n",
+               p->quality, p->APPn, p->APP_len,
+               p->COM_len, p->jpeg_markers);
+}
+
+static void v4l_print_enc_idx(const void *arg, bool write_only)
+{
+       const struct v4l2_enc_idx *p = arg;
+
+       pr_cont("entries=%d, entries_cap=%d\n",
+                       p->entries, p->entries_cap);
+}
+
+static void v4l_print_encoder_cmd(const void *arg, bool write_only)
+{
+       const struct v4l2_encoder_cmd *p = arg;
+
+       pr_cont("cmd=%d, flags=0x%x\n",
+                       p->cmd, p->flags);
+}
+
+static void v4l_print_decoder_cmd(const void *arg, bool write_only)
+{
+       const struct v4l2_decoder_cmd *p = arg;
+
+       pr_cont("cmd=%d, flags=0x%x\n", p->cmd, p->flags);
+
+       if (p->cmd == V4L2_DEC_CMD_START)
+               pr_info("speed=%d, format=%u\n",
+                               p->start.speed, p->start.format);
+       else if (p->cmd == V4L2_DEC_CMD_STOP)
+               pr_info("pts=%llu\n", p->stop.pts);
+}
+
+static void v4l_print_dbg_chip_ident(const void *arg, bool write_only)
 {
+       const struct v4l2_dbg_chip_ident *p = arg;
+
+       pr_cont("type=%u, ", p->match.type);
+       if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER)
+               pr_cont("name=%s, ", p->match.name);
+       else
+               pr_cont("addr=%u, ", p->match.addr);
+       pr_cont("chip_ident=%u, revision=0x%x\n",
+                       p->ident, p->revision);
+}
+
+static void v4l_print_dbg_register(const void *arg, bool write_only)
+{
+       const struct v4l2_dbg_register *p = arg;
+
+       pr_cont("type=%u, ", p->match.type);
+       if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER)
+               pr_cont("name=%s, ", p->match.name);
+       else
+               pr_cont("addr=%u, ", p->match.addr);
+       pr_cont("reg=0x%llx, val=0x%llx\n",
+                       p->reg, p->val);
+}
+
+static void v4l_print_dv_enum_presets(const void *arg, bool write_only)
+{
+       const struct v4l2_dv_enum_preset *p = arg;
+
+       pr_cont("index=%u, preset=%u, name=%s, width=%u, height=%u\n",
+                       p->index, p->preset, p->name, p->width, p->height);
+}
+
+static void v4l_print_dv_preset(const void *arg, bool write_only)
+{
+       const struct v4l2_dv_preset *p = arg;
+
+       pr_cont("preset=%u\n", p->preset);
+}
+
+static void v4l_print_dv_timings(const void *arg, bool write_only)
+{
+       const struct v4l2_dv_timings *p = arg;
+
        switch (p->type) {
        case V4L2_DV_BT_656_1120:
-               dbgarg2("bt-656/1120:interlaced=%d,"
-                               " pixelclock=%lld,"
-                               " width=%d, height=%d, polarities=%x,"
-                               " hfrontporch=%d, hsync=%d,"
-                               " hbackporch=%d, vfrontporch=%d,"
-                               " vsync=%d, vbackporch=%d,"
-                               " il_vfrontporch=%d, il_vsync=%d,"
-                               " il_vbackporch=%d, standards=%x, flags=%x\n",
+               pr_cont("type=bt-656/1120, interlaced=%u, "
+                       "pixelclock=%llu, "
+                       "width=%u, height=%u, polarities=0x%x, "
+                       "hfrontporch=%u, hsync=%u, "
+                       "hbackporch=%u, vfrontporch=%u, "
+                       "vsync=%u, vbackporch=%u, "
+                       "il_vfrontporch=%u, il_vsync=%u, "
+                       "il_vbackporch=%u, standards=0x%x, flags=0x%x\n",
                                p->bt.interlaced, p->bt.pixelclock,
                                p->bt.width, p->bt.height,
                                p->bt.polarities, p->bt.hfrontporch,
@@ -394,67 +674,173 @@ static void dbgtimings(struct video_device *vfd,
                                p->bt.standards, p->bt.flags);
                break;
        default:
-               dbgarg2("Unknown type %d!\n", p->type);
+               pr_cont("type=%d\n", p->type);
                break;
        }
 }
 
-static inline void v4l_print_pix_fmt(struct video_device *vfd,
-                                               struct v4l2_pix_format *fmt)
+static void v4l_print_enum_dv_timings(const void *arg, bool write_only)
 {
-       dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, "
-               "bytesperline=%d sizeimage=%d, colorspace=%d\n",
-               fmt->width, fmt->height,
-               (fmt->pixelformat & 0xff),
-               (fmt->pixelformat >>  8) & 0xff,
-               (fmt->pixelformat >> 16) & 0xff,
-               (fmt->pixelformat >> 24) & 0xff,
-               prt_names(fmt->field, v4l2_field_names),
-               fmt->bytesperline, fmt->sizeimage, fmt->colorspace);
-};
+       const struct v4l2_enum_dv_timings *p = arg;
 
-static inline void v4l_print_pix_fmt_mplane(struct video_device *vfd,
-                                           struct v4l2_pix_format_mplane *fmt)
+       pr_cont("index=%u, ", p->index);
+       v4l_print_dv_timings(&p->timings, write_only);
+}
+
+static void v4l_print_dv_timings_cap(const void *arg, bool write_only)
 {
-       int i;
+       const struct v4l2_dv_timings_cap *p = arg;
+
+       switch (p->type) {
+       case V4L2_DV_BT_656_1120:
+               pr_cont("type=bt-656/1120, width=%u-%u, height=%u-%u, "
+                       "pixelclock=%llu-%llu, standards=0x%x, capabilities=0x%x\n",
+                       p->bt.min_width, p->bt.max_width,
+                       p->bt.min_height, p->bt.max_height,
+                       p->bt.min_pixelclock, p->bt.max_pixelclock,
+                       p->bt.standards, p->bt.capabilities);
+               break;
+       default:
+               pr_cont("type=%u\n", p->type);
+               break;
+       }
+}
+
+static void v4l_print_frmsizeenum(const void *arg, bool write_only)
+{
+       const struct v4l2_frmsizeenum *p = arg;
+
+       pr_cont("index=%u, pixelformat=%c%c%c%c, type=%u",
+                       p->index,
+                       (p->pixel_format & 0xff),
+                       (p->pixel_format >>  8) & 0xff,
+                       (p->pixel_format >> 16) & 0xff,
+                       (p->pixel_format >> 24) & 0xff,
+                       p->type);
+       switch (p->type) {
+       case V4L2_FRMSIZE_TYPE_DISCRETE:
+               pr_cont(" wxh=%ux%u\n",
+                       p->discrete.width, p->discrete.height);
+               break;
+       case V4L2_FRMSIZE_TYPE_STEPWISE:
+               pr_cont(" min=%ux%u, max=%ux%u, step=%ux%u\n",
+                               p->stepwise.min_width,  p->stepwise.min_height,
+                               p->stepwise.step_width, p->stepwise.step_height,
+                               p->stepwise.max_width,  p->stepwise.max_height);
+               break;
+       case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+               /* fall through */
+       default:
+               pr_cont("\n");
+               break;
+       }
+}
 
-       dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, "
-               "colorspace=%d, num_planes=%d\n",
-               fmt->width, fmt->height,
-               (fmt->pixelformat & 0xff),
-               (fmt->pixelformat >>  8) & 0xff,
-               (fmt->pixelformat >> 16) & 0xff,
-               (fmt->pixelformat >> 24) & 0xff,
-               prt_names(fmt->field, v4l2_field_names),
-               fmt->colorspace, fmt->num_planes);
+static void v4l_print_frmivalenum(const void *arg, bool write_only)
+{
+       const struct v4l2_frmivalenum *p = arg;
 
-       for (i = 0; i < fmt->num_planes; ++i)
-               dbgarg2("plane %d: bytesperline=%d sizeimage=%d\n", i,
-                       fmt->plane_fmt[i].bytesperline,
-                       fmt->plane_fmt[i].sizeimage);
+       pr_cont("index=%u, pixelformat=%c%c%c%c, wxh=%ux%u, type=%u",
+                       p->index,
+                       (p->pixel_format & 0xff),
+                       (p->pixel_format >>  8) & 0xff,
+                       (p->pixel_format >> 16) & 0xff,
+                       (p->pixel_format >> 24) & 0xff,
+                       p->width, p->height, p->type);
+       switch (p->type) {
+       case V4L2_FRMIVAL_TYPE_DISCRETE:
+               pr_cont(" fps=%d/%d\n",
+                               p->discrete.numerator,
+                               p->discrete.denominator);
+               break;
+       case V4L2_FRMIVAL_TYPE_STEPWISE:
+               pr_cont(" min=%d/%d, max=%d/%d, step=%d/%d\n",
+                               p->stepwise.min.numerator,
+                               p->stepwise.min.denominator,
+                               p->stepwise.max.numerator,
+                               p->stepwise.max.denominator,
+                               p->stepwise.step.numerator,
+                               p->stepwise.step.denominator);
+               break;
+       case V4L2_FRMIVAL_TYPE_CONTINUOUS:
+               /* fall through */
+       default:
+               pr_cont("\n");
+               break;
+       }
 }
 
-static inline void v4l_print_ext_ctrls(unsigned int cmd,
-       struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals)
+static void v4l_print_event(const void *arg, bool write_only)
 {
-       __u32 i;
+       const struct v4l2_event *p = arg;
+       const struct v4l2_event_ctrl *c;
 
-       if (!(vfd->debug & V4L2_DEBUG_IOCTL_ARG))
-               return;
-       dbgarg(cmd, "");
-       printk(KERN_CONT "class=0x%x", c->ctrl_class);
-       for (i = 0; i < c->count; i++) {
-               if (show_vals && !c->controls[i].size)
-                       printk(KERN_CONT " id/val=0x%x/0x%x",
-                               c->controls[i].id, c->controls[i].value);
+       pr_cont("type=0x%x, pending=%u, sequence=%u, id=%u, "
+               "timestamp=%lu.%9.9lu\n",
+                       p->type, p->pending, p->sequence, p->id,
+                       p->timestamp.tv_sec, p->timestamp.tv_nsec);
+       switch (p->type) {
+       case V4L2_EVENT_VSYNC:
+               printk(KERN_DEBUG "field=%s\n",
+                       prt_names(p->u.vsync.field, v4l2_field_names));
+               break;
+       case V4L2_EVENT_CTRL:
+               c = &p->u.ctrl;
+               printk(KERN_DEBUG "changes=0x%x, type=%u, ",
+                       c->changes, c->type);
+               if (c->type == V4L2_CTRL_TYPE_INTEGER64)
+                       pr_cont("value64=%lld, ", c->value64);
                else
-                       printk(KERN_CONT " id=0x%x,size=%u",
-                               c->controls[i].id, c->controls[i].size);
+                       pr_cont("value=%d, ", c->value);
+               pr_cont("flags=0x%x, minimum=%d, maximum=%d, step=%d,"
+                               " default_value=%d\n",
+                       c->flags, c->minimum, c->maximum,
+                       c->step, c->default_value);
+               break;
+       case V4L2_EVENT_FRAME_SYNC:
+               pr_cont("frame_sequence=%u\n",
+                       p->u.frame_sync.frame_sequence);
+               break;
        }
-       printk(KERN_CONT "\n");
-};
+}
+
+static void v4l_print_event_subscription(const void *arg, bool write_only)
+{
+       const struct v4l2_event_subscription *p = arg;
+
+       pr_cont("type=0x%x, id=0x%x, flags=0x%x\n",
+                       p->type, p->id, p->flags);
+}
+
+static void v4l_print_sliced_vbi_cap(const void *arg, bool write_only)
+{
+       const struct v4l2_sliced_vbi_cap *p = arg;
+       int i;
+
+       pr_cont("type=%s, service_set=0x%08x\n",
+                       prt_names(p->type, v4l2_type_names), p->service_set);
+       for (i = 0; i < 24; i++)
+               printk(KERN_DEBUG "line[%02u]=0x%04x, 0x%04x\n", i,
+                               p->service_lines[0][i],
+                               p->service_lines[1][i]);
+}
+
+static void v4l_print_u32(const void *arg, bool write_only)
+{
+       pr_cont("value=%u\n", *(const u32 *)arg);
+}
+
+static void v4l_print_newline(const void *arg, bool write_only)
+{
+       pr_cont("\n");
+}
+
+static void v4l_print_default(const void *arg, bool write_only)
+{
+       pr_cont("driver-specific ioctl\n");
+}
 
-static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
+static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
 {
        __u32 i;
 
@@ -536,1615 +922,1159 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
        return -EINVAL;
 }
 
-static long __video_do_ioctl(struct file *file,
-               unsigned int cmd, void *arg)
+static int v4l_querycap(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
 {
-       struct video_device *vfd = video_devdata(file);
-       const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
-       void *fh = file->private_data;
-       struct v4l2_fh *vfh = NULL;
-       int use_fh_prio = 0;
-       long ret = -ENOTTY;
+       struct v4l2_capability *cap = (struct v4l2_capability *)arg;
 
-       if (ops == NULL) {
-               printk(KERN_WARNING "videodev: \"%s\" has no ioctl_ops.\n",
-                               vfd->name);
-               return ret;
-       }
-
-       if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
-               vfh = file->private_data;
-               use_fh_prio = test_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
-       }
+       cap->version = LINUX_VERSION_CODE;
+       return ops->vidioc_querycap(file, fh, cap);
+}
 
-       if (v4l2_is_known_ioctl(cmd)) {
-               struct v4l2_ioctl_info *info = &v4l2_ioctls[_IOC_NR(cmd)];
+static int v4l_s_input(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       return ops->vidioc_s_input(file, fh, *(unsigned int *)arg);
+}
 
-               if (!test_bit(_IOC_NR(cmd), vfd->valid_ioctls) &&
-                   !((info->flags & INFO_FL_CTRL) && vfh && vfh->ctrl_handler))
-                       return -ENOTTY;
+static int v4l_s_output(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       return ops->vidioc_s_output(file, fh, *(unsigned int *)arg);
+}
 
-               if (use_fh_prio && (info->flags & INFO_FL_PRIO)) {
-                       ret = v4l2_prio_check(vfd->prio, vfh->prio);
-                       if (ret)
-                               return ret;
-               }
-       }
+static int v4l_g_priority(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd;
+       u32 *p = arg;
 
-       if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
-                               !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
-               v4l_print_ioctl(vfd->name, cmd);
-               printk(KERN_CONT "\n");
-       }
+       if (ops->vidioc_g_priority)
+               return ops->vidioc_g_priority(file, fh, arg);
+       vfd = video_devdata(file);
+       *p = v4l2_prio_max(&vfd->v4l2_dev->prio);
+       return 0;
+}
 
-       switch (cmd) {
+static int v4l_s_priority(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd;
+       struct v4l2_fh *vfh;
+       u32 *p = arg;
+
+       if (ops->vidioc_s_priority)
+               return ops->vidioc_s_priority(file, fh, *p);
+       vfd = video_devdata(file);
+       vfh = file->private_data;
+       return v4l2_prio_change(&vfd->v4l2_dev->prio, &vfh->prio, *p);
+}
 
-       /* --- capabilities ------------------------------------------ */
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability *cap = (struct v4l2_capability *)arg;
-
-               cap->version = LINUX_VERSION_CODE;
-               ret = ops->vidioc_querycap(file, fh, cap);
-               if (!ret)
-                       dbgarg(cmd, "driver=%s, card=%s, bus=%s, "
-                                       "version=0x%08x, "
-                                       "capabilities=0x%08x, "
-                                       "device_caps=0x%08x\n",
-                                       cap->driver, cap->card, cap->bus_info,
-                                       cap->version,
-                                       cap->capabilities,
-                                       cap->device_caps);
-               break;
-       }
+static int v4l_enuminput(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_input *p = arg;
 
-       /* --- priority ------------------------------------------ */
-       case VIDIOC_G_PRIORITY:
-       {
-               enum v4l2_priority *p = arg;
+       /*
+        * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS &
+        * CAP_STD here based on ioctl handler provided by the
+        * driver. If the driver doesn't support these
+        * for a specific input, it must override these flags.
+        */
+       if (ops->vidioc_s_std)
+               p->capabilities |= V4L2_IN_CAP_STD;
+       if (ops->vidioc_s_dv_preset)
+               p->capabilities |= V4L2_IN_CAP_PRESETS;
+       if (ops->vidioc_s_dv_timings)
+               p->capabilities |= V4L2_IN_CAP_CUSTOM_TIMINGS;
+
+       return ops->vidioc_enum_input(file, fh, p);
+}
 
-               if (ops->vidioc_g_priority) {
-                       ret = ops->vidioc_g_priority(file, fh, p);
-               } else if (use_fh_prio) {
-                       *p = v4l2_prio_max(&vfd->v4l2_dev->prio);
-                       ret = 0;
-               }
-               if (!ret)
-                       dbgarg(cmd, "priority is %d\n", *p);
-               break;
-       }
-       case VIDIOC_S_PRIORITY:
-       {
-               enum v4l2_priority *p = arg;
+static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_output *p = arg;
 
-               dbgarg(cmd, "setting priority to %d\n", *p);
-               if (ops->vidioc_s_priority)
-                       ret = ops->vidioc_s_priority(file, fh, *p);
-               else
-                       ret = v4l2_prio_change(&vfd->v4l2_dev->prio,
-                                                       &vfh->prio, *p);
-               break;
-       }
+       /*
+        * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS &
+        * CAP_STD here based on ioctl handler provided by the
+        * driver. If the driver doesn't support these
+        * for a specific output, it must override these flags.
+        */
+       if (ops->vidioc_s_std)
+               p->capabilities |= V4L2_OUT_CAP_STD;
+       if (ops->vidioc_s_dv_preset)
+               p->capabilities |= V4L2_OUT_CAP_PRESETS;
+       if (ops->vidioc_s_dv_timings)
+               p->capabilities |= V4L2_OUT_CAP_CUSTOM_TIMINGS;
+
+       return ops->vidioc_enum_output(file, fh, p);
+}
 
-       /* --- capture ioctls ---------------------------------------- */
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc *f = arg;
+static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_fmtdesc *p = arg;
 
-               ret = -EINVAL;
-               switch (f->type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       if (likely(ops->vidioc_enum_fmt_vid_cap))
-                               ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
-                       break;
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-                       if (likely(ops->vidioc_enum_fmt_vid_cap_mplane))
-                               ret = ops->vidioc_enum_fmt_vid_cap_mplane(file,
-                                                                       fh, f);
+       switch (p->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               if (unlikely(!ops->vidioc_enum_fmt_vid_cap))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       if (likely(ops->vidioc_enum_fmt_vid_overlay))
-                               ret = ops->vidioc_enum_fmt_vid_overlay(file,
-                                       fh, f);
+               return ops->vidioc_enum_fmt_vid_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+               if (unlikely(!ops->vidioc_enum_fmt_vid_cap_mplane))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-                       if (likely(ops->vidioc_enum_fmt_vid_out))
-                               ret = ops->vidioc_enum_fmt_vid_out(file, fh, f);
+               return ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (unlikely(!ops->vidioc_enum_fmt_vid_overlay))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-                       if (likely(ops->vidioc_enum_fmt_vid_out_mplane))
-                               ret = ops->vidioc_enum_fmt_vid_out_mplane(file,
-                                                                       fh, f);
+               return ops->vidioc_enum_fmt_vid_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               if (unlikely(!ops->vidioc_enum_fmt_vid_out))
                        break;
-               case V4L2_BUF_TYPE_PRIVATE:
-                       if (likely(ops->vidioc_enum_fmt_type_private))
-                               ret = ops->vidioc_enum_fmt_type_private(file,
-                                                               fh, f);
+               return ops->vidioc_enum_fmt_vid_out(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               if (unlikely(!ops->vidioc_enum_fmt_vid_out_mplane))
                        break;
-               default:
+               return ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_PRIVATE:
+               if (unlikely(!ops->vidioc_enum_fmt_type_private))
                        break;
-               }
-               if (likely(!ret))
-                       dbgarg(cmd, "index=%d, type=%d, flags=%d, "
-                               "pixelformat=%c%c%c%c, description='%s'\n",
-                               f->index, f->type, f->flags,
-                               (f->pixelformat & 0xff),
-                               (f->pixelformat >>  8) & 0xff,
-                               (f->pixelformat >> 16) & 0xff,
-                               (f->pixelformat >> 24) & 0xff,
-                               f->description);
-               break;
+               return ops->vidioc_enum_fmt_type_private(file, fh, arg);
        }
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *f = (struct v4l2_format *)arg;
-
-               /* FIXME: Should be one dump per type */
-               dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
-
-               ret = -EINVAL;
-               switch (f->type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       if (ops->vidioc_g_fmt_vid_cap)
-                               ret = ops->vidioc_g_fmt_vid_cap(file, fh, f);
-                       if (!ret)
-                               v4l_print_pix_fmt(vfd, &f->fmt.pix);
+       return -EINVAL;
+}
+
+static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_format *p = arg;
+
+       switch (p->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               if (unlikely(!ops->vidioc_g_fmt_vid_cap))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-                       if (ops->vidioc_g_fmt_vid_cap_mplane)
-                               ret = ops->vidioc_g_fmt_vid_cap_mplane(file,
-                                                                       fh, f);
-                       if (!ret)
-                               v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+               return ops->vidioc_g_fmt_vid_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+               if (unlikely(!ops->vidioc_g_fmt_vid_cap_mplane))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       if (likely(ops->vidioc_g_fmt_vid_overlay))
-                               ret = ops->vidioc_g_fmt_vid_overlay(file,
-                                                                   fh, f);
+               return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (unlikely(!ops->vidioc_g_fmt_vid_overlay))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-                       if (ops->vidioc_g_fmt_vid_out)
-                               ret = ops->vidioc_g_fmt_vid_out(file, fh, f);
-                       if (!ret)
-                               v4l_print_pix_fmt(vfd, &f->fmt.pix);
+               return ops->vidioc_g_fmt_vid_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               if (unlikely(!ops->vidioc_g_fmt_vid_out))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-                       if (ops->vidioc_g_fmt_vid_out_mplane)
-                               ret = ops->vidioc_g_fmt_vid_out_mplane(file,
-                                                                       fh, f);
-                       if (!ret)
-                               v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+               return ops->vidioc_g_fmt_vid_out(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               if (unlikely(!ops->vidioc_g_fmt_vid_out_mplane))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-                       if (likely(ops->vidioc_g_fmt_vid_out_overlay))
-                               ret = ops->vidioc_g_fmt_vid_out_overlay(file,
-                                      fh, f);
+               return ops->vidioc_g_fmt_vid_out_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+               if (unlikely(!ops->vidioc_g_fmt_vid_out_overlay))
                        break;
-               case V4L2_BUF_TYPE_VBI_CAPTURE:
-                       if (likely(ops->vidioc_g_fmt_vbi_cap))
-                               ret = ops->vidioc_g_fmt_vbi_cap(file, fh, f);
+               return ops->vidioc_g_fmt_vid_out_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               if (unlikely(!ops->vidioc_g_fmt_vbi_cap))
                        break;
-               case V4L2_BUF_TYPE_VBI_OUTPUT:
-                       if (likely(ops->vidioc_g_fmt_vbi_out))
-                               ret = ops->vidioc_g_fmt_vbi_out(file, fh, f);
+               return ops->vidioc_g_fmt_vbi_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+               if (unlikely(!ops->vidioc_g_fmt_vbi_out))
                        break;
-               case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-                       if (likely(ops->vidioc_g_fmt_sliced_vbi_cap))
-                               ret = ops->vidioc_g_fmt_sliced_vbi_cap(file,
-                                                                       fh, f);
+               return ops->vidioc_g_fmt_vbi_out(file, fh, arg);
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+               if (unlikely(!ops->vidioc_g_fmt_sliced_vbi_cap))
                        break;
-               case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-                       if (likely(ops->vidioc_g_fmt_sliced_vbi_out))
-                               ret = ops->vidioc_g_fmt_sliced_vbi_out(file,
-                                                                       fh, f);
+               return ops->vidioc_g_fmt_sliced_vbi_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+               if (unlikely(!ops->vidioc_g_fmt_sliced_vbi_out))
                        break;
-               case V4L2_BUF_TYPE_PRIVATE:
-                       if (likely(ops->vidioc_g_fmt_type_private))
-                               ret = ops->vidioc_g_fmt_type_private(file,
-                                                               fh, f);
+               return ops->vidioc_g_fmt_sliced_vbi_out(file, fh, arg);
+       case V4L2_BUF_TYPE_PRIVATE:
+               if (unlikely(!ops->vidioc_g_fmt_type_private))
                        break;
-               }
-               break;
+               return ops->vidioc_g_fmt_type_private(file, fh, arg);
        }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *f = (struct v4l2_format *)arg;
-
-               ret = -EINVAL;
+       return -EINVAL;
+}
 
-               /* FIXME: Should be one dump per type */
-               dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
+static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_format *p = arg;
 
-               switch (f->type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       CLEAR_AFTER_FIELD(f, fmt.pix);
-                       v4l_print_pix_fmt(vfd, &f->fmt.pix);
-                       if (ops->vidioc_s_fmt_vid_cap)
-                               ret = ops->vidioc_s_fmt_vid_cap(file, fh, f);
+       switch (p->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               if (unlikely(!ops->vidioc_s_fmt_vid_cap))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-                       CLEAR_AFTER_FIELD(f, fmt.pix_mp);
-                       v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
-                       if (ops->vidioc_s_fmt_vid_cap_mplane)
-                               ret = ops->vidioc_s_fmt_vid_cap_mplane(file,
-                                                                       fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.pix);
+               return ops->vidioc_s_fmt_vid_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+               if (unlikely(!ops->vidioc_s_fmt_vid_cap_mplane))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       CLEAR_AFTER_FIELD(f, fmt.win);
-                       if (ops->vidioc_s_fmt_vid_overlay)
-                               ret = ops->vidioc_s_fmt_vid_overlay(file,
-                                                                   fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.pix_mp);
+               return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (unlikely(!ops->vidioc_s_fmt_vid_overlay))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-                       CLEAR_AFTER_FIELD(f, fmt.pix);
-                       v4l_print_pix_fmt(vfd, &f->fmt.pix);
-                       if (ops->vidioc_s_fmt_vid_out)
-                               ret = ops->vidioc_s_fmt_vid_out(file, fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.win);
+               return ops->vidioc_s_fmt_vid_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               if (unlikely(!ops->vidioc_s_fmt_vid_out))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-                       CLEAR_AFTER_FIELD(f, fmt.pix_mp);
-                       v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
-                       if (ops->vidioc_s_fmt_vid_out_mplane)
-                               ret = ops->vidioc_s_fmt_vid_out_mplane(file,
-                                                                       fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.pix);
+               return ops->vidioc_s_fmt_vid_out(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               if (unlikely(!ops->vidioc_s_fmt_vid_out_mplane))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-                       CLEAR_AFTER_FIELD(f, fmt.win);
-                       if (ops->vidioc_s_fmt_vid_out_overlay)
-                               ret = ops->vidioc_s_fmt_vid_out_overlay(file,
-                                       fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.pix_mp);
+               return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+               if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay))
                        break;
-               case V4L2_BUF_TYPE_VBI_CAPTURE:
-                       CLEAR_AFTER_FIELD(f, fmt.vbi);
-                       if (likely(ops->vidioc_s_fmt_vbi_cap))
-                               ret = ops->vidioc_s_fmt_vbi_cap(file, fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.win);
+               return ops->vidioc_s_fmt_vid_out_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               if (unlikely(!ops->vidioc_s_fmt_vbi_cap))
                        break;
-               case V4L2_BUF_TYPE_VBI_OUTPUT:
-                       CLEAR_AFTER_FIELD(f, fmt.vbi);
-                       if (likely(ops->vidioc_s_fmt_vbi_out))
-                               ret = ops->vidioc_s_fmt_vbi_out(file, fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.vbi);
+               return ops->vidioc_s_fmt_vbi_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+               if (unlikely(!ops->vidioc_s_fmt_vbi_out))
                        break;
-               case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-                       CLEAR_AFTER_FIELD(f, fmt.sliced);
-                       if (likely(ops->vidioc_s_fmt_sliced_vbi_cap))
-                               ret = ops->vidioc_s_fmt_sliced_vbi_cap(file,
-                                                                       fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.vbi);
+               return ops->vidioc_s_fmt_vbi_out(file, fh, arg);
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+               if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap))
                        break;
-               case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-                       CLEAR_AFTER_FIELD(f, fmt.sliced);
-                       if (likely(ops->vidioc_s_fmt_sliced_vbi_out))
-                               ret = ops->vidioc_s_fmt_sliced_vbi_out(file,
-                                                                       fh, f);
-
+               CLEAR_AFTER_FIELD(p, fmt.sliced);
+               return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+               if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out))
                        break;
-               case V4L2_BUF_TYPE_PRIVATE:
-                       /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */
-                       if (likely(ops->vidioc_s_fmt_type_private))
-                               ret = ops->vidioc_s_fmt_type_private(file,
-                                                               fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.sliced);
+               return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg);
+       case V4L2_BUF_TYPE_PRIVATE:
+               if (unlikely(!ops->vidioc_s_fmt_type_private))
                        break;
-               }
-               break;
+               return ops->vidioc_s_fmt_type_private(file, fh, arg);
        }
-       case VIDIOC_TRY_FMT:
-       {
-               struct v4l2_format *f = (struct v4l2_format *)arg;
-
-               /* FIXME: Should be one dump per type */
-               dbgarg(cmd, "type=%s\n", prt_names(f->type,
-                                               v4l2_type_names));
-               ret = -EINVAL;
-               switch (f->type) {
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       CLEAR_AFTER_FIELD(f, fmt.pix);
-                       if (ops->vidioc_try_fmt_vid_cap)
-                               ret = ops->vidioc_try_fmt_vid_cap(file, fh, f);
-                       if (!ret)
-                               v4l_print_pix_fmt(vfd, &f->fmt.pix);
+       return -EINVAL;
+}
+
+static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_format *p = arg;
+
+       switch (p->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               if (unlikely(!ops->vidioc_try_fmt_vid_cap))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-                       CLEAR_AFTER_FIELD(f, fmt.pix_mp);
-                       if (ops->vidioc_try_fmt_vid_cap_mplane)
-                               ret = ops->vidioc_try_fmt_vid_cap_mplane(file,
-                                                                        fh, f);
-                       if (!ret)
-                               v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+               CLEAR_AFTER_FIELD(p, fmt.pix);
+               return ops->vidioc_try_fmt_vid_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+               if (unlikely(!ops->vidioc_try_fmt_vid_cap_mplane))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-                       CLEAR_AFTER_FIELD(f, fmt.win);
-                       if (likely(ops->vidioc_try_fmt_vid_overlay))
-                               ret = ops->vidioc_try_fmt_vid_overlay(file,
-                                       fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.pix_mp);
+               return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               if (unlikely(!ops->vidioc_try_fmt_vid_overlay))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-                       CLEAR_AFTER_FIELD(f, fmt.pix);
-                       if (ops->vidioc_try_fmt_vid_out)
-                               ret = ops->vidioc_try_fmt_vid_out(file, fh, f);
-                       if (!ret)
-                               v4l_print_pix_fmt(vfd, &f->fmt.pix);
+               CLEAR_AFTER_FIELD(p, fmt.win);
+               return ops->vidioc_try_fmt_vid_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               if (unlikely(!ops->vidioc_try_fmt_vid_out))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-                       CLEAR_AFTER_FIELD(f, fmt.pix_mp);
-                       if (ops->vidioc_try_fmt_vid_out_mplane)
-                               ret = ops->vidioc_try_fmt_vid_out_mplane(file,
-                                                                        fh, f);
-                       if (!ret)
-                               v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+               CLEAR_AFTER_FIELD(p, fmt.pix);
+               return ops->vidioc_try_fmt_vid_out(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               if (unlikely(!ops->vidioc_try_fmt_vid_out_mplane))
                        break;
-               case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-                       CLEAR_AFTER_FIELD(f, fmt.win);
-                       if (likely(ops->vidioc_try_fmt_vid_out_overlay))
-                               ret = ops->vidioc_try_fmt_vid_out_overlay(file,
-                                      fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.pix_mp);
+               return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg);
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+               if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay))
                        break;
-               case V4L2_BUF_TYPE_VBI_CAPTURE:
-                       CLEAR_AFTER_FIELD(f, fmt.vbi);
-                       if (likely(ops->vidioc_try_fmt_vbi_cap))
-                               ret = ops->vidioc_try_fmt_vbi_cap(file, fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.win);
+               return ops->vidioc_try_fmt_vid_out_overlay(file, fh, arg);
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               if (unlikely(!ops->vidioc_try_fmt_vbi_cap))
                        break;
-               case V4L2_BUF_TYPE_VBI_OUTPUT:
-                       CLEAR_AFTER_FIELD(f, fmt.vbi);
-                       if (likely(ops->vidioc_try_fmt_vbi_out))
-                               ret = ops->vidioc_try_fmt_vbi_out(file, fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.vbi);
+               return ops->vidioc_try_fmt_vbi_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+               if (unlikely(!ops->vidioc_try_fmt_vbi_out))
                        break;
-               case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-                       CLEAR_AFTER_FIELD(f, fmt.sliced);
-                       if (likely(ops->vidioc_try_fmt_sliced_vbi_cap))
-                               ret = ops->vidioc_try_fmt_sliced_vbi_cap(file,
-                                                               fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.vbi);
+               return ops->vidioc_try_fmt_vbi_out(file, fh, arg);
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+               if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap))
                        break;
-               case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-                       CLEAR_AFTER_FIELD(f, fmt.sliced);
-                       if (likely(ops->vidioc_try_fmt_sliced_vbi_out))
-                               ret = ops->vidioc_try_fmt_sliced_vbi_out(file,
-                                                               fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.sliced);
+               return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg);
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+               if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out))
                        break;
-               case V4L2_BUF_TYPE_PRIVATE:
-                       /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */
-                       if (likely(ops->vidioc_try_fmt_type_private))
-                               ret = ops->vidioc_try_fmt_type_private(file,
-                                                               fh, f);
+               CLEAR_AFTER_FIELD(p, fmt.sliced);
+               return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg);
+       case V4L2_BUF_TYPE_PRIVATE:
+               if (unlikely(!ops->vidioc_try_fmt_type_private))
                        break;
-               }
-               break;
+               return ops->vidioc_try_fmt_type_private(file, fh, arg);
        }
-       /* FIXME: Those buf reqs could be handled here,
-          with some changes on videobuf to allow its header to be included at
-          videodev2.h or being merged at videodev2.
-        */
-       case VIDIOC_REQBUFS:
-       {
-               struct v4l2_requestbuffers *p = arg;
-
-               ret = check_fmt(ops, p->type);
-               if (ret)
-                       break;
+       return -EINVAL;
+}
 
-               if (p->type < V4L2_BUF_TYPE_PRIVATE)
-                       CLEAR_AFTER_FIELD(p, memory);
+static int v4l_streamon(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       return ops->vidioc_streamon(file, fh, *(unsigned int *)arg);
+}
 
-               ret = ops->vidioc_reqbufs(file, fh, p);
-               dbgarg(cmd, "count=%d, type=%s, memory=%s\n",
-                               p->count,
-                               prt_names(p->type, v4l2_type_names),
-                               prt_names(p->memory, v4l2_memory_names));
-               break;
-       }
-       case VIDIOC_QUERYBUF:
-       {
-               struct v4l2_buffer *p = arg;
+static int v4l_streamoff(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       return ops->vidioc_streamoff(file, fh, *(unsigned int *)arg);
+}
 
-               ret = check_fmt(ops, p->type);
-               if (ret)
-                       break;
+static int v4l_g_tuner(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_tuner *p = arg;
 
-               ret = ops->vidioc_querybuf(file, fh, p);
-               if (!ret)
-                       dbgbuf(cmd, vfd, p);
-               break;
-       }
-       case VIDIOC_QBUF:
-       {
-               struct v4l2_buffer *p = arg;
+       p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+                       V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       return ops->vidioc_g_tuner(file, fh, p);
+}
 
-               ret = check_fmt(ops, p->type);
-               if (ret)
-                       break;
+static int v4l_s_tuner(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_tuner *p = arg;
 
-               ret = ops->vidioc_qbuf(file, fh, p);
-               if (!ret)
-                       dbgbuf(cmd, vfd, p);
-               break;
-       }
-       case VIDIOC_DQBUF:
-       {
-               struct v4l2_buffer *p = arg;
+       p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+                       V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       return ops->vidioc_s_tuner(file, fh, p);
+}
 
-               ret = check_fmt(ops, p->type);
-               if (ret)
-                       break;
+static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_frequency *p = arg;
 
-               ret = ops->vidioc_dqbuf(file, fh, p);
-               if (!ret)
-                       dbgbuf(cmd, vfd, p);
-               break;
-       }
-       case VIDIOC_OVERLAY:
-       {
-               int *i = arg;
+       p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+                       V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       return ops->vidioc_g_frequency(file, fh, p);
+}
 
-               dbgarg(cmd, "value=%d\n", *i);
-               ret = ops->vidioc_overlay(file, fh, *i);
-               break;
-       }
-       case VIDIOC_G_FBUF:
-       {
-               struct v4l2_framebuffer *p = arg;
-
-               ret = ops->vidioc_g_fbuf(file, fh, arg);
-               if (!ret) {
-                       dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n",
-                                       p->capability, p->flags,
-                                       (unsigned long)p->base);
-                       v4l_print_pix_fmt(vfd, &p->fmt);
-               }
-               break;
-       }
-       case VIDIOC_S_FBUF:
-       {
-               struct v4l2_framebuffer *p = arg;
-
-               dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n",
-                       p->capability, p->flags, (unsigned long)p->base);
-               v4l_print_pix_fmt(vfd, &p->fmt);
-               ret = ops->vidioc_s_fbuf(file, fh, arg);
-               break;
-       }
-       case VIDIOC_STREAMON:
-       {
-               enum v4l2_buf_type i = *(int *)arg;
+static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_frequency *p = arg;
+       enum v4l2_tuner_type type;
 
-               dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
-               ret = ops->vidioc_streamon(file, fh, i);
-               break;
-       }
-       case VIDIOC_STREAMOFF:
-       {
-               enum v4l2_buf_type i = *(int *)arg;
+       type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+                       V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       if (p->type != type)
+               return -EINVAL;
+       return ops->vidioc_s_frequency(file, fh, p);
+}
 
-               dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
-               ret = ops->vidioc_streamoff(file, fh, i);
-               break;
-       }
-       /* ---------- tv norms ---------- */
-       case VIDIOC_ENUMSTD:
-       {
-               struct v4l2_standard *p = arg;
-               v4l2_std_id id = vfd->tvnorms, curr_id = 0;
-               unsigned int index = p->index, i, j = 0;
-               const char *descr = "";
-
-               if (id == 0)
-                       break;
-               ret = -EINVAL;
-
-               /* Return norm array in a canonical way */
-               for (i = 0; i <= index && id; i++) {
-                       /* last std value in the standards array is 0, so this
-                          while always ends there since (id & 0) == 0. */
-                       while ((id & standards[j].std) != standards[j].std)
-                               j++;
-                       curr_id = standards[j].std;
-                       descr = standards[j].descr;
+static int v4l_enumstd(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_standard *p = arg;
+       v4l2_std_id id = vfd->tvnorms, curr_id = 0;
+       unsigned int index = p->index, i, j = 0;
+       const char *descr = "";
+
+       /* Return norm array in a canonical way */
+       for (i = 0; i <= index && id; i++) {
+               /* last std value in the standards array is 0, so this
+                  while always ends there since (id & 0) == 0. */
+               while ((id & standards[j].std) != standards[j].std)
                        j++;
-                       if (curr_id == 0)
-                               break;
-                       if (curr_id != V4L2_STD_PAL &&
-                           curr_id != V4L2_STD_SECAM &&
-                           curr_id != V4L2_STD_NTSC)
-                               id &= ~curr_id;
-               }
-               if (i <= index)
+               curr_id = standards[j].std;
+               descr = standards[j].descr;
+               j++;
+               if (curr_id == 0)
                        break;
-
-               v4l2_video_std_construct(p, curr_id, descr);
-
-               dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, "
-                               "framelines=%d\n", p->index,
-                               (unsigned long long)p->id, p->name,
-                               p->frameperiod.numerator,
-                               p->frameperiod.denominator,
-                               p->framelines);
-
-               ret = 0;
-               break;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *id = arg;
-
-               /* Calls the specific handler */
-               if (ops->vidioc_g_std)
-                       ret = ops->vidioc_g_std(file, fh, id);
-               else if (vfd->current_norm) {
-                       ret = 0;
-                       *id = vfd->current_norm;
-               }
-
-               if (likely(!ret))
-                       dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id);
-               break;
-       }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *id = arg, norm;
-
-               dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id);
-
-               ret = -EINVAL;
-               norm = (*id) & vfd->tvnorms;
-               if (vfd->tvnorms && !norm)      /* Check if std is supported */
-                       break;
-
-               /* Calls the specific handler */
-               ret = ops->vidioc_s_std(file, fh, &norm);
-
-               /* Updates standard information */
-               if (ret >= 0)
-                       vfd->current_norm = norm;
-               break;
+               if (curr_id != V4L2_STD_PAL &&
+                               curr_id != V4L2_STD_SECAM &&
+                               curr_id != V4L2_STD_NTSC)
+                       id &= ~curr_id;
        }
-       case VIDIOC_QUERYSTD:
-       {
-               v4l2_std_id *p = arg;
-
-               /*
-                * If nothing detected, it should return all supported
-                * Drivers just need to mask the std argument, in order
-                * to remove the standards that don't apply from the mask.
-                * This means that tuners, audio and video decoders can join
-                * their efforts to improve the standards detection
-                */
-               *p = vfd->tvnorms;
-               ret = ops->vidioc_querystd(file, fh, arg);
-               if (!ret)
-                       dbgarg(cmd, "detected std=%08Lx\n",
-                                               (unsigned long long)*p);
-               break;
-       }
-       /* ------ input switching ---------- */
-       /* FIXME: Inputs can be handled inside videodev2 */
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input *p = arg;
+       if (i <= index)
+               return -EINVAL;
 
-               /*
-                * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS &
-                * CAP_STD here based on ioctl handler provided by the
-                * driver. If the driver doesn't support these
-                * for a specific input, it must override these flags.
-                */
-               if (ops->vidioc_s_std)
-                       p->capabilities |= V4L2_IN_CAP_STD;
-               if (ops->vidioc_s_dv_preset)
-                       p->capabilities |= V4L2_IN_CAP_PRESETS;
-               if (ops->vidioc_s_dv_timings)
-                       p->capabilities |= V4L2_IN_CAP_CUSTOM_TIMINGS;
-
-               ret = ops->vidioc_enum_input(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "index=%d, name=%s, type=%d, "
-                               "audioset=%d, "
-                               "tuner=%d, std=%08Lx, status=%d\n",
-                               p->index, p->name, p->type, p->audioset,
-                               p->tuner,
-                               (unsigned long long)p->std,
-                               p->status);
-               break;
-       }
-       case VIDIOC_G_INPUT:
-       {
-               unsigned int *i = arg;
+       v4l2_video_std_construct(p, curr_id, descr);
+       return 0;
+}
 
-               ret = ops->vidioc_g_input(file, fh, i);
-               if (!ret)
-                       dbgarg(cmd, "value=%d\n", *i);
-               break;
-       }
-       case VIDIOC_S_INPUT:
-       {
-               unsigned int *i = arg;
+static int v4l_g_std(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       v4l2_std_id *id = arg;
 
-               dbgarg(cmd, "value=%d\n", *i);
-               ret = ops->vidioc_s_input(file, fh, *i);
-               break;
+       /* Calls the specific handler */
+       if (ops->vidioc_g_std)
+               return ops->vidioc_g_std(file, fh, arg);
+       if (vfd->current_norm) {
+               *id = vfd->current_norm;
+               return 0;
        }
+       return -ENOTTY;
+}
 
-       /* ------ output switching ---------- */
-       case VIDIOC_ENUMOUTPUT:
-       {
-               struct v4l2_output *p = arg;
-
-               /*
-                * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS &
-                * CAP_STD here based on ioctl handler provided by the
-                * driver. If the driver doesn't support these
-                * for a specific output, it must override these flags.
-                */
-               if (ops->vidioc_s_std)
-                       p->capabilities |= V4L2_OUT_CAP_STD;
-               if (ops->vidioc_s_dv_preset)
-                       p->capabilities |= V4L2_OUT_CAP_PRESETS;
-               if (ops->vidioc_s_dv_timings)
-                       p->capabilities |= V4L2_OUT_CAP_CUSTOM_TIMINGS;
-
-               ret = ops->vidioc_enum_output(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "index=%d, name=%s, type=%d, "
-                               "audioset=0x%x, "
-                               "modulator=%d, std=0x%08Lx\n",
-                               p->index, p->name, p->type, p->audioset,
-                               p->modulator, (unsigned long long)p->std);
-               break;
-       }
-       case VIDIOC_G_OUTPUT:
-       {
-               unsigned int *i = arg;
+static int v4l_s_std(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       v4l2_std_id *id = arg, norm;
+       int ret;
 
-               ret = ops->vidioc_g_output(file, fh, i);
-               if (!ret)
-                       dbgarg(cmd, "value=%d\n", *i);
-               break;
-       }
-       case VIDIOC_S_OUTPUT:
-       {
-               unsigned int *i = arg;
+       norm = (*id) & vfd->tvnorms;
+       if (vfd->tvnorms && !norm)      /* Check if std is supported */
+               return -EINVAL;
 
-               dbgarg(cmd, "value=%d\n", *i);
-               ret = ops->vidioc_s_output(file, fh, *i);
-               break;
-       }
+       /* Calls the specific handler */
+       ret = ops->vidioc_s_std(file, fh, &norm);
 
-       /* --- controls ---------------------------------------------- */
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *p = arg;
-
-               if (vfh && vfh->ctrl_handler)
-                       ret = v4l2_queryctrl(vfh->ctrl_handler, p);
-               else if (vfd->ctrl_handler)
-                       ret = v4l2_queryctrl(vfd->ctrl_handler, p);
-               else if (ops->vidioc_queryctrl)
-                       ret = ops->vidioc_queryctrl(file, fh, p);
-               else
-                       break;
-               if (!ret)
-                       dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, "
-                                       "step=%d, default=%d, flags=0x%08x\n",
-                                       p->id, p->type, p->name,
-                                       p->minimum, p->maximum,
-                                       p->step, p->default_value, p->flags);
-               else
-                       dbgarg(cmd, "id=0x%x\n", p->id);
-               break;
-       }
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *p = arg;
-
-               if (vfh && vfh->ctrl_handler)
-                       ret = v4l2_g_ctrl(vfh->ctrl_handler, p);
-               else if (vfd->ctrl_handler)
-                       ret = v4l2_g_ctrl(vfd->ctrl_handler, p);
-               else if (ops->vidioc_g_ctrl)
-                       ret = ops->vidioc_g_ctrl(file, fh, p);
-               else if (ops->vidioc_g_ext_ctrls) {
-                       struct v4l2_ext_controls ctrls;
-                       struct v4l2_ext_control ctrl;
-
-                       ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
-                       ctrls.count = 1;
-                       ctrls.controls = &ctrl;
-                       ctrl.id = p->id;
-                       ctrl.value = p->value;
-                       if (check_ext_ctrls(&ctrls, 1)) {
-                               ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls);
-                               if (ret == 0)
-                                       p->value = ctrl.value;
-                       }
-               } else
-                       break;
-               if (!ret)
-                       dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
-               else
-                       dbgarg(cmd, "id=0x%x\n", p->id);
-               break;
-       }
-       case VIDIOC_S_CTRL:
-       {
-               struct v4l2_control *p = arg;
-               struct v4l2_ext_controls ctrls;
-               struct v4l2_ext_control ctrl;
-
-               if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
-                       !ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls)
-                       break;
+       /* Updates standard information */
+       if (ret >= 0)
+               vfd->current_norm = norm;
+       return ret;
+}
 
-               dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
+static int v4l_querystd(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       v4l2_std_id *p = arg;
+
+       /*
+        * If nothing detected, it should return all supported
+        * standard.
+        * Drivers just need to mask the std argument, in order
+        * to remove the standards that don't apply from the mask.
+        * This means that tuners, audio and video decoders can join
+        * their efforts to improve the standards detection.
+        */
+       *p = vfd->tvnorms;
+       return ops->vidioc_querystd(file, fh, arg);
+}
 
-               if (vfh && vfh->ctrl_handler) {
-                       ret = v4l2_s_ctrl(vfh, vfh->ctrl_handler, p);
-                       break;
-               }
-               if (vfd->ctrl_handler) {
-                       ret = v4l2_s_ctrl(NULL, vfd->ctrl_handler, p);
-                       break;
-               }
-               if (ops->vidioc_s_ctrl) {
-                       ret = ops->vidioc_s_ctrl(file, fh, p);
-                       break;
-               }
-               if (!ops->vidioc_s_ext_ctrls)
-                       break;
+static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_hw_freq_seek *p = arg;
+       enum v4l2_tuner_type type;
 
-               ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
-               ctrls.count = 1;
-               ctrls.controls = &ctrl;
-               ctrl.id = p->id;
-               ctrl.value = p->value;
-               if (check_ext_ctrls(&ctrls, 1))
-                       ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls);
-               else
-                       ret = -EINVAL;
-               break;
-       }
-       case VIDIOC_G_EXT_CTRLS:
-       {
-               struct v4l2_ext_controls *p = arg;
-
-               p->error_idx = p->count;
-               if (vfh && vfh->ctrl_handler)
-                       ret = v4l2_g_ext_ctrls(vfh->ctrl_handler, p);
-               else if (vfd->ctrl_handler)
-                       ret = v4l2_g_ext_ctrls(vfd->ctrl_handler, p);
-               else if (ops->vidioc_g_ext_ctrls)
-                       ret = check_ext_ctrls(p, 0) ?
-                               ops->vidioc_g_ext_ctrls(file, fh, p) :
-                               -EINVAL;
-               else
-                       break;
-               v4l_print_ext_ctrls(cmd, vfd, p, !ret);
-               break;
-       }
-       case VIDIOC_S_EXT_CTRLS:
-       {
-               struct v4l2_ext_controls *p = arg;
+       type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
+               V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+       if (p->type != type)
+               return -EINVAL;
+       return ops->vidioc_s_hw_freq_seek(file, fh, p);
+}
 
-               p->error_idx = p->count;
-               if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
-                               !ops->vidioc_s_ext_ctrls)
-                       break;
-               v4l_print_ext_ctrls(cmd, vfd, p, 1);
-               if (vfh && vfh->ctrl_handler)
-                       ret = v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p);
-               else if (vfd->ctrl_handler)
-                       ret = v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, p);
-               else if (check_ext_ctrls(p, 0))
-                       ret = ops->vidioc_s_ext_ctrls(file, fh, p);
-               else
-                       ret = -EINVAL;
-               break;
-       }
-       case VIDIOC_TRY_EXT_CTRLS:
-       {
-               struct v4l2_ext_controls *p = arg;
+static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_requestbuffers *p = arg;
+       int ret = check_fmt(ops, p->type);
 
-               p->error_idx = p->count;
-               if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
-                               !ops->vidioc_try_ext_ctrls)
-                       break;
-               v4l_print_ext_ctrls(cmd, vfd, p, 1);
-               if (vfh && vfh->ctrl_handler)
-                       ret = v4l2_try_ext_ctrls(vfh->ctrl_handler, p);
-               else if (vfd->ctrl_handler)
-                       ret = v4l2_try_ext_ctrls(vfd->ctrl_handler, p);
-               else if (check_ext_ctrls(p, 0))
-                       ret = ops->vidioc_try_ext_ctrls(file, fh, p);
-               else
-                       ret = -EINVAL;
-               break;
-       }
-       case VIDIOC_QUERYMENU:
-       {
-               struct v4l2_querymenu *p = arg;
-
-               if (vfh && vfh->ctrl_handler)
-                       ret = v4l2_querymenu(vfh->ctrl_handler, p);
-               else if (vfd->ctrl_handler)
-                       ret = v4l2_querymenu(vfd->ctrl_handler, p);
-               else if (ops->vidioc_querymenu)
-                       ret = ops->vidioc_querymenu(file, fh, p);
-               else
-                       break;
-               if (!ret)
-                       dbgarg(cmd, "id=0x%x, index=%d, name=%s\n",
-                               p->id, p->index, p->name);
-               else
-                       dbgarg(cmd, "id=0x%x, index=%d\n",
-                               p->id, p->index);
-               break;
-       }
-       /* --- audio ---------------------------------------------- */
-       case VIDIOC_ENUMAUDIO:
-       {
-               struct v4l2_audio *p = arg;
-
-               ret = ops->vidioc_enumaudio(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
-                                       "mode=0x%x\n", p->index, p->name,
-                                       p->capability, p->mode);
-               else
-                       dbgarg(cmd, "index=%d\n", p->index);
-               break;
-       }
-       case VIDIOC_G_AUDIO:
-       {
-               struct v4l2_audio *p = arg;
-
-               ret = ops->vidioc_g_audio(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
-                                       "mode=0x%x\n", p->index,
-                                       p->name, p->capability, p->mode);
-               else
-                       dbgarg(cmd, "index=%d\n", p->index);
-               break;
-       }
-       case VIDIOC_S_AUDIO:
-       {
-               struct v4l2_audio *p = arg;
-
-               dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
-                                       "mode=0x%x\n", p->index, p->name,
-                                       p->capability, p->mode);
-               ret = ops->vidioc_s_audio(file, fh, p);
-               break;
-       }
-       case VIDIOC_ENUMAUDOUT:
-       {
-               struct v4l2_audioout *p = arg;
-
-               dbgarg(cmd, "Enum for index=%d\n", p->index);
-               ret = ops->vidioc_enumaudout(file, fh, p);
-               if (!ret)
-                       dbgarg2("index=%d, name=%s, capability=%d, "
-                                       "mode=%d\n", p->index, p->name,
-                                       p->capability, p->mode);
-               break;
-       }
-       case VIDIOC_G_AUDOUT:
-       {
-               struct v4l2_audioout *p = arg;
-
-               ret = ops->vidioc_g_audout(file, fh, p);
-               if (!ret)
-                       dbgarg2("index=%d, name=%s, capability=%d, "
-                                       "mode=%d\n", p->index, p->name,
-                                       p->capability, p->mode);
-               break;
-       }
-       case VIDIOC_S_AUDOUT:
-       {
-               struct v4l2_audioout *p = arg;
+       if (ret)
+               return ret;
 
-               dbgarg(cmd, "index=%d, name=%s, capability=%d, "
-                                       "mode=%d\n", p->index, p->name,
-                                       p->capability, p->mode);
+       if (p->type < V4L2_BUF_TYPE_PRIVATE)
+               CLEAR_AFTER_FIELD(p, memory);
 
-               ret = ops->vidioc_s_audout(file, fh, p);
-               break;
-       }
-       case VIDIOC_G_MODULATOR:
-       {
-               struct v4l2_modulator *p = arg;
-
-               ret = ops->vidioc_g_modulator(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "index=%d, name=%s, "
-                                       "capability=%d, rangelow=%d,"
-                                       " rangehigh=%d, txsubchans=%d\n",
-                                       p->index, p->name, p->capability,
-                                       p->rangelow, p->rangehigh,
-                                       p->txsubchans);
-               break;
-       }
-       case VIDIOC_S_MODULATOR:
-       {
-               struct v4l2_modulator *p = arg;
-
-               dbgarg(cmd, "index=%d, name=%s, capability=%d, "
-                               "rangelow=%d, rangehigh=%d, txsubchans=%d\n",
-                               p->index, p->name, p->capability, p->rangelow,
-                               p->rangehigh, p->txsubchans);
-                       ret = ops->vidioc_s_modulator(file, fh, p);
-               break;
-       }
-       case VIDIOC_G_CROP:
-       {
-               struct v4l2_crop *p = arg;
+       return ops->vidioc_reqbufs(file, fh, p);
+}
 
-               dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+static int v4l_querybuf(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_buffer *p = arg;
+       int ret = check_fmt(ops, p->type);
 
-               if (ops->vidioc_g_crop) {
-                       ret = ops->vidioc_g_crop(file, fh, p);
-               } else {
-                       /* simulate capture crop using selection api */
-                       struct v4l2_selection s = {
-                               .type = p->type,
-                       };
-
-                       /* crop means compose for output devices */
-                       if (V4L2_TYPE_IS_OUTPUT(p->type))
-                               s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
-                       else
-                               s.target = V4L2_SEL_TGT_CROP_ACTIVE;
-
-                       ret = ops->vidioc_g_selection(file, fh, &s);
-
-                       /* copying results to old structure on success */
-                       if (!ret)
-                               p->c = s.r;
-               }
+       return ret ? ret : ops->vidioc_querybuf(file, fh, p);
+}
 
-               if (!ret)
-                       dbgrect(vfd, "", &p->c);
-               break;
-       }
-       case VIDIOC_S_CROP:
-       {
-               struct v4l2_crop *p = arg;
+static int v4l_qbuf(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_buffer *p = arg;
+       int ret = check_fmt(ops, p->type);
 
-               dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
-               dbgrect(vfd, "", &p->c);
+       return ret ? ret : ops->vidioc_qbuf(file, fh, p);
+}
 
-               if (ops->vidioc_s_crop) {
-                       ret = ops->vidioc_s_crop(file, fh, p);
-               } else {
-                       /* simulate capture crop using selection api */
-                       struct v4l2_selection s = {
-                               .type = p->type,
-                               .r = p->c,
-                       };
-
-                       /* crop means compose for output devices */
-                       if (V4L2_TYPE_IS_OUTPUT(p->type))
-                               s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
-                       else
-                               s.target = V4L2_SEL_TGT_CROP_ACTIVE;
-
-                       ret = ops->vidioc_s_selection(file, fh, &s);
-               }
-               break;
-       }
-       case VIDIOC_G_SELECTION:
-       {
-               struct v4l2_selection *p = arg;
+static int v4l_dqbuf(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_buffer *p = arg;
+       int ret = check_fmt(ops, p->type);
 
-               dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+       return ret ? ret : ops->vidioc_dqbuf(file, fh, p);
+}
 
-               ret = ops->vidioc_g_selection(file, fh, p);
-               if (!ret)
-                       dbgrect(vfd, "", &p->r);
-               break;
-       }
-       case VIDIOC_S_SELECTION:
-       {
-               struct v4l2_selection *p = arg;
+static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_create_buffers *create = arg;
+       int ret = check_fmt(ops, create->format.type);
 
+       return ret ? ret : ops->vidioc_create_bufs(file, fh, create);
+}
 
-               dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
-               dbgrect(vfd, "", &p->r);
+static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_buffer *b = arg;
+       int ret = check_fmt(ops, b->type);
 
-               ret = ops->vidioc_s_selection(file, fh, p);
-               break;
-       }
-       case VIDIOC_CROPCAP:
-       {
-               struct v4l2_cropcap *p = arg;
-
-               /*FIXME: Should also show v4l2_fract pixelaspect */
-               dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
-               if (ops->vidioc_cropcap) {
-                       ret = ops->vidioc_cropcap(file, fh, p);
-               } else {
-                       struct v4l2_selection s = { .type = p->type };
+       return ret ? ret : ops->vidioc_prepare_buf(file, fh, b);
+}
 
-                       /* obtaining bounds */
-                       if (V4L2_TYPE_IS_OUTPUT(p->type))
-                               s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS;
-                       else
-                               s.target = V4L2_SEL_TGT_CROP_BOUNDS;
+static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_streamparm *p = arg;
+       v4l2_std_id std;
+       int ret = check_fmt(ops, p->type);
 
-                       ret = ops->vidioc_g_selection(file, fh, &s);
-                       if (ret)
-                               break;
-                       p->bounds = s.r;
+       if (ret)
+               return ret;
+       if (ops->vidioc_g_parm)
+               return ops->vidioc_g_parm(file, fh, p);
+       std = vfd->current_norm;
+       if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return -EINVAL;
+       p->parm.capture.readbuffers = 2;
+       if (ops->vidioc_g_std)
+               ret = ops->vidioc_g_std(file, fh, &std);
+       if (ret == 0)
+               v4l2_video_std_frame_period(std,
+                           &p->parm.capture.timeperframe);
+       return ret;
+}
 
-                       /* obtaining defrect */
-                       if (V4L2_TYPE_IS_OUTPUT(p->type))
-                               s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
-                       else
-                               s.target = V4L2_SEL_TGT_CROP_DEFAULT;
+static int v4l_s_parm(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_streamparm *p = arg;
+       int ret = check_fmt(ops, p->type);
 
-                       ret = ops->vidioc_g_selection(file, fh, &s);
-                       if (ret)
-                               break;
-                       p->defrect = s.r;
+       return ret ? ret : ops->vidioc_s_parm(file, fh, p);
+}
 
-                       /* setting trivial pixelaspect */
-                       p->pixelaspect.numerator = 1;
-                       p->pixelaspect.denominator = 1;
-               }
+static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_queryctrl *p = arg;
+       struct v4l2_fh *vfh = fh;
+
+       if (vfh && vfh->ctrl_handler)
+               return v4l2_queryctrl(vfh->ctrl_handler, p);
+       if (vfd->ctrl_handler)
+               return v4l2_queryctrl(vfd->ctrl_handler, p);
+       if (ops->vidioc_queryctrl)
+               return ops->vidioc_queryctrl(file, fh, p);
+       return -ENOTTY;
+}
 
-               if (!ret) {
-                       dbgrect(vfd, "bounds ", &p->bounds);
-                       dbgrect(vfd, "defrect ", &p->defrect);
-               }
-               break;
-       }
-       case VIDIOC_G_JPEGCOMP:
-       {
-               struct v4l2_jpegcompression *p = arg;
-
-               ret = ops->vidioc_g_jpegcomp(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "quality=%d, APPn=%d, "
-                                       "APP_len=%d, COM_len=%d, "
-                                       "jpeg_markers=%d\n",
-                                       p->quality, p->APPn, p->APP_len,
-                                       p->COM_len, p->jpeg_markers);
-               break;
-       }
-       case VIDIOC_S_JPEGCOMP:
-       {
-               struct v4l2_jpegcompression *p = arg;
-
-               dbgarg(cmd, "quality=%d, APPn=%d, APP_len=%d, "
-                                       "COM_len=%d, jpeg_markers=%d\n",
-                                       p->quality, p->APPn, p->APP_len,
-                                       p->COM_len, p->jpeg_markers);
-               ret = ops->vidioc_s_jpegcomp(file, fh, p);
-               break;
-       }
-       case VIDIOC_G_ENC_INDEX:
-       {
-               struct v4l2_enc_idx *p = arg;
-
-               ret = ops->vidioc_g_enc_index(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "entries=%d, entries_cap=%d\n",
-                                       p->entries, p->entries_cap);
-               break;
-       }
-       case VIDIOC_ENCODER_CMD:
-       {
-               struct v4l2_encoder_cmd *p = arg;
+static int v4l_querymenu(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_querymenu *p = arg;
+       struct v4l2_fh *vfh = fh;
+
+       if (vfh && vfh->ctrl_handler)
+               return v4l2_querymenu(vfh->ctrl_handler, p);
+       if (vfd->ctrl_handler)
+               return v4l2_querymenu(vfd->ctrl_handler, p);
+       if (ops->vidioc_querymenu)
+               return ops->vidioc_querymenu(file, fh, p);
+       return -ENOTTY;
+}
 
-               ret = ops->vidioc_encoder_cmd(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
-               break;
+static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_control *p = arg;
+       struct v4l2_fh *vfh = fh;
+       struct v4l2_ext_controls ctrls;
+       struct v4l2_ext_control ctrl;
+
+       if (vfh && vfh->ctrl_handler)
+               return v4l2_g_ctrl(vfh->ctrl_handler, p);
+       if (vfd->ctrl_handler)
+               return v4l2_g_ctrl(vfd->ctrl_handler, p);
+       if (ops->vidioc_g_ctrl)
+               return ops->vidioc_g_ctrl(file, fh, p);
+       if (ops->vidioc_g_ext_ctrls == NULL)
+               return -ENOTTY;
+
+       ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
+       ctrls.count = 1;
+       ctrls.controls = &ctrl;
+       ctrl.id = p->id;
+       ctrl.value = p->value;
+       if (check_ext_ctrls(&ctrls, 1)) {
+               int ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls);
+
+               if (ret == 0)
+                       p->value = ctrl.value;
+               return ret;
        }
-       case VIDIOC_TRY_ENCODER_CMD:
-       {
-               struct v4l2_encoder_cmd *p = arg;
+       return -EINVAL;
+}
 
-               ret = ops->vidioc_try_encoder_cmd(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
-               break;
-       }
-       case VIDIOC_DECODER_CMD:
-       {
-               struct v4l2_decoder_cmd *p = arg;
+static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_control *p = arg;
+       struct v4l2_fh *vfh = fh;
+       struct v4l2_ext_controls ctrls;
+       struct v4l2_ext_control ctrl;
+
+       if (vfh && vfh->ctrl_handler)
+               return v4l2_s_ctrl(vfh, vfh->ctrl_handler, p);
+       if (vfd->ctrl_handler)
+               return v4l2_s_ctrl(NULL, vfd->ctrl_handler, p);
+       if (ops->vidioc_s_ctrl)
+               return ops->vidioc_s_ctrl(file, fh, p);
+       if (ops->vidioc_s_ext_ctrls == NULL)
+               return -ENOTTY;
+
+       ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
+       ctrls.count = 1;
+       ctrls.controls = &ctrl;
+       ctrl.id = p->id;
+       ctrl.value = p->value;
+       if (check_ext_ctrls(&ctrls, 1))
+               return ops->vidioc_s_ext_ctrls(file, fh, &ctrls);
+       return -EINVAL;
+}
 
-               ret = ops->vidioc_decoder_cmd(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
-               break;
-       }
-       case VIDIOC_TRY_DECODER_CMD:
-       {
-               struct v4l2_decoder_cmd *p = arg;
+static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_ext_controls *p = arg;
+       struct v4l2_fh *vfh = fh;
+
+       p->error_idx = p->count;
+       if (vfh && vfh->ctrl_handler)
+               return v4l2_g_ext_ctrls(vfh->ctrl_handler, p);
+       if (vfd->ctrl_handler)
+               return v4l2_g_ext_ctrls(vfd->ctrl_handler, p);
+       if (ops->vidioc_g_ext_ctrls == NULL)
+               return -ENOTTY;
+       return check_ext_ctrls(p, 0) ? ops->vidioc_g_ext_ctrls(file, fh, p) :
+                                       -EINVAL;
+}
 
-               ret = ops->vidioc_try_decoder_cmd(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
-               break;
-       }
-       case VIDIOC_G_PARM:
-       {
-               struct v4l2_streamparm *p = arg;
+static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_ext_controls *p = arg;
+       struct v4l2_fh *vfh = fh;
+
+       p->error_idx = p->count;
+       if (vfh && vfh->ctrl_handler)
+               return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p);
+       if (vfd->ctrl_handler)
+               return v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, p);
+       if (ops->vidioc_s_ext_ctrls == NULL)
+               return -ENOTTY;
+       return check_ext_ctrls(p, 0) ? ops->vidioc_s_ext_ctrls(file, fh, p) :
+                                       -EINVAL;
+}
 
-               if (ops->vidioc_g_parm) {
-                       ret = check_fmt(ops, p->type);
-                       if (ret)
-                               break;
-                       ret = ops->vidioc_g_parm(file, fh, p);
-               } else {
-                       v4l2_std_id std = vfd->current_norm;
+static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_ext_controls *p = arg;
+       struct v4l2_fh *vfh = fh;
+
+       p->error_idx = p->count;
+       if (vfh && vfh->ctrl_handler)
+               return v4l2_try_ext_ctrls(vfh->ctrl_handler, p);
+       if (vfd->ctrl_handler)
+               return v4l2_try_ext_ctrls(vfd->ctrl_handler, p);
+       if (ops->vidioc_try_ext_ctrls == NULL)
+               return -ENOTTY;
+       return check_ext_ctrls(p, 0) ? ops->vidioc_try_ext_ctrls(file, fh, p) :
+                                       -EINVAL;
+}
 
-                       ret = -EINVAL;
-                       if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                               break;
+static int v4l_g_crop(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_crop *p = arg;
+       struct v4l2_selection s = {
+               .type = p->type,
+       };
+       int ret;
+
+       if (ops->vidioc_g_crop)
+               return ops->vidioc_g_crop(file, fh, p);
+       /* simulate capture crop using selection api */
+
+       /* crop means compose for output devices */
+       if (V4L2_TYPE_IS_OUTPUT(p->type))
+               s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
+       else
+               s.target = V4L2_SEL_TGT_CROP_ACTIVE;
+
+       ret = ops->vidioc_g_selection(file, fh, &s);
+
+       /* copying results to old structure on success */
+       if (!ret)
+               p->c = s.r;
+       return ret;
+}
 
-                       ret = 0;
-                       p->parm.capture.readbuffers = 2;
-                       if (ops->vidioc_g_std)
-                               ret = ops->vidioc_g_std(file, fh, &std);
-                       if (ret == 0)
-                               v4l2_video_std_frame_period(std,
-                                                   &p->parm.capture.timeperframe);
-               }
+static int v4l_s_crop(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_crop *p = arg;
+       struct v4l2_selection s = {
+               .type = p->type,
+               .r = p->c,
+       };
+
+       if (ops->vidioc_s_crop)
+               return ops->vidioc_s_crop(file, fh, p);
+       /* simulate capture crop using selection api */
+
+       /* crop means compose for output devices */
+       if (V4L2_TYPE_IS_OUTPUT(p->type))
+               s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
+       else
+               s.target = V4L2_SEL_TGT_CROP_ACTIVE;
+
+       return ops->vidioc_s_selection(file, fh, &s);
+}
 
-               dbgarg(cmd, "type=%d\n", p->type);
-               break;
-       }
-       case VIDIOC_S_PARM:
-       {
-               struct v4l2_streamparm *p = arg;
+static int v4l_cropcap(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_cropcap *p = arg;
+       struct v4l2_selection s = { .type = p->type };
+       int ret;
 
-               ret = check_fmt(ops, p->type);
-               if (ret)
-                       break;
+       if (ops->vidioc_cropcap)
+               return ops->vidioc_cropcap(file, fh, p);
 
-               dbgarg(cmd, "type=%d\n", p->type);
-               ret = ops->vidioc_s_parm(file, fh, p);
-               break;
-       }
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *p = arg;
+       /* obtaining bounds */
+       if (V4L2_TYPE_IS_OUTPUT(p->type))
+               s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS;
+       else
+               s.target = V4L2_SEL_TGT_CROP_BOUNDS;
 
-               p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
-                       V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-               ret = ops->vidioc_g_tuner(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "index=%d, name=%s, type=%d, "
-                                       "capability=0x%x, rangelow=%d, "
-                                       "rangehigh=%d, signal=%d, afc=%d, "
-                                       "rxsubchans=0x%x, audmode=%d\n",
-                                       p->index, p->name, p->type,
-                                       p->capability, p->rangelow,
-                                       p->rangehigh, p->signal, p->afc,
-                                       p->rxsubchans, p->audmode);
-               break;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *p = arg;
+       ret = ops->vidioc_g_selection(file, fh, &s);
+       if (ret)
+               return ret;
+       p->bounds = s.r;
 
-               p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
-                       V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-               dbgarg(cmd, "index=%d, name=%s, type=%d, "
-                               "capability=0x%x, rangelow=%d, "
-                               "rangehigh=%d, signal=%d, afc=%d, "
-                               "rxsubchans=0x%x, audmode=%d\n",
-                               p->index, p->name, p->type,
-                               p->capability, p->rangelow,
-                               p->rangehigh, p->signal, p->afc,
-                               p->rxsubchans, p->audmode);
-               ret = ops->vidioc_s_tuner(file, fh, p);
-               break;
-       }
-       case VIDIOC_G_FREQUENCY:
-       {
-               struct v4l2_frequency *p = arg;
+       /* obtaining defrect */
+       if (V4L2_TYPE_IS_OUTPUT(p->type))
+               s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
+       else
+               s.target = V4L2_SEL_TGT_CROP_DEFAULT;
 
-               p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
-                       V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-               ret = ops->vidioc_g_frequency(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
-                                       p->tuner, p->type, p->frequency);
-               break;
-       }
-       case VIDIOC_S_FREQUENCY:
-       {
-               struct v4l2_frequency *p = arg;
-               enum v4l2_tuner_type type;
+       ret = ops->vidioc_g_selection(file, fh, &s);
+       if (ret)
+               return ret;
+       p->defrect = s.r;
 
-               type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
-                       V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-               dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
-                               p->tuner, p->type, p->frequency);
-               if (p->type != type)
-                       ret = -EINVAL;
-               else
-                       ret = ops->vidioc_s_frequency(file, fh, p);
-               break;
-       }
-       case VIDIOC_G_SLICED_VBI_CAP:
-       {
-               struct v4l2_sliced_vbi_cap *p = arg;
+       /* setting trivial pixelaspect */
+       p->pixelaspect.numerator = 1;
+       p->pixelaspect.denominator = 1;
+       return 0;
+}
 
-               /* Clear up to type, everything after type is zerod already */
-               memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type));
+static int v4l_log_status(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       int ret;
+
+       if (vfd->v4l2_dev)
+               pr_info("%s: =================  START STATUS  =================\n",
+                       vfd->v4l2_dev->name);
+       ret = ops->vidioc_log_status(file, fh);
+       if (vfd->v4l2_dev)
+               pr_info("%s: ==================  END STATUS  ==================\n",
+                       vfd->v4l2_dev->name);
+       return ret;
+}
 
-               dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
-               ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p);
-               if (!ret)
-                       dbgarg2("service_set=%d\n", p->service_set);
-               break;
-       }
-       case VIDIOC_LOG_STATUS:
-       {
-               if (vfd->v4l2_dev)
-                       pr_info("%s: =================  START STATUS  =================\n",
-                               vfd->v4l2_dev->name);
-               ret = ops->vidioc_log_status(file, fh);
-               if (vfd->v4l2_dev)
-                       pr_info("%s: ==================  END STATUS  ==================\n",
-                               vfd->v4l2_dev->name);
-               break;
-       }
-       case VIDIOC_DBG_G_REGISTER:
-       {
+static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-               struct v4l2_dbg_register *p = arg;
+       struct v4l2_dbg_register *p = arg;
 
-               if (!capable(CAP_SYS_ADMIN))
-                       ret = -EPERM;
-               else
-                       ret = ops->vidioc_g_register(file, fh, p);
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       return ops->vidioc_g_register(file, fh, p);
+#else
+       return -ENOTTY;
 #endif
-               break;
-       }
-       case VIDIOC_DBG_S_REGISTER:
-       {
+}
+
+static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-               struct v4l2_dbg_register *p = arg;
+       struct v4l2_dbg_register *p = arg;
 
-               if (!capable(CAP_SYS_ADMIN))
-                       ret = -EPERM;
-               else
-                       ret = ops->vidioc_s_register(file, fh, p);
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       return ops->vidioc_s_register(file, fh, p);
+#else
+       return -ENOTTY;
 #endif
-               break;
-       }
-       case VIDIOC_DBG_G_CHIP_IDENT:
-       {
-               struct v4l2_dbg_chip_ident *p = arg;
-
-               p->ident = V4L2_IDENT_NONE;
-               p->revision = 0;
-               ret = ops->vidioc_g_chip_ident(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
-               break;
-       }
-       case VIDIOC_S_HW_FREQ_SEEK:
-       {
-               struct v4l2_hw_freq_seek *p = arg;
-               enum v4l2_tuner_type type;
+}
 
-               type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
-                       V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-               dbgarg(cmd,
-                       "tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u\n",
-                       p->tuner, p->type, p->seek_upward, p->wrap_around, p->spacing);
-               if (p->type != type)
-                       ret = -EINVAL;
-               else
-                       ret = ops->vidioc_s_hw_freq_seek(file, fh, p);
-               break;
-       }
-       case VIDIOC_ENUM_FRAMESIZES:
-       {
-               struct v4l2_frmsizeenum *p = arg;
+static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_dbg_chip_ident *p = arg;
 
-               ret = ops->vidioc_enum_framesizes(file, fh, p);
-               dbgarg(cmd,
-                       "index=%d, pixelformat=%c%c%c%c, type=%d ",
-                       p->index,
-                       (p->pixel_format & 0xff),
-                       (p->pixel_format >>  8) & 0xff,
-                       (p->pixel_format >> 16) & 0xff,
-                       (p->pixel_format >> 24) & 0xff,
-                       p->type);
-               switch (p->type) {
-               case V4L2_FRMSIZE_TYPE_DISCRETE:
-                       dbgarg3("width = %d, height=%d\n",
-                               p->discrete.width, p->discrete.height);
-                       break;
-               case V4L2_FRMSIZE_TYPE_STEPWISE:
-                       dbgarg3("min %dx%d, max %dx%d, step %dx%d\n",
-                               p->stepwise.min_width,  p->stepwise.min_height,
-                               p->stepwise.step_width, p->stepwise.step_height,
-                               p->stepwise.max_width,  p->stepwise.max_height);
-                       break;
-               case V4L2_FRMSIZE_TYPE_CONTINUOUS:
-                       dbgarg3("continuous\n");
-                       break;
-               default:
-                       dbgarg3("- Unknown type!\n");
-               }
+       p->ident = V4L2_IDENT_NONE;
+       p->revision = 0;
+       return ops->vidioc_g_chip_ident(file, fh, p);
+}
 
-               break;
-       }
-       case VIDIOC_ENUM_FRAMEINTERVALS:
-       {
-               struct v4l2_frmivalenum *p = arg;
-
-               ret = ops->vidioc_enum_frameintervals(file, fh, p);
-               dbgarg(cmd,
-                       "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ",
-                       p->index, p->pixel_format,
-                       p->width, p->height, p->type);
-               switch (p->type) {
-               case V4L2_FRMIVAL_TYPE_DISCRETE:
-                       dbgarg2("fps=%d/%d\n",
-                               p->discrete.numerator,
-                               p->discrete.denominator);
-                       break;
-               case V4L2_FRMIVAL_TYPE_STEPWISE:
-                       dbgarg2("min=%d/%d, max=%d/%d, step=%d/%d\n",
-                               p->stepwise.min.numerator,
-                               p->stepwise.min.denominator,
-                               p->stepwise.max.numerator,
-                               p->stepwise.max.denominator,
-                               p->stepwise.step.numerator,
-                               p->stepwise.step.denominator);
-                       break;
-               case V4L2_FRMIVAL_TYPE_CONTINUOUS:
-                       dbgarg2("continuous\n");
-                       break;
-               default:
-                       dbgarg2("- Unknown type!\n");
-               }
-               break;
-       }
-       case VIDIOC_ENUM_DV_PRESETS:
-       {
-               struct v4l2_dv_enum_preset *p = arg;
-
-               ret = ops->vidioc_enum_dv_presets(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd,
-                               "index=%d, preset=%d, name=%s, width=%d,"
-                               " height=%d ",
-                               p->index, p->preset, p->name, p->width,
-                               p->height);
-               break;
-       }
-       case VIDIOC_S_DV_PRESET:
-       {
-               struct v4l2_dv_preset *p = arg;
+static int v4l_dqevent(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK);
+}
 
-               dbgarg(cmd, "preset=%d\n", p->preset);
-               ret = ops->vidioc_s_dv_preset(file, fh, p);
-               break;
-       }
-       case VIDIOC_G_DV_PRESET:
-       {
-               struct v4l2_dv_preset *p = arg;
+static int v4l_subscribe_event(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       return ops->vidioc_subscribe_event(fh, arg);
+}
 
-               ret = ops->vidioc_g_dv_preset(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "preset=%d\n", p->preset);
-               break;
-       }
-       case VIDIOC_QUERY_DV_PRESET:
-       {
-               struct v4l2_dv_preset *p = arg;
+static int v4l_unsubscribe_event(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       return ops->vidioc_unsubscribe_event(fh, arg);
+}
 
-               ret = ops->vidioc_query_dv_preset(file, fh, p);
-               if (!ret)
-                       dbgarg(cmd, "preset=%d\n", p->preset);
-               break;
-       }
-       case VIDIOC_S_DV_TIMINGS:
-       {
-               struct v4l2_dv_timings *p = arg;
-
-               dbgtimings(vfd, p);
-               switch (p->type) {
-               case V4L2_DV_BT_656_1120:
-                       ret = ops->vidioc_s_dv_timings(file, fh, p);
-                       break;
-               default:
-                       ret = -EINVAL;
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_G_DV_TIMINGS:
-       {
-               struct v4l2_dv_timings *p = arg;
+static int v4l_g_sliced_vbi_cap(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *arg)
+{
+       struct v4l2_sliced_vbi_cap *p = arg;
 
-               ret = ops->vidioc_g_dv_timings(file, fh, p);
-               if (!ret)
-                       dbgtimings(vfd, p);
-               break;
-       }
-       case VIDIOC_ENUM_DV_TIMINGS:
-       {
-               struct v4l2_enum_dv_timings *p = arg;
+       /* Clear up to type, everything after type is zeroed already */
+       memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type));
 
-               if (!ops->vidioc_enum_dv_timings)
-                       break;
+       return ops->vidioc_g_sliced_vbi_cap(file, fh, p);
+}
 
-               ret = ops->vidioc_enum_dv_timings(file, fh, p);
-               if (!ret) {
-                       dbgarg(cmd, "index=%d: ", p->index);
-                       dbgtimings(vfd, &p->timings);
-               }
-               break;
+struct v4l2_ioctl_info {
+       unsigned int ioctl;
+       u32 flags;
+       const char * const name;
+       union {
+               u32 offset;
+               int (*func)(const struct v4l2_ioctl_ops *ops,
+                               struct file *file, void *fh, void *p);
+       };
+       void (*debug)(const void *arg, bool write_only);
+};
+
+/* This control needs a priority check */
+#define INFO_FL_PRIO   (1 << 0)
+/* This control can be valid if the filehandle passes a control handler. */
+#define INFO_FL_CTRL   (1 << 1)
+/* This is a standard ioctl, no need for special code */
+#define INFO_FL_STD    (1 << 2)
+/* This is ioctl has its own function */
+#define INFO_FL_FUNC   (1 << 3)
+/* Queuing ioctl */
+#define INFO_FL_QUEUE  (1 << 4)
+/* Zero struct from after the field to the end */
+#define INFO_FL_CLEAR(v4l2_struct, field)                      \
+       ((offsetof(struct v4l2_struct, field) +                 \
+         sizeof(((struct v4l2_struct *)0)->field)) << 16)
+#define INFO_FL_CLEAR_MASK (_IOC_SIZEMASK << 16)
+
+#define IOCTL_INFO_STD(_ioctl, _vidioc, _debug, _flags)                        \
+       [_IOC_NR(_ioctl)] = {                                           \
+               .ioctl = _ioctl,                                        \
+               .flags = _flags | INFO_FL_STD,                          \
+               .name = #_ioctl,                                        \
+               .offset = offsetof(struct v4l2_ioctl_ops, _vidioc),     \
+               .debug = _debug,                                        \
+       }
+
+#define IOCTL_INFO_FNC(_ioctl, _func, _debug, _flags)                  \
+       [_IOC_NR(_ioctl)] = {                                           \
+               .ioctl = _ioctl,                                        \
+               .flags = _flags | INFO_FL_FUNC,                         \
+               .name = #_ioctl,                                        \
+               .func = _func,                                          \
+               .debug = _debug,                                        \
        }
-       case VIDIOC_QUERY_DV_TIMINGS:
-       {
-               struct v4l2_dv_timings *p = arg;
 
-               if (!ops->vidioc_query_dv_timings)
-                       break;
+static struct v4l2_ioctl_info v4l2_ioctls[] = {
+       IOCTL_INFO_FNC(VIDIOC_QUERYCAP, v4l_querycap, v4l_print_querycap, 0),
+       IOCTL_INFO_FNC(VIDIOC_ENUM_FMT, v4l_enum_fmt, v4l_print_fmtdesc, INFO_FL_CLEAR(v4l2_fmtdesc, type)),
+       IOCTL_INFO_FNC(VIDIOC_G_FMT, v4l_g_fmt, v4l_print_format, INFO_FL_CLEAR(v4l2_format, type)),
+       IOCTL_INFO_FNC(VIDIOC_S_FMT, v4l_s_fmt, v4l_print_format, INFO_FL_PRIO),
+       IOCTL_INFO_FNC(VIDIOC_REQBUFS, v4l_reqbufs, v4l_print_requestbuffers, INFO_FL_PRIO | INFO_FL_QUEUE),
+       IOCTL_INFO_FNC(VIDIOC_QUERYBUF, v4l_querybuf, v4l_print_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_buffer, length)),
+       IOCTL_INFO_STD(VIDIOC_G_FBUF, vidioc_g_fbuf, v4l_print_framebuffer, 0),
+       IOCTL_INFO_STD(VIDIOC_S_FBUF, vidioc_s_fbuf, v4l_print_framebuffer, INFO_FL_PRIO),
+       IOCTL_INFO_STD(VIDIOC_OVERLAY, vidioc_overlay, v4l_print_u32, INFO_FL_PRIO),
+       IOCTL_INFO_FNC(VIDIOC_QBUF, v4l_qbuf, v4l_print_buffer, INFO_FL_QUEUE),
+       IOCTL_INFO_FNC(VIDIOC_DQBUF, v4l_dqbuf, v4l_print_buffer, INFO_FL_QUEUE),
+       IOCTL_INFO_FNC(VIDIOC_STREAMON, v4l_streamon, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE),
+       IOCTL_INFO_FNC(VIDIOC_STREAMOFF, v4l_streamoff, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE),
+       IOCTL_INFO_FNC(VIDIOC_G_PARM, v4l_g_parm, v4l_print_streamparm, INFO_FL_CLEAR(v4l2_streamparm, type)),
+       IOCTL_INFO_FNC(VIDIOC_S_PARM, v4l_s_parm, v4l_print_streamparm, INFO_FL_PRIO),
+       IOCTL_INFO_FNC(VIDIOC_G_STD, v4l_g_std, v4l_print_std, 0),
+       IOCTL_INFO_FNC(VIDIOC_S_STD, v4l_s_std, v4l_print_std, INFO_FL_PRIO),
+       IOCTL_INFO_FNC(VIDIOC_ENUMSTD, v4l_enumstd, v4l_print_standard, INFO_FL_CLEAR(v4l2_standard, index)),
+       IOCTL_INFO_FNC(VIDIOC_ENUMINPUT, v4l_enuminput, v4l_print_enuminput, INFO_FL_CLEAR(v4l2_input, index)),
+       IOCTL_INFO_FNC(VIDIOC_G_CTRL, v4l_g_ctrl, v4l_print_control, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_control, id)),
+       IOCTL_INFO_FNC(VIDIOC_S_CTRL, v4l_s_ctrl, v4l_print_control, INFO_FL_PRIO | INFO_FL_CTRL),
+       IOCTL_INFO_FNC(VIDIOC_G_TUNER, v4l_g_tuner, v4l_print_tuner, INFO_FL_CLEAR(v4l2_tuner, index)),
+       IOCTL_INFO_FNC(VIDIOC_S_TUNER, v4l_s_tuner, v4l_print_tuner, INFO_FL_PRIO),
+       IOCTL_INFO_STD(VIDIOC_G_AUDIO, vidioc_g_audio, v4l_print_audio, 0),
+       IOCTL_INFO_STD(VIDIOC_S_AUDIO, vidioc_s_audio, v4l_print_audio, INFO_FL_PRIO),
+       IOCTL_INFO_FNC(VIDIOC_QUERYCTRL, v4l_queryctrl, v4l_print_queryctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_queryctrl, id)),
+       IOCTL_INFO_FNC(VIDIOC_QUERYMENU, v4l_querymenu, v4l_print_querymenu, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_querymenu, index)),
+       IOCTL_INFO_STD(VIDIOC_G_INPUT, vidioc_g_input, v4l_print_u32, 0),
+       IOCTL_INFO_FNC(VIDIOC_S_INPUT, v4l_s_input, v4l_print_u32, INFO_FL_PRIO),
+       IOCTL_INFO_STD(VIDIOC_G_OUTPUT, vidioc_g_output, v4l_print_u32, 0),
+       IOCTL_INFO_FNC(VIDIOC_S_OUTPUT, v4l_s_output, v4l_print_u32, INFO_FL_PRIO),
+       IOCTL_INFO_FNC(VIDIOC_ENUMOUTPUT, v4l_enumoutput, v4l_print_enumoutput, INFO_FL_CLEAR(v4l2_output, index)),
+       IOCTL_INFO_STD(VIDIOC_G_AUDOUT, vidioc_g_audout, v4l_print_audioout, 0),
+       IOCTL_INFO_STD(VIDIOC_S_AUDOUT, vidioc_s_audout, v4l_print_audioout, INFO_FL_PRIO),
+       IOCTL_INFO_STD(VIDIOC_G_MODULATOR, vidioc_g_modulator, v4l_print_modulator, INFO_FL_CLEAR(v4l2_modulator, index)),
+       IOCTL_INFO_STD(VIDIOC_S_MODULATOR, vidioc_s_modulator, v4l_print_modulator, INFO_FL_PRIO),
+       IOCTL_INFO_FNC(VIDIOC_G_FREQUENCY, v4l_g_frequency, v4l_print_frequency, INFO_FL_CLEAR(v4l2_frequency, tuner)),
+       IOCTL_INFO_FNC(VIDIOC_S_FREQUENCY, v4l_s_frequency, v4l_print_frequency, INFO_FL_PRIO),
+       IOCTL_INFO_FNC(VIDIOC_CROPCAP, v4l_cropcap, v4l_print_cropcap, INFO_FL_CLEAR(v4l2_cropcap, type)),
+       IOCTL_INFO_FNC(VIDIOC_G_CROP, v4l_g_crop, v4l_print_crop, INFO_FL_CLEAR(v4l2_crop, type)),
+       IOCTL_INFO_FNC(VIDIOC_S_CROP, v4l_s_crop, v4l_print_crop, INFO_FL_PRIO),
+       IOCTL_INFO_STD(VIDIOC_G_SELECTION, vidioc_g_selection, v4l_print_selection, 0),
+       IOCTL_INFO_STD(VIDIOC_S_SELECTION, vidioc_s_selection, v4l_print_selection, INFO_FL_PRIO),
+       IOCTL_INFO_STD(VIDIOC_G_JPEGCOMP, vidioc_g_jpegcomp, v4l_print_jpegcompression, 0),
+       IOCTL_INFO_STD(VIDIOC_S_JPEGCOMP, vidioc_s_jpegcomp, v4l_print_jpegcompression, INFO_FL_PRIO),
+       IOCTL_INFO_FNC(VIDIOC_QUERYSTD, v4l_querystd, v4l_print_std, 0),
+       IOCTL_INFO_FNC(VIDIOC_TRY_FMT, v4l_try_fmt, v4l_print_format, 0),
+       IOCTL_INFO_STD(VIDIOC_ENUMAUDIO, vidioc_enumaudio, v4l_print_audio, INFO_FL_CLEAR(v4l2_audio, index)),
+       IOCTL_INFO_STD(VIDIOC_ENUMAUDOUT, vidioc_enumaudout, v4l_print_audioout, INFO_FL_CLEAR(v4l2_audioout, index)),
+       IOCTL_INFO_FNC(VIDIOC_G_PRIORITY, v4l_g_priority, v4l_print_u32, 0),
+       IOCTL_INFO_FNC(VIDIOC_S_PRIORITY, v4l_s_priority, v4l_print_u32, INFO_FL_PRIO),
+       IOCTL_INFO_FNC(VIDIOC_G_SLICED_VBI_CAP, v4l_g_sliced_vbi_cap, v4l_print_sliced_vbi_cap, INFO_FL_CLEAR(v4l2_sliced_vbi_cap, type)),
+       IOCTL_INFO_FNC(VIDIOC_LOG_STATUS, v4l_log_status, v4l_print_newline, 0),
+       IOCTL_INFO_FNC(VIDIOC_G_EXT_CTRLS, v4l_g_ext_ctrls, v4l_print_ext_controls, INFO_FL_CTRL),
+       IOCTL_INFO_FNC(VIDIOC_S_EXT_CTRLS, v4l_s_ext_ctrls, v4l_print_ext_controls, INFO_FL_PRIO | INFO_FL_CTRL),
+       IOCTL_INFO_FNC(VIDIOC_TRY_EXT_CTRLS, v4l_try_ext_ctrls, v4l_print_ext_controls, 0),
+       IOCTL_INFO_STD(VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes, v4l_print_frmsizeenum, INFO_FL_CLEAR(v4l2_frmsizeenum, pixel_format)),
+       IOCTL_INFO_STD(VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals, v4l_print_frmivalenum, INFO_FL_CLEAR(v4l2_frmivalenum, height)),
+       IOCTL_INFO_STD(VIDIOC_G_ENC_INDEX, vidioc_g_enc_index, v4l_print_enc_idx, 0),
+       IOCTL_INFO_STD(VIDIOC_ENCODER_CMD, vidioc_encoder_cmd, v4l_print_encoder_cmd, INFO_FL_PRIO | INFO_FL_CLEAR(v4l2_encoder_cmd, flags)),
+       IOCTL_INFO_STD(VIDIOC_TRY_ENCODER_CMD, vidioc_try_encoder_cmd, v4l_print_encoder_cmd, INFO_FL_CLEAR(v4l2_encoder_cmd, flags)),
+       IOCTL_INFO_STD(VIDIOC_DECODER_CMD, vidioc_decoder_cmd, v4l_print_decoder_cmd, INFO_FL_PRIO),
+       IOCTL_INFO_STD(VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd, v4l_print_decoder_cmd, 0),
+       IOCTL_INFO_FNC(VIDIOC_DBG_S_REGISTER, v4l_dbg_s_register, v4l_print_dbg_register, 0),
+       IOCTL_INFO_FNC(VIDIOC_DBG_G_REGISTER, v4l_dbg_g_register, v4l_print_dbg_register, 0),
+       IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_IDENT, v4l_dbg_g_chip_ident, v4l_print_dbg_chip_ident, 0),
+       IOCTL_INFO_FNC(VIDIOC_S_HW_FREQ_SEEK, v4l_s_hw_freq_seek, v4l_print_hw_freq_seek, INFO_FL_PRIO),
+       IOCTL_INFO_STD(VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets, v4l_print_dv_enum_presets, 0),
+       IOCTL_INFO_STD(VIDIOC_S_DV_PRESET, vidioc_s_dv_preset, v4l_print_dv_preset, INFO_FL_PRIO),
+       IOCTL_INFO_STD(VIDIOC_G_DV_PRESET, vidioc_g_dv_preset, v4l_print_dv_preset, 0),
+       IOCTL_INFO_STD(VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset, v4l_print_dv_preset, 0),
+       IOCTL_INFO_STD(VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings, v4l_print_dv_timings, INFO_FL_PRIO),
+       IOCTL_INFO_STD(VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings, v4l_print_dv_timings, 0),
+       IOCTL_INFO_FNC(VIDIOC_DQEVENT, v4l_dqevent, v4l_print_event, 0),
+       IOCTL_INFO_FNC(VIDIOC_SUBSCRIBE_EVENT, v4l_subscribe_event, v4l_print_event_subscription, 0),
+       IOCTL_INFO_FNC(VIDIOC_UNSUBSCRIBE_EVENT, v4l_unsubscribe_event, v4l_print_event_subscription, 0),
+       IOCTL_INFO_FNC(VIDIOC_CREATE_BUFS, v4l_create_bufs, v4l_print_create_buffers, INFO_FL_PRIO | INFO_FL_QUEUE),
+       IOCTL_INFO_FNC(VIDIOC_PREPARE_BUF, v4l_prepare_buf, v4l_print_buffer, INFO_FL_QUEUE),
+       IOCTL_INFO_STD(VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings, v4l_print_enum_dv_timings, 0),
+       IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, 0),
+       IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, 0),
+};
+#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
-               ret = ops->vidioc_query_dv_timings(file, fh, p);
-               if (!ret)
-                       dbgtimings(vfd, p);
-               break;
-       }
-       case VIDIOC_DV_TIMINGS_CAP:
-       {
-               struct v4l2_dv_timings_cap *p = arg;
+bool v4l2_is_known_ioctl(unsigned int cmd)
+{
+       if (_IOC_NR(cmd) >= V4L2_IOCTLS)
+               return false;
+       return v4l2_ioctls[_IOC_NR(cmd)].ioctl == cmd;
+}
 
-               if (!ops->vidioc_dv_timings_cap)
-                       break;
+struct mutex *v4l2_ioctl_get_lock(struct video_device *vdev, unsigned cmd)
+{
+       if (_IOC_NR(cmd) >= V4L2_IOCTLS)
+               return vdev->lock;
+       if (test_bit(_IOC_NR(cmd), vdev->disable_locking))
+               return NULL;
+       if (vdev->queue && vdev->queue->lock &&
+                       (v4l2_ioctls[_IOC_NR(cmd)].flags & INFO_FL_QUEUE))
+               return vdev->queue->lock;
+       return vdev->lock;
+}
 
-               ret = ops->vidioc_dv_timings_cap(file, fh, p);
-               if (ret)
-                       break;
-               switch (p->type) {
-               case V4L2_DV_BT_656_1120:
-                       dbgarg(cmd,
-                              "type=%d, width=%u-%u, height=%u-%u, "
-                              "pixelclock=%llu-%llu, standards=%x, capabilities=%x ",
-                              p->type,
-                              p->bt.min_width, p->bt.max_width,
-                              p->bt.min_height, p->bt.max_height,
-                              p->bt.min_pixelclock, p->bt.max_pixelclock,
-                              p->bt.standards, p->bt.capabilities);
-                       break;
-               default:
-                       dbgarg(cmd, "unknown type ");
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_DQEVENT:
-       {
-               struct v4l2_event *ev = arg;
+/* Common ioctl debug function. This function can be used by
+   external ioctl messages as well as internal V4L ioctl */
+void v4l_printk_ioctl(const char *prefix, unsigned int cmd)
+{
+       const char *dir, *type;
 
-               ret = v4l2_event_dequeue(fh, ev, file->f_flags & O_NONBLOCK);
-               if (ret < 0) {
-                       dbgarg(cmd, "no pending events?");
-                       break;
-               }
-               dbgarg(cmd,
-                      "pending=%d, type=0x%8.8x, sequence=%d, "
-                      "timestamp=%lu.%9.9lu ",
-                      ev->pending, ev->type, ev->sequence,
-                      ev->timestamp.tv_sec, ev->timestamp.tv_nsec);
-               break;
-       }
-       case VIDIOC_SUBSCRIBE_EVENT:
-       {
-               struct v4l2_event_subscription *sub = arg;
+       if (prefix)
+               printk(KERN_DEBUG "%s: ", prefix);
 
-               ret = ops->vidioc_subscribe_event(fh, sub);
-               if (ret < 0) {
-                       dbgarg(cmd, "failed, ret=%ld", ret);
-                       break;
-               }
-               dbgarg(cmd, "type=0x%8.8x", sub->type);
+       switch (_IOC_TYPE(cmd)) {
+       case 'd':
+               type = "v4l2_int";
                break;
-       }
-       case VIDIOC_UNSUBSCRIBE_EVENT:
-       {
-               struct v4l2_event_subscription *sub = arg;
-
-               ret = ops->vidioc_unsubscribe_event(fh, sub);
-               if (ret < 0) {
-                       dbgarg(cmd, "failed, ret=%ld", ret);
+       case 'V':
+               if (_IOC_NR(cmd) >= V4L2_IOCTLS) {
+                       type = "v4l2";
                        break;
                }
-               dbgarg(cmd, "type=0x%8.8x", sub->type);
+               pr_cont("%s", v4l2_ioctls[_IOC_NR(cmd)].name);
+               return;
+       default:
+               type = "unknown";
                break;
        }
-       case VIDIOC_CREATE_BUFS:
-       {
-               struct v4l2_create_buffers *create = arg;
 
-               ret = check_fmt(ops, create->format.type);
-               if (ret)
-                       break;
+       switch (_IOC_DIR(cmd)) {
+       case _IOC_NONE:              dir = "--"; break;
+       case _IOC_READ:              dir = "r-"; break;
+       case _IOC_WRITE:             dir = "-w"; break;
+       case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+       default:                     dir = "*ERR*"; break;
+       }
+       pr_cont("%s ioctl '%c', dir=%s, #%d (0x%08x)",
+               type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
+}
+EXPORT_SYMBOL(v4l_printk_ioctl);
 
-               ret = ops->vidioc_create_bufs(file, fh, create);
+static long __video_do_ioctl(struct file *file,
+               unsigned int cmd, void *arg)
+{
+       struct video_device *vfd = video_devdata(file);
+       const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
+       bool write_only = false;
+       struct v4l2_ioctl_info default_info;
+       const struct v4l2_ioctl_info *info;
+       void *fh = file->private_data;
+       struct v4l2_fh *vfh = NULL;
+       int use_fh_prio = 0;
+       int debug = vfd->debug;
+       long ret = -ENOTTY;
 
-               dbgarg(cmd, "count=%d @ %d\n", create->count, create->index);
-               break;
+       if (ops == NULL) {
+               pr_warn("%s: has no ioctl_ops.\n",
+                               video_device_node_name(vfd));
+               return ret;
        }
-       case VIDIOC_PREPARE_BUF:
-       {
-               struct v4l2_buffer *b = arg;
 
-               ret = check_fmt(ops, b->type);
-               if (ret)
-                       break;
+       if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
+               vfh = file->private_data;
+               use_fh_prio = test_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+       }
 
-               ret = ops->vidioc_prepare_buf(file, fh, b);
+       if (v4l2_is_known_ioctl(cmd)) {
+               info = &v4l2_ioctls[_IOC_NR(cmd)];
 
-               dbgarg(cmd, "index=%d", b->index);
-               break;
-       }
-       default:
-               if (!ops->vidioc_default)
-                       break;
-               ret = ops->vidioc_default(file, fh, use_fh_prio ?
-                               v4l2_prio_check(vfd->prio, vfh->prio) >= 0 : 0,
-                               cmd, arg);
-               break;
-       } /* switch */
+               if (!test_bit(_IOC_NR(cmd), vfd->valid_ioctls) &&
+                   !((info->flags & INFO_FL_CTRL) && vfh && vfh->ctrl_handler))
+                       goto done;
 
-       if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
-               if (ret < 0) {
-                       v4l_print_ioctl(vfd->name, cmd);
-                       printk(KERN_CONT " error %ld\n", ret);
+               if (use_fh_prio && (info->flags & INFO_FL_PRIO)) {
+                       ret = v4l2_prio_check(vfd->prio, vfh->prio);
+                       if (ret)
+                               goto done;
+               }
+       } else {
+               default_info.ioctl = cmd;
+               default_info.flags = 0;
+               default_info.debug = v4l_print_default;
+               info = &default_info;
+       }
+
+       write_only = _IOC_DIR(cmd) == _IOC_WRITE;
+       if (write_only && debug > V4L2_DEBUG_IOCTL) {
+               v4l_printk_ioctl(video_device_node_name(vfd), cmd);
+               pr_cont(": ");
+               info->debug(arg, write_only);
+       }
+       if (info->flags & INFO_FL_STD) {
+               typedef int (*vidioc_op)(struct file *file, void *fh, void *p);
+               const void *p = vfd->ioctl_ops;
+               const vidioc_op *vidioc = p + info->offset;
+
+               ret = (*vidioc)(file, fh, arg);
+       } else if (info->flags & INFO_FL_FUNC) {
+               ret = info->func(ops, file, fh, arg);
+       } else if (!ops->vidioc_default) {
+               ret = -ENOTTY;
+       } else {
+               ret = ops->vidioc_default(file, fh,
+                       use_fh_prio ? v4l2_prio_check(vfd->prio, vfh->prio) >= 0 : 0,
+                       cmd, arg);
+       }
+
+done:
+       if (debug) {
+               if (write_only && debug > V4L2_DEBUG_IOCTL) {
+                       if (ret < 0)
+                               printk(KERN_DEBUG "%s: error %ld\n",
+                                       video_device_node_name(vfd), ret);
+                       return ret;
+               }
+               v4l_printk_ioctl(video_device_node_name(vfd), cmd);
+               if (ret < 0)
+                       pr_cont(": error %ld\n", ret);
+               else if (debug == V4L2_DEBUG_IOCTL)
+                       pr_cont("\n");
+               else if (_IOC_DIR(cmd) == _IOC_NONE)
+                       info->debug(arg, write_only);
+               else {
+                       pr_cont(": ");
+                       info->debug(arg, write_only);
                }
        }
 
        return ret;
 }
 
-/* In some cases, only a few fields are used as input, i.e. when the app sets
- * "index" and then the driver fills in the rest of the structure for the thing
- * with that index.  We only need to copy up the first non-input field.  */
-static unsigned long cmd_input_size(unsigned int cmd)
-{
-       /* Size of structure up to and including 'field' */
-#define CMDINSIZE(cmd, type, field)                            \
-       case VIDIOC_##cmd:                                      \
-               return offsetof(struct v4l2_##type, field) +    \
-                       sizeof(((struct v4l2_##type *)0)->field);
-
-       switch (cmd) {
-               CMDINSIZE(ENUM_FMT,             fmtdesc,        type);
-               CMDINSIZE(G_FMT,                format,         type);
-               CMDINSIZE(QUERYBUF,             buffer,         length);
-               CMDINSIZE(G_PARM,               streamparm,     type);
-               CMDINSIZE(ENUMSTD,              standard,       index);
-               CMDINSIZE(ENUMINPUT,            input,          index);
-               CMDINSIZE(G_CTRL,               control,        id);
-               CMDINSIZE(G_TUNER,              tuner,          index);
-               CMDINSIZE(QUERYCTRL,            queryctrl,      id);
-               CMDINSIZE(QUERYMENU,            querymenu,      index);
-               CMDINSIZE(ENUMOUTPUT,           output,         index);
-               CMDINSIZE(G_MODULATOR,          modulator,      index);
-               CMDINSIZE(G_FREQUENCY,          frequency,      tuner);
-               CMDINSIZE(CROPCAP,              cropcap,        type);
-               CMDINSIZE(G_CROP,               crop,           type);
-               CMDINSIZE(ENUMAUDIO,            audio,          index);
-               CMDINSIZE(ENUMAUDOUT,           audioout,       index);
-               CMDINSIZE(ENCODER_CMD,          encoder_cmd,    flags);
-               CMDINSIZE(TRY_ENCODER_CMD,      encoder_cmd,    flags);
-               CMDINSIZE(G_SLICED_VBI_CAP,     sliced_vbi_cap, type);
-               CMDINSIZE(ENUM_FRAMESIZES,      frmsizeenum,    pixel_format);
-               CMDINSIZE(ENUM_FRAMEINTERVALS,  frmivalenum,    height);
-       default:
-               return _IOC_SIZE(cmd);
-       }
-}
-
 static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
                            void * __user *user_ptr, void ***kernel_ptr)
 {
@@ -2219,7 +2149,20 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
 
                err = -EFAULT;
                if (_IOC_DIR(cmd) & _IOC_WRITE) {
-                       unsigned long n = cmd_input_size(cmd);
+                       unsigned int n = _IOC_SIZE(cmd);
+
+                       /*
+                        * In some cases, only a few fields are used as input,
+                        * i.e. when the app sets "index" and then the driver
+                        * fills in the rest of the structure for the thing
+                        * with that index.  We only need to copy up the first
+                        * non-input field.
+                        */
+                       if (v4l2_is_known_ioctl(cmd)) {
+                               u32 flags = v4l2_ioctls[_IOC_NR(cmd)].flags;
+                               if (flags & INFO_FL_CLEAR_MASK)
+                                       n = (flags & INFO_FL_CLEAR_MASK) >> 16;
+                       }
 
                        if (copy_from_user(parg, (void __user *)arg, n))
                                goto out;
index db6e859b93d4832a6420ca6d3d111d24b13164df..9182f81deb5b0177ede5b1d3280c07cc02e82188 100644 (file)
@@ -245,7 +245,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                memset(&sel, 0, sizeof(sel));
                sel.which = crop->which;
                sel.pad = crop->pad;
-               sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL;
+               sel.target = V4L2_SEL_TGT_CROP;
 
                rval = v4l2_subdev_call(
                        sd, pad, get_selection, subdev_fh, &sel);
@@ -274,7 +274,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                memset(&sel, 0, sizeof(sel));
                sel.which = crop->which;
                sel.pad = crop->pad;
-               sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL;
+               sel.target = V4L2_SEL_TGT_CROP;
                sel.r = crop->rect;
 
                rval = v4l2_subdev_call(
index ffdf59cfe4054f18d258ec4d682fddcfc7dc1aa7..bf7a326b1cdc06f8346981f246a74be572894fe4 100644 (file)
@@ -359,11 +359,6 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
                break;
        }
 
-       if (vb->input != UNSET) {
-               b->flags |= V4L2_BUF_FLAG_INPUT;
-               b->input  = vb->input;
-       }
-
        b->field     = vb->field;
        b->timestamp = vb->ts;
        b->bytesused = vb->size;
@@ -402,7 +397,6 @@ int __videobuf_mmap_setup(struct videobuf_queue *q,
                        break;
 
                q->bufs[i]->i      = i;
-               q->bufs[i]->input  = UNSET;
                q->bufs[i]->memory = memory;
                q->bufs[i]->bsize  = bsize;
                switch (memory) {
@@ -566,16 +560,6 @@ int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b)
                goto done;
        }
 
-       if (b->flags & V4L2_BUF_FLAG_INPUT) {
-               if (b->input >= q->inputs) {
-                       dprintk(1, "qbuf: wrong input.\n");
-                       goto done;
-               }
-               buf->input = b->input;
-       } else {
-               buf->input = UNSET;
-       }
-
        switch (b->memory) {
        case V4L2_MEMORY_MMAP:
                if (0 == buf->baddr) {
index b6b5cc1a43cb9261023f52fd7c78fdb77e49066d..9b9a06fdd0f00c17249e8880e9e8f0b55211a250 100644 (file)
@@ -40,7 +40,7 @@ struct videobuf_dma_contig_memory {
 
 static int __videobuf_dc_alloc(struct device *dev,
                               struct videobuf_dma_contig_memory *mem,
-                              unsigned long size, unsigned long flags)
+                              unsigned long size, gfp_t flags)
 {
        mem->size = size;
        if (mem->cached) {
index 9d4e9edbd2e7a661b5e07a35637bf5ad28b65c14..4e0290ab50716113f449a9326e1761400412654d 100644 (file)
@@ -336,9 +336,9 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
        struct vb2_queue *q = vb->vb2_queue;
        int ret;
 
-       /* Copy back data such as timestamp, flags, input, etc. */
+       /* Copy back data such as timestamp, flags, etc. */
        memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
-       b->input = vb->v4l2_buf.input;
+       b->reserved2 = vb->v4l2_buf.reserved2;
        b->reserved = vb->v4l2_buf.reserved;
 
        if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) {
@@ -454,7 +454,50 @@ static int __verify_mmap_ops(struct vb2_queue *q)
 }
 
 /**
- * vb2_reqbufs() - Initiate streaming
+ * __verify_memory_type() - Check whether the memory type and buffer type
+ * passed to a buffer operation are compatible with the queue.
+ */
+static int __verify_memory_type(struct vb2_queue *q,
+               enum v4l2_memory memory, enum v4l2_buf_type type)
+{
+       if (memory != V4L2_MEMORY_MMAP && memory != V4L2_MEMORY_USERPTR) {
+               dprintk(1, "reqbufs: unsupported memory type\n");
+               return -EINVAL;
+       }
+
+       if (type != q->type) {
+               dprintk(1, "reqbufs: requested type is incorrect\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Make sure all the required memory ops for given memory type
+        * are available.
+        */
+       if (memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) {
+               dprintk(1, "reqbufs: MMAP for current setup unsupported\n");
+               return -EINVAL;
+       }
+
+       if (memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) {
+               dprintk(1, "reqbufs: USERPTR for current setup unsupported\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Place the busy tests at the end: -EBUSY can be ignored when
+        * create_bufs is called with count == 0, but count == 0 should still
+        * do the memory and type validation.
+        */
+       if (q->fileio) {
+               dprintk(1, "reqbufs: file io in progress\n");
+               return -EBUSY;
+       }
+       return 0;
+}
+
+/**
+ * __reqbufs() - Initiate streaming
  * @q:         videobuf2 queue
  * @req:       struct passed from userspace to vidioc_reqbufs handler in driver
  *
@@ -476,46 +519,16 @@ static int __verify_mmap_ops(struct vb2_queue *q)
  * The return values from this function are intended to be directly returned
  * from vidioc_reqbufs handler in driver.
  */
-int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
+static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 {
        unsigned int num_buffers, allocated_buffers, num_planes = 0;
-       int ret = 0;
-
-       if (q->fileio) {
-               dprintk(1, "reqbufs: file io in progress\n");
-               return -EBUSY;
-       }
-
-       if (req->memory != V4L2_MEMORY_MMAP
-                       && req->memory != V4L2_MEMORY_USERPTR) {
-               dprintk(1, "reqbufs: unsupported memory type\n");
-               return -EINVAL;
-       }
-
-       if (req->type != q->type) {
-               dprintk(1, "reqbufs: requested type is incorrect\n");
-               return -EINVAL;
-       }
+       int ret;
 
        if (q->streaming) {
                dprintk(1, "reqbufs: streaming active\n");
                return -EBUSY;
        }
 
-       /*
-        * Make sure all the required memory ops for given memory type
-        * are available.
-        */
-       if (req->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) {
-               dprintk(1, "reqbufs: MMAP for current setup unsupported\n");
-               return -EINVAL;
-       }
-
-       if (req->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) {
-               dprintk(1, "reqbufs: USERPTR for current setup unsupported\n");
-               return -EINVAL;
-       }
-
        if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
                /*
                 * We already have buffers allocated, so first check if they
@@ -595,10 +608,23 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 
        return 0;
 }
+
+/**
+ * vb2_reqbufs() - Wrapper for __reqbufs() that also verifies the memory and
+ * type values.
+ * @q:         videobuf2 queue
+ * @req:       struct passed from userspace to vidioc_reqbufs handler in driver
+ */
+int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
+{
+       int ret = __verify_memory_type(q, req->memory, req->type);
+
+       return ret ? ret : __reqbufs(q, req);
+}
 EXPORT_SYMBOL_GPL(vb2_reqbufs);
 
 /**
- * vb2_create_bufs() - Allocate buffers and any required auxiliary structs
+ * __create_bufs() - Allocate buffers and any required auxiliary structs
  * @q:         videobuf2 queue
  * @create:    creation parameters, passed from userspace to vidioc_create_bufs
  *             handler in driver
@@ -612,40 +638,10 @@ EXPORT_SYMBOL_GPL(vb2_reqbufs);
  * The return values from this function are intended to be directly returned
  * from vidioc_create_bufs handler in driver.
  */
-int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
+static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
 {
        unsigned int num_planes = 0, num_buffers, allocated_buffers;
-       int ret = 0;
-
-       if (q->fileio) {
-               dprintk(1, "%s(): file io in progress\n", __func__);
-               return -EBUSY;
-       }
-
-       if (create->memory != V4L2_MEMORY_MMAP
-                       && create->memory != V4L2_MEMORY_USERPTR) {
-               dprintk(1, "%s(): unsupported memory type\n", __func__);
-               return -EINVAL;
-       }
-
-       if (create->format.type != q->type) {
-               dprintk(1, "%s(): requested type is incorrect\n", __func__);
-               return -EINVAL;
-       }
-
-       /*
-        * Make sure all the required memory ops for given memory type
-        * are available.
-        */
-       if (create->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) {
-               dprintk(1, "%s(): MMAP for current setup unsupported\n", __func__);
-               return -EINVAL;
-       }
-
-       if (create->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) {
-               dprintk(1, "%s(): USERPTR for current setup unsupported\n", __func__);
-               return -EINVAL;
-       }
+       int ret;
 
        if (q->num_buffers == VIDEO_MAX_FRAME) {
                dprintk(1, "%s(): maximum number of buffers already allocated\n",
@@ -653,8 +649,6 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
                return -ENOBUFS;
        }
 
-       create->index = q->num_buffers;
-
        if (!q->num_buffers) {
                memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
                memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
@@ -675,9 +669,9 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
        /* Finally, allocate buffers and video memory */
        ret = __vb2_queue_alloc(q, create->memory, num_buffers,
                                num_planes);
-       if (ret < 0) {
-               dprintk(1, "Memory allocation failed with error: %d\n", ret);
-               return ret;
+       if (ret == 0) {
+               dprintk(1, "Memory allocation failed\n");
+               return -ENOMEM;
        }
 
        allocated_buffers = ret;
@@ -708,7 +702,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
 
        if (ret < 0) {
                __vb2_queue_free(q, allocated_buffers);
-               return ret;
+               return -ENOMEM;
        }
 
        /*
@@ -719,6 +713,23 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
 
        return 0;
 }
+
+/**
+ * vb2_reqbufs() - Wrapper for __reqbufs() that also verifies the memory and
+ * type values.
+ * @q:         videobuf2 queue
+ * @create:    creation parameters, passed from userspace to vidioc_create_bufs
+ *             handler in driver
+ */
+int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
+{
+       int ret = __verify_memory_type(q, create->memory, create->format.type);
+
+       create->index = q->num_buffers;
+       if (create->count == 0)
+               return ret != -EBUSY ? ret : 0;
+       return ret ? ret : __create_bufs(q, create);
+}
 EXPORT_SYMBOL_GPL(vb2_create_bufs);
 
 /**
@@ -860,7 +871,6 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b,
 
        vb->v4l2_buf.field = b->field;
        vb->v4l2_buf.timestamp = b->timestamp;
-       vb->v4l2_buf.input = b->input;
        vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS;
 
        return 0;
@@ -2115,6 +2125,263 @@ size_t vb2_write(struct vb2_queue *q, char __user *data, size_t count,
 }
 EXPORT_SYMBOL_GPL(vb2_write);
 
+
+/*
+ * The following functions are not part of the vb2 core API, but are helper
+ * functions that plug into struct v4l2_ioctl_ops, struct v4l2_file_operations
+ * and struct vb2_ops.
+ * They contain boilerplate code that most if not all drivers have to do
+ * and so they simplify the driver code.
+ */
+
+/* The queue is busy if there is a owner and you are not that owner. */
+static inline bool vb2_queue_is_busy(struct video_device *vdev, struct file *file)
+{
+       return vdev->queue->owner && vdev->queue->owner != file->private_data;
+}
+
+/* vb2 ioctl helpers */
+
+int vb2_ioctl_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *p)
+{
+       struct video_device *vdev = video_devdata(file);
+       int res = __verify_memory_type(vdev->queue, p->memory, p->type);
+
+       if (res)
+               return res;
+       if (vb2_queue_is_busy(vdev, file))
+               return -EBUSY;
+       res = __reqbufs(vdev->queue, p);
+       /* If count == 0, then the owner has released all buffers and he
+          is no longer owner of the queue. Otherwise we have a new owner. */
+       if (res == 0)
+               vdev->queue->owner = p->count ? file->private_data : NULL;
+       return res;
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_reqbufs);
+
+int vb2_ioctl_create_bufs(struct file *file, void *priv,
+                         struct v4l2_create_buffers *p)
+{
+       struct video_device *vdev = video_devdata(file);
+       int res = __verify_memory_type(vdev->queue, p->memory, p->format.type);
+
+       p->index = vdev->queue->num_buffers;
+       /* If count == 0, then just check if memory and type are valid.
+          Any -EBUSY result from __verify_memory_type can be mapped to 0. */
+       if (p->count == 0)
+               return res != -EBUSY ? res : 0;
+       if (res)
+               return res;
+       if (vb2_queue_is_busy(vdev, file))
+               return -EBUSY;
+       res = __create_bufs(vdev->queue, p);
+       if (res == 0)
+               vdev->queue->owner = file->private_data;
+       return res;
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_create_bufs);
+
+int vb2_ioctl_prepare_buf(struct file *file, void *priv,
+                         struct v4l2_buffer *p)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vb2_queue_is_busy(vdev, file))
+               return -EBUSY;
+       return vb2_prepare_buf(vdev->queue, p);
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_prepare_buf);
+
+int vb2_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       /* No need to call vb2_queue_is_busy(), anyone can query buffers. */
+       return vb2_querybuf(vdev->queue, p);
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf);
+
+int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vb2_queue_is_busy(vdev, file))
+               return -EBUSY;
+       return vb2_qbuf(vdev->queue, p);
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf);
+
+int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vb2_queue_is_busy(vdev, file))
+               return -EBUSY;
+       return vb2_dqbuf(vdev->queue, p, file->f_flags & O_NONBLOCK);
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_dqbuf);
+
+int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vb2_queue_is_busy(vdev, file))
+               return -EBUSY;
+       return vb2_streamon(vdev->queue, i);
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_streamon);
+
+int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (vb2_queue_is_busy(vdev, file))
+               return -EBUSY;
+       return vb2_streamoff(vdev->queue, i);
+}
+EXPORT_SYMBOL_GPL(vb2_ioctl_streamoff);
+
+/* v4l2_file_operations helpers */
+
+int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       return vb2_mmap(vdev->queue, vma);
+}
+EXPORT_SYMBOL_GPL(vb2_fop_mmap);
+
+int vb2_fop_release(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (file->private_data == vdev->queue->owner) {
+               vb2_queue_release(vdev->queue);
+               vdev->queue->owner = NULL;
+       }
+       return v4l2_fh_release(file);
+}
+EXPORT_SYMBOL_GPL(vb2_fop_release);
+
+ssize_t vb2_fop_write(struct file *file, char __user *buf,
+               size_t count, loff_t *ppos)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
+       bool must_lock = !test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) && lock;
+       int err = -EBUSY;
+
+       if (must_lock && mutex_lock_interruptible(lock))
+               return -ERESTARTSYS;
+       if (vb2_queue_is_busy(vdev, file))
+               goto exit;
+       err = vb2_write(vdev->queue, buf, count, ppos,
+                      file->f_flags & O_NONBLOCK);
+       if (err >= 0)
+               vdev->queue->owner = file->private_data;
+exit:
+       if (must_lock)
+               mutex_unlock(lock);
+       return err;
+}
+EXPORT_SYMBOL_GPL(vb2_fop_write);
+
+ssize_t vb2_fop_read(struct file *file, char __user *buf,
+               size_t count, loff_t *ppos)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
+       bool must_lock = !test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) && vdev->lock;
+       int err = -EBUSY;
+
+       if (must_lock && mutex_lock_interruptible(lock))
+               return -ERESTARTSYS;
+       if (vb2_queue_is_busy(vdev, file))
+               goto exit;
+       err = vb2_read(vdev->queue, buf, count, ppos,
+                      file->f_flags & O_NONBLOCK);
+       if (err >= 0)
+               vdev->queue->owner = file->private_data;
+exit:
+       if (must_lock)
+               mutex_unlock(lock);
+       return err;
+}
+EXPORT_SYMBOL_GPL(vb2_fop_read);
+
+unsigned int vb2_fop_poll(struct file *file, poll_table *wait)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct vb2_queue *q = vdev->queue;
+       struct mutex *lock = q->lock ? q->lock : vdev->lock;
+       unsigned long req_events = poll_requested_events(wait);
+       unsigned res;
+       void *fileio;
+       /* Yuck. We really need to get rid of this flag asap. If it is
+          set, then the core took the serialization lock before calling
+          poll(). This is being phased out, but for now we have to handle
+          this case. */
+       bool locked = test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
+       bool must_lock = false;
+
+       /* Try to be smart: only lock if polling might start fileio,
+          otherwise locking will only introduce unwanted delays. */
+       if (q->num_buffers == 0 && q->fileio == NULL) {
+               if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) &&
+                               (req_events & (POLLIN | POLLRDNORM)))
+                       must_lock = true;
+               else if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) &&
+                               (req_events & (POLLOUT | POLLWRNORM)))
+                       must_lock = true;
+       }
+
+       /* If locking is needed, but this helper doesn't know how, then you
+          shouldn't be using this helper but you should write your own. */
+       WARN_ON(must_lock && !locked && !lock);
+
+       if (must_lock && !locked && lock && mutex_lock_interruptible(lock))
+               return POLLERR;
+
+       fileio = q->fileio;
+
+       res = vb2_poll(vdev->queue, file, wait);
+
+       /* If fileio was started, then we have a new queue owner. */
+       if (must_lock && !fileio && q->fileio)
+               q->owner = file->private_data;
+       if (must_lock && !locked && lock)
+               mutex_unlock(lock);
+       return res;
+}
+EXPORT_SYMBOL_GPL(vb2_fop_poll);
+
+#ifndef CONFIG_MMU
+unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr,
+               unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       return vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
+}
+EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area);
+#endif
+
+/* vb2_ops helpers. Only use if vq->lock is non-NULL. */
+
+void vb2_ops_wait_prepare(struct vb2_queue *vq)
+{
+       mutex_unlock(vq->lock);
+}
+EXPORT_SYMBOL_GPL(vb2_ops_wait_prepare);
+
+void vb2_ops_wait_finish(struct vb2_queue *vq)
+{
+       mutex_lock(vq->lock);
+}
+EXPORT_SYMBOL_GPL(vb2_ops_wait_finish);
+
 MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
 MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski");
 MODULE_LICENSE("GPL");
index 08c10240e70fba4063f2abd8cab3904b1f935a4b..1e8c4f3ab60244a89bc4321a30a03c2947e9b50d 100644 (file)
@@ -188,6 +188,7 @@ struct vivi_dev {
        struct list_head           vivi_devlist;
        struct v4l2_device         v4l2_dev;
        struct v4l2_ctrl_handler   ctrl_handler;
+       struct video_device        vdev;
 
        /* controls */
        struct v4l2_ctrl           *brightness;
@@ -213,9 +214,6 @@ struct vivi_dev {
        spinlock_t                 slock;
        struct mutex               mutex;
 
-       /* various device info */
-       struct video_device        *vfd;
-
        struct vivi_dmaqueue       vidq;
 
        /* Several counters */
@@ -769,7 +767,13 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
        struct vivi_dev *dev = vb2_get_drv_priv(vq);
        unsigned long size;
 
-       size = dev->width * dev->height * dev->pixelsize;
+       if (fmt)
+               size = fmt->fmt.pix.sizeimage;
+       else
+               size = dev->width * dev->height * dev->pixelsize;
+
+       if (size == 0)
+               return -EINVAL;
 
        if (0 == *nbuffers)
                *nbuffers = 32;
@@ -792,27 +796,6 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
        return 0;
 }
 
-static int buffer_init(struct vb2_buffer *vb)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
-
-       BUG_ON(NULL == dev->fmt);
-
-       /*
-        * This callback is called once per buffer, after its allocation.
-        *
-        * Vivi does not allow changing format during streaming, but it is
-        * possible to do so when streaming is paused (i.e. in streamoff state).
-        * Buffers however are not freed when going into streamoff and so
-        * buffer size verification has to be done in buffer_prepare, on each
-        * qbuf.
-        * It would be best to move verification code here to buf_init and
-        * s_fmt though.
-        */
-
-       return 0;
-}
-
 static int buffer_prepare(struct vb2_buffer *vb)
 {
        struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
@@ -850,20 +833,6 @@ static int buffer_prepare(struct vb2_buffer *vb)
        return 0;
 }
 
-static int buffer_finish(struct vb2_buffer *vb)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
-       dprintk(dev, 1, "%s\n", __func__);
-       return 0;
-}
-
-static void buffer_cleanup(struct vb2_buffer *vb)
-{
-       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
-       dprintk(dev, 1, "%s\n", __func__);
-
-}
-
 static void buffer_queue(struct vb2_buffer *vb)
 {
        struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
@@ -909,10 +878,7 @@ static void vivi_unlock(struct vb2_queue *vq)
 
 static struct vb2_ops vivi_video_qops = {
        .queue_setup            = queue_setup,
-       .buf_init               = buffer_init,
        .buf_prepare            = buffer_prepare,
-       .buf_finish             = buffer_finish,
-       .buf_cleanup            = buffer_cleanup,
        .buf_queue              = buffer_queue,
        .start_streaming        = start_streaming,
        .stop_streaming         = stop_streaming,
@@ -1021,7 +987,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        if (ret < 0)
                return ret;
 
-       if (vb2_is_streaming(q)) {
+       if (vb2_is_busy(q)) {
                dprintk(dev, 1, "%s device busy\n", __func__);
                return -EBUSY;
        }
@@ -1035,48 +1001,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_reqbufs(struct file *file, void *priv,
-                         struct v4l2_requestbuffers *p)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       return vb2_reqbufs(&dev->vb_vidq, p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       return vb2_querybuf(&dev->vb_vidq, p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       return vb2_qbuf(&dev->vb_vidq, p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       return vb2_streamon(&dev->vb_vidq, i);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       return vb2_streamoff(&dev->vb_vidq, i);
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
-{
-       return 0;
-}
-
 /* only one input in this sample driver */
 static int vidioc_enum_input(struct file *file, void *priv,
                                struct v4l2_input *inp)
@@ -1085,7 +1009,6 @@ static int vidioc_enum_input(struct file *file, void *priv,
                return -EINVAL;
 
        inp->type = V4L2_INPUT_TYPE_CAMERA;
-       inp->std = V4L2_STD_525_60;
        sprintf(inp->name, "Camera %u", inp->index);
        return 0;
 }
@@ -1145,58 +1068,6 @@ static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
        File operations for the device
    ------------------------------------------------------------------*/
 
-static ssize_t
-vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       int err;
-
-       dprintk(dev, 1, "read called\n");
-       mutex_lock(&dev->mutex);
-       err = vb2_read(&dev->vb_vidq, data, count, ppos,
-                      file->f_flags & O_NONBLOCK);
-       mutex_unlock(&dev->mutex);
-       return err;
-}
-
-static unsigned int
-vivi_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       struct vb2_queue *q = &dev->vb_vidq;
-
-       dprintk(dev, 1, "%s\n", __func__);
-       return vb2_poll(q, file, wait);
-}
-
-static int vivi_close(struct file *file)
-{
-       struct video_device  *vdev = video_devdata(file);
-       struct vivi_dev *dev = video_drvdata(file);
-
-       dprintk(dev, 1, "close called (dev=%s), file %p\n",
-               video_device_node_name(vdev), file);
-
-       if (v4l2_fh_is_singular_file(file))
-               vb2_queue_release(&dev->vb_vidq);
-       return v4l2_fh_release(file);
-}
-
-static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       int ret;
-
-       dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
-
-       ret = vb2_mmap(&dev->vb_vidq, vma);
-       dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
-               (unsigned long)vma->vm_start,
-               (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
-               ret);
-       return ret;
-}
-
 static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
        .g_volatile_ctrl = vivi_g_volatile_ctrl,
        .s_ctrl = vivi_s_ctrl,
@@ -1301,11 +1172,11 @@ static const struct v4l2_ctrl_config vivi_ctrl_int_menu = {
 static const struct v4l2_file_operations vivi_fops = {
        .owner          = THIS_MODULE,
        .open           = v4l2_fh_open,
-       .release        = vivi_close,
-       .read           = vivi_read,
-       .poll           = vivi_poll,
+       .release        = vb2_fop_release,
+       .read           = vb2_fop_read,
+       .poll           = vb2_fop_poll,
        .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
-       .mmap           = vivi_mmap,
+       .mmap           = vb2_fop_mmap,
 };
 
 static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
@@ -1314,16 +1185,17 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
        .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs       = vidioc_reqbufs,
-       .vidioc_querybuf      = vidioc_querybuf,
-       .vidioc_qbuf          = vidioc_qbuf,
-       .vidioc_dqbuf         = vidioc_dqbuf,
-       .vidioc_s_std         = vidioc_s_std,
+       .vidioc_reqbufs       = vb2_ioctl_reqbufs,
+       .vidioc_create_bufs   = vb2_ioctl_create_bufs,
+       .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf      = vb2_ioctl_querybuf,
+       .vidioc_qbuf          = vb2_ioctl_qbuf,
+       .vidioc_dqbuf         = vb2_ioctl_dqbuf,
        .vidioc_enum_input    = vidioc_enum_input,
        .vidioc_g_input       = vidioc_g_input,
        .vidioc_s_input       = vidioc_s_input,
-       .vidioc_streamon      = vidioc_streamon,
-       .vidioc_streamoff     = vidioc_streamoff,
+       .vidioc_streamon      = vb2_ioctl_streamon,
+       .vidioc_streamoff     = vb2_ioctl_streamoff,
        .vidioc_log_status    = v4l2_ctrl_log_status,
        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
@@ -1333,10 +1205,7 @@ static struct video_device vivi_template = {
        .name           = "vivi",
        .fops           = &vivi_fops,
        .ioctl_ops      = &vivi_ioctl_ops,
-       .release        = video_device_release,
-
-       .tvnorms              = V4L2_STD_525_60,
-       .current_norm         = V4L2_STD_NTSC_M,
+       .release        = video_device_release_empty,
 };
 
 /* -----------------------------------------------------------------
@@ -1354,8 +1223,8 @@ static int vivi_release(void)
                dev = list_entry(list, struct vivi_dev, vivi_devlist);
 
                v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
-                       video_device_node_name(dev->vfd));
-               video_unregister_device(dev->vfd);
+                       video_device_node_name(&dev->vdev));
+               video_unregister_device(&dev->vdev);
                v4l2_device_unregister(&dev->v4l2_dev);
                v4l2_ctrl_handler_free(&dev->ctrl_handler);
                kfree(dev);
@@ -1440,14 +1309,11 @@ static int __init vivi_create_instance(int inst)
        INIT_LIST_HEAD(&dev->vidq.active);
        init_waitqueue_head(&dev->vidq.wq);
 
-       ret = -ENOMEM;
-       vfd = video_device_alloc();
-       if (!vfd)
-               goto unreg_dev;
-
+       vfd = &dev->vdev;
        *vfd = vivi_template;
        vfd->debug = debug;
        vfd->v4l2_dev = &dev->v4l2_dev;
+       vfd->queue = q;
        set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
 
        /*
@@ -1455,12 +1321,11 @@ static int __init vivi_create_instance(int inst)
         * all fops and v4l2 ioctls.
         */
        vfd->lock = &dev->mutex;
+       video_set_drvdata(vfd, dev);
 
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
        if (ret < 0)
-               goto rel_vdev;
-
-       video_set_drvdata(vfd, dev);
+               goto unreg_dev;
 
        /* Now that everything is fine, let's add it to device list */
        list_add_tail(&dev->vivi_devlist, &vivi_devlist);
@@ -1468,13 +1333,10 @@ static int __init vivi_create_instance(int inst)
        if (video_nr != -1)
                video_nr++;
 
-       dev->vfd = vfd;
        v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
                  video_device_node_name(vfd));
        return 0;
 
-rel_vdev:
-       video_device_release(vfd);
 unreg_dev:
        v4l2_ctrl_handler_free(hdl);
        v4l2_device_unregister(&dev->v4l2_dev);
index e44cb330bbc8a8464d7e2e05106b0da1975a42c7..9afab35878b417f0c0ef7a7b352b718655373d7b 100644 (file)
 #include <linux/highmem.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
 #include <media/videobuf-vmalloc.h>
 
 
@@ -120,11 +124,6 @@ static struct usb_device_id device_table[] = {
 
 MODULE_DEVICE_TABLE(usb, device_table);
 
-struct zr364xx_mode {
-       u32 color;      /* output video color format */
-       u32 brightness; /* brightness */
-};
-
 /* frame structure */
 struct zr364xx_framei {
        unsigned long ulState;  /* ulState:ZR364XX_READ_IDLE,
@@ -173,7 +172,10 @@ static const struct zr364xx_fmt formats[] = {
 struct zr364xx_camera {
        struct usb_device *udev;        /* save off the usb device pointer */
        struct usb_interface *interface;/* the interface for this device */
-       struct video_device *vdev;      /* v4l video device */
+       struct v4l2_device v4l2_dev;
+       struct v4l2_ctrl_handler ctrl_handler;
+       struct video_device vdev;       /* v4l video device */
+       struct v4l2_fh *owner;          /* owns the streaming */
        int nb;
        struct zr364xx_bufferi          buffer;
        int skip;
@@ -181,12 +183,9 @@ struct zr364xx_camera {
        int height;
        int method;
        struct mutex lock;
-       struct mutex open_lock;
-       int users;
 
        spinlock_t              slock;
        struct zr364xx_dmaqueue vidq;
-       int                     resources;
        int                     last_frame;
        int                     cur_frame;
        unsigned long           frame_count;
@@ -197,8 +196,7 @@ struct zr364xx_camera {
 
        const struct zr364xx_fmt *fmt;
        struct videobuf_queue   vb_vidq;
-       enum v4l2_buf_type      type;
-       struct zr364xx_mode     mode;
+       bool was_streaming;
 };
 
 /* buffer for one video frame */
@@ -230,11 +228,6 @@ static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
                                 transfer_buffer, size, CTRL_TIMEOUT);
 
        kfree(transfer_buffer);
-
-       if (status < 0)
-               dev_err(&udev->dev,
-                       "Failed sending control message, error %d.\n", status);
-
        return status;
 }
 
@@ -468,6 +461,7 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count,
                            loff_t * ppos)
 {
        struct zr364xx_camera *cam = video_drvdata(file);
+       int err = 0;
 
        _DBG("%s\n", __func__);
 
@@ -477,17 +471,21 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count,
        if (!count)
                return -EINVAL;
 
-       if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-           zr364xx_vidioc_streamon(file, cam, cam->type) == 0) {
-               DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count,
-                   (int) *ppos);
+       if (mutex_lock_interruptible(&cam->lock))
+               return -ERESTARTSYS;
+
+       err = zr364xx_vidioc_streamon(file, file->private_data,
+                               V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       if (err == 0) {
+               DBG("%s: reading %d bytes at pos %d.\n", __func__,
+                               (int) count, (int) *ppos);
 
                /* NoMan Sux ! */
-               return videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
+               err = videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
                                        file->f_flags & O_NONBLOCK);
        }
-
-       return 0;
+       mutex_unlock(&cam->lock);
+       return err;
 }
 
 /* video buffer vmalloc implementation based partly on VIVI driver which is
@@ -702,35 +700,6 @@ static int zr364xx_read_video_callback(struct zr364xx_camera *cam,
        return 0;
 }
 
-static int res_get(struct zr364xx_camera *cam)
-{
-       /* is it free? */
-       mutex_lock(&cam->lock);
-       if (cam->resources) {
-               /* no, someone else uses it */
-               mutex_unlock(&cam->lock);
-               return 0;
-       }
-       /* it's free, grab it */
-       cam->resources = 1;
-       _DBG("res: get\n");
-       mutex_unlock(&cam->lock);
-       return 1;
-}
-
-static inline int res_check(struct zr364xx_camera *cam)
-{
-       return cam->resources;
-}
-
-static void res_free(struct zr364xx_camera *cam)
-{
-       mutex_lock(&cam->lock);
-       cam->resources = 0;
-       mutex_unlock(&cam->lock);
-       _DBG("res: put\n");
-}
-
 static int zr364xx_vidioc_querycap(struct file *file, void *priv,
                                   struct v4l2_capability *cap)
 {
@@ -740,9 +709,10 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv,
        strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
        strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
                sizeof(cap->bus_info));
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
                            V4L2_CAP_READWRITE |
                            V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 
        return 0;
 }
@@ -772,50 +742,18 @@ static int zr364xx_vidioc_s_input(struct file *file, void *priv,
        return 0;
 }
 
-static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
-                                   struct v4l2_queryctrl *c)
+static int zr364xx_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct zr364xx_camera *cam;
-
-       if (file == NULL)
-               return -ENODEV;
-       cam = video_drvdata(file);
-
-       switch (c->id) {
-       case V4L2_CID_BRIGHTNESS:
-               c->type = V4L2_CTRL_TYPE_INTEGER;
-               strcpy(c->name, "Brightness");
-               c->minimum = 0;
-               c->maximum = 127;
-               c->step = 1;
-               c->default_value = cam->mode.brightness;
-               c->flags = 0;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
-                                struct v4l2_control *c)
-{
-       struct zr364xx_camera *cam;
+       struct zr364xx_camera *cam =
+               container_of(ctrl->handler, struct zr364xx_camera, ctrl_handler);
        int temp;
 
-       if (file == NULL)
-               return -ENODEV;
-       cam = video_drvdata(file);
-
-       switch (c->id) {
+       switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               cam->mode.brightness = c->value;
                /* hardware brightness */
-               mutex_lock(&cam->lock);
                send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
-               temp = (0x60 << 8) + 127 - cam->mode.brightness;
+               temp = (0x60 << 8) + 127 - ctrl->val;
                send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
-               mutex_unlock(&cam->lock);
                break;
        default:
                return -EINVAL;
@@ -824,25 +762,6 @@ static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
        return 0;
 }
 
-static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv,
-                                struct v4l2_control *c)
-{
-       struct zr364xx_camera *cam;
-
-       if (file == NULL)
-               return -ENODEV;
-       cam = video_drvdata(file);
-
-       switch (c->id) {
-       case V4L2_CID_BRIGHTNESS:
-               c->value = cam->mode.brightness;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
 static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file,
                                       void *priv, struct v4l2_fmtdesc *f)
 {
@@ -888,7 +807,7 @@ static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        f->fmt.pix.field = V4L2_FIELD_NONE;
        f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
        f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
-       f->fmt.pix.colorspace = 0;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
        f->fmt.pix.priv = 0;
        DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
            decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
@@ -911,7 +830,7 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        f->fmt.pix.height = cam->height;
        f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
        f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
-       f->fmt.pix.colorspace = 0;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
        f->fmt.pix.priv = 0;
        return 0;
 }
@@ -936,7 +855,7 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                goto out;
        }
 
-       if (res_check(cam)) {
+       if (cam->owner) {
                DBG("%s can't change format after started\n", __func__);
                ret = -EBUSY;
                goto out;
@@ -944,14 +863,13 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 
        cam->width = f->fmt.pix.width;
        cam->height = f->fmt.pix.height;
-       dev_info(&cam->udev->dev, "%s: %dx%d mode selected\n", __func__,
+       DBG("%s: %dx%d mode selected\n", __func__,
                 cam->width, cam->height);
        f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
        f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
-       f->fmt.pix.colorspace = 0;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
        f->fmt.pix.priv = 0;
        cam->vb_vidq.field = f->fmt.pix.field;
-       cam->mode.color = V4L2_PIX_FMT_JPEG;
 
        if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120)
                mode = 1;
@@ -1015,10 +933,11 @@ out:
 static int zr364xx_vidioc_reqbufs(struct file *file, void *priv,
                          struct v4l2_requestbuffers *p)
 {
-       int rc;
        struct zr364xx_camera *cam = video_drvdata(file);
-       rc = videobuf_reqbufs(&cam->vb_vidq, p);
-       return rc;
+
+       if (cam->owner && cam->owner != priv)
+               return -EBUSY;
+       return videobuf_reqbufs(&cam->vb_vidq, p);
 }
 
 static int zr364xx_vidioc_querybuf(struct file *file,
@@ -1038,6 +957,8 @@ static int zr364xx_vidioc_qbuf(struct file *file,
        int rc;
        struct zr364xx_camera *cam = video_drvdata(file);
        _DBG("%s\n", __func__);
+       if (cam->owner && cam->owner != priv)
+               return -EBUSY;
        rc = videobuf_qbuf(&cam->vb_vidq, p);
        return rc;
 }
@@ -1049,6 +970,8 @@ static int zr364xx_vidioc_dqbuf(struct file *file,
        int rc;
        struct zr364xx_camera *cam = video_drvdata(file);
        _DBG("%s\n", __func__);
+       if (cam->owner && cam->owner != priv)
+               return -EBUSY;
        rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
        return rc;
 }
@@ -1197,29 +1120,23 @@ static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam)
        return 0;
 }
 
-static int zr364xx_vidioc_streamon(struct file *file, void *priv,
-                                  enum v4l2_buf_type type)
+static int zr364xx_prepare(struct zr364xx_camera *cam)
 {
-       struct zr364xx_camera *cam = video_drvdata(file);
-       int j;
        int res;
+       int i, j;
 
-       DBG("%s\n", __func__);
-
-       if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               dev_err(&cam->udev->dev, "invalid fh type0\n");
-               return -EINVAL;
-       }
-       if (cam->type != type) {
-               dev_err(&cam->udev->dev, "invalid fh type1\n");
-               return -EINVAL;
-       }
-
-       if (!res_get(cam)) {
-               dev_err(&cam->udev->dev, "stream busy\n");
-               return -EBUSY;
+       for (i = 0; init[cam->method][i].size != -1; i++) {
+               res = send_control_msg(cam->udev, 1, init[cam->method][i].value,
+                                    0, init[cam->method][i].bytes,
+                                    init[cam->method][i].size);
+               if (res < 0) {
+                       dev_err(&cam->udev->dev,
+                               "error during open sequence: %d\n", i);
+                       return res;
+               }
        }
 
+       cam->skip = 2;
        cam->last_frame = -1;
        cam->cur_frame = 0;
        cam->frame_count = 0;
@@ -1227,11 +1144,31 @@ static int zr364xx_vidioc_streamon(struct file *file, void *priv,
                cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
                cam->buffer.frame[j].cur_size = 0;
        }
+       v4l2_ctrl_handler_setup(&cam->ctrl_handler);
+       return 0;
+}
+
+static int zr364xx_vidioc_streamon(struct file *file, void *priv,
+                                  enum v4l2_buf_type type)
+{
+       struct zr364xx_camera *cam = video_drvdata(file);
+       int res;
+
+       DBG("%s\n", __func__);
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (cam->owner && cam->owner != priv)
+               return -EBUSY;
+
+       res = zr364xx_prepare(cam);
+       if (res)
+               return res;
        res = videobuf_streamon(&cam->vb_vidq);
        if (res == 0) {
                zr364xx_start_acquire(cam);
-       } else {
-               res_free(cam);
+               cam->owner = file->private_data;
        }
        return res;
 }
@@ -1239,67 +1176,32 @@ static int zr364xx_vidioc_streamon(struct file *file, void *priv,
 static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
                                    enum v4l2_buf_type type)
 {
-       int res;
        struct zr364xx_camera *cam = video_drvdata(file);
 
        DBG("%s\n", __func__);
-       if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               dev_err(&cam->udev->dev, "invalid fh type0\n");
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
-       }
-       if (cam->type != type) {
-               dev_err(&cam->udev->dev, "invalid fh type1\n");
-               return -EINVAL;
-       }
+       if (cam->owner && cam->owner != priv)
+               return -EBUSY;
        zr364xx_stop_acquire(cam);
-       res = videobuf_streamoff(&cam->vb_vidq);
-       if (res < 0)
-               return res;
-       res_free(cam);
-       return 0;
+       return videobuf_streamoff(&cam->vb_vidq);
 }
 
 
 /* open the camera */
 static int zr364xx_open(struct file *file)
 {
-       struct video_device *vdev = video_devdata(file);
        struct zr364xx_camera *cam = video_drvdata(file);
-       struct usb_device *udev = cam->udev;
-       int i, err;
+       int err;
 
        DBG("%s\n", __func__);
 
-       mutex_lock(&cam->open_lock);
+       if (mutex_lock_interruptible(&cam->lock))
+               return -ERESTARTSYS;
 
-       if (cam->users) {
-               err = -EBUSY;
+       err = v4l2_fh_open(file);
+       if (err)
                goto out;
-       }
-
-       for (i = 0; init[cam->method][i].size != -1; i++) {
-               err =
-                   send_control_msg(udev, 1, init[cam->method][i].value,
-                                    0, init[cam->method][i].bytes,
-                                    init[cam->method][i].size);
-               if (err < 0) {
-                       dev_err(&cam->udev->dev,
-                               "error during open sequence: %d\n", i);
-                       goto out;
-               }
-       }
-
-       cam->skip = 2;
-       cam->users++;
-       file->private_data = vdev;
-       cam->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       cam->fmt = formats;
-
-       videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
-                                   NULL, &cam->slock,
-                                   cam->type,
-                                   V4L2_FIELD_NONE,
-                                   sizeof(struct zr364xx_buffer), cam, NULL);
 
        /* Added some delay here, since opening/closing the camera quickly,
         * like Ekiga does during its startup, can crash the webcam
@@ -1308,29 +1210,20 @@ static int zr364xx_open(struct file *file)
        err = 0;
 
 out:
-       mutex_unlock(&cam->open_lock);
+       mutex_unlock(&cam->lock);
        DBG("%s: %d\n", __func__, err);
        return err;
 }
 
-static void zr364xx_destroy(struct zr364xx_camera *cam)
+static void zr364xx_release(struct v4l2_device *v4l2_dev)
 {
+       struct zr364xx_camera *cam =
+               container_of(v4l2_dev, struct zr364xx_camera, v4l2_dev);
        unsigned long i;
 
-       if (!cam) {
-               printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__);
-               return;
-       }
-       mutex_lock(&cam->open_lock);
-       if (cam->vdev)
-               video_unregister_device(cam->vdev);
-       cam->vdev = NULL;
-
-       /* stops the read pipe if it is running */
-       if (cam->b_acquire)
-               zr364xx_stop_acquire(cam);
+       v4l2_device_unregister(&cam->v4l2_dev);
 
-       zr364xx_stop_readpipe(cam);
+       videobuf_mmap_free(&cam->vb_vidq);
 
        /* release sys buffers */
        for (i = 0; i < FRAMES; i++) {
@@ -1341,62 +1234,45 @@ static void zr364xx_destroy(struct zr364xx_camera *cam)
                cam->buffer.frame[i].lpvbits = NULL;
        }
 
+       v4l2_ctrl_handler_free(&cam->ctrl_handler);
        /* release transfer buffer */
        kfree(cam->pipe->transfer_buffer);
-       cam->pipe->transfer_buffer = NULL;
-       mutex_unlock(&cam->open_lock);
        kfree(cam);
-       cam = NULL;
 }
 
 /* release the camera */
-static int zr364xx_release(struct file *file)
+static int zr364xx_close(struct file *file)
 {
        struct zr364xx_camera *cam;
        struct usb_device *udev;
-       int i, err;
+       int i;
 
        DBG("%s\n", __func__);
        cam = video_drvdata(file);
 
-       if (!cam)
-               return -ENODEV;
-
-       mutex_lock(&cam->open_lock);
+       mutex_lock(&cam->lock);
        udev = cam->udev;
 
-       /* turn off stream */
-       if (res_check(cam)) {
+       if (file->private_data == cam->owner) {
+               /* turn off stream */
                if (cam->b_acquire)
                        zr364xx_stop_acquire(cam);
                videobuf_streamoff(&cam->vb_vidq);
-               res_free(cam);
-       }
-
-       cam->users--;
-       file->private_data = NULL;
 
-       for (i = 0; i < 2; i++) {
-               err =
-                   send_control_msg(udev, 1, init[cam->method][i].value,
-                                    0, init[cam->method][i].bytes,
-                                    init[cam->method][i].size);
-               if (err < 0) {
-                       dev_err(&udev->dev, "error during release sequence\n");
-                       goto out;
+               for (i = 0; i < 2; i++) {
+                       send_control_msg(udev, 1, init[cam->method][i].value,
+                                       0, init[cam->method][i].bytes,
+                                       init[cam->method][i].size);
                }
+               cam->owner = NULL;
        }
 
        /* Added some delay here, since opening/closing the camera quickly,
         * like Ekiga does during its startup, can crash the webcam
         */
        mdelay(100);
-       err = 0;
-
-out:
-       mutex_unlock(&cam->open_lock);
-
-       return err;
+       mutex_unlock(&cam->lock);
+       return v4l2_fh_release(file);
 }
 
 
@@ -1424,21 +1300,24 @@ static unsigned int zr364xx_poll(struct file *file,
 {
        struct zr364xx_camera *cam = video_drvdata(file);
        struct videobuf_queue *q = &cam->vb_vidq;
-       _DBG("%s\n", __func__);
+       unsigned res = v4l2_ctrl_poll(file, wait);
 
-       if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return POLLERR;
+       _DBG("%s\n", __func__);
 
-       return videobuf_poll_stream(file, q, wait);
+       return res | videobuf_poll_stream(file, q, wait);
 }
 
+static const struct v4l2_ctrl_ops zr364xx_ctrl_ops = {
+       .s_ctrl = zr364xx_s_ctrl,
+};
+
 static const struct v4l2_file_operations zr364xx_fops = {
        .owner = THIS_MODULE,
        .open = zr364xx_open,
-       .release = zr364xx_release,
+       .release = zr364xx_close,
        .read = zr364xx_read,
        .mmap = zr364xx_mmap,
-       .ioctl = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
        .poll = zr364xx_poll,
 };
 
@@ -1453,20 +1332,20 @@ static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
        .vidioc_s_input         = zr364xx_vidioc_s_input,
        .vidioc_streamon        = zr364xx_vidioc_streamon,
        .vidioc_streamoff       = zr364xx_vidioc_streamoff,
-       .vidioc_queryctrl       = zr364xx_vidioc_queryctrl,
-       .vidioc_g_ctrl          = zr364xx_vidioc_g_ctrl,
-       .vidioc_s_ctrl          = zr364xx_vidioc_s_ctrl,
        .vidioc_reqbufs         = zr364xx_vidioc_reqbufs,
        .vidioc_querybuf        = zr364xx_vidioc_querybuf,
        .vidioc_qbuf            = zr364xx_vidioc_qbuf,
        .vidioc_dqbuf           = zr364xx_vidioc_dqbuf,
+       .vidioc_log_status      = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 static struct video_device zr364xx_template = {
        .name = DRIVER_DESC,
        .fops = &zr364xx_fops,
        .ioctl_ops = &zr364xx_ioctl_ops,
-       .release = video_device_release,
+       .release = video_device_release_empty,
 };
 
 
@@ -1540,6 +1419,7 @@ static int zr364xx_probe(struct usb_interface *intf,
        struct zr364xx_camera *cam = NULL;
        struct usb_host_interface *iface_desc;
        struct usb_endpoint_descriptor *endpoint;
+       struct v4l2_ctrl_handler *hdl;
        int err;
        int i;
 
@@ -1555,21 +1435,34 @@ static int zr364xx_probe(struct usb_interface *intf,
                dev_err(&udev->dev, "cam: out of memory !\n");
                return -ENOMEM;
        }
-       /* save the init method used by this camera */
-       cam->method = id->driver_info;
 
-       cam->vdev = video_device_alloc();
-       if (cam->vdev == NULL) {
-               dev_err(&udev->dev, "cam->vdev: out of memory !\n");
+       cam->v4l2_dev.release = zr364xx_release;
+       err = v4l2_device_register(&intf->dev, &cam->v4l2_dev);
+       if (err < 0) {
+               dev_err(&udev->dev, "couldn't register v4l2_device\n");
                kfree(cam);
-               cam = NULL;
-               return -ENOMEM;
+               return err;
        }
-       memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
-       cam->vdev->parent = &intf->dev;
-       video_set_drvdata(cam->vdev, cam);
+       hdl = &cam->ctrl_handler;
+       v4l2_ctrl_handler_init(hdl, 1);
+       v4l2_ctrl_new_std(hdl, &zr364xx_ctrl_ops,
+                         V4L2_CID_BRIGHTNESS, 0, 127, 1, 64);
+       if (hdl->error) {
+               err = hdl->error;
+               dev_err(&udev->dev, "couldn't register control\n");
+               goto fail;
+       }
+       /* save the init method used by this camera */
+       cam->method = id->driver_info;
+       mutex_init(&cam->lock);
+       cam->vdev = zr364xx_template;
+       cam->vdev.lock = &cam->lock;
+       cam->vdev.v4l2_dev = &cam->v4l2_dev;
+       cam->vdev.ctrl_handler = &cam->ctrl_handler;
+       set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
+       video_set_drvdata(&cam->vdev, cam);
        if (debug)
-               cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+               cam->vdev.debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
 
        cam->udev = udev;
 
@@ -1615,11 +1508,7 @@ static int zr364xx_probe(struct usb_interface *intf,
        header2[439] = cam->width / 256;
        header2[440] = cam->width % 256;
 
-       cam->users = 0;
        cam->nb = 0;
-       cam->mode.brightness = 64;
-       mutex_init(&cam->lock);
-       mutex_init(&cam->open_lock);
 
        DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
 
@@ -1635,52 +1524,100 @@ static int zr364xx_probe(struct usb_interface *intf,
        }
 
        if (!cam->read_endpoint) {
+               err = -ENOMEM;
                dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
-               video_device_release(cam->vdev);
-               kfree(cam);
-               cam = NULL;
-               return -ENOMEM;
+               goto fail;
        }
 
        /* v4l */
        INIT_LIST_HEAD(&cam->vidq.active);
        cam->vidq.cam = cam;
-       err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
-       if (err) {
-               dev_err(&udev->dev, "video_register_device failed\n");
-               video_device_release(cam->vdev);
-               kfree(cam);
-               cam = NULL;
-               return err;
-       }
 
        usb_set_intfdata(intf, cam);
 
        /* load zr364xx board specific */
        err = zr364xx_board_init(cam);
-       if (err) {
-               spin_lock_init(&cam->slock);
-               return err;
-       }
+       if (!err)
+               err = v4l2_ctrl_handler_setup(hdl);
+       if (err)
+               goto fail;
 
        spin_lock_init(&cam->slock);
 
+       cam->fmt = formats;
+
+       videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
+                                   NULL, &cam->slock,
+                                   V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                                   V4L2_FIELD_NONE,
+                                   sizeof(struct zr364xx_buffer), cam, &cam->lock);
+
+       err = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+       if (err) {
+               dev_err(&udev->dev, "video_register_device failed\n");
+               goto fail;
+       }
+
        dev_info(&udev->dev, DRIVER_DESC " controlling device %s\n",
-                video_device_node_name(cam->vdev));
+                video_device_node_name(&cam->vdev));
        return 0;
+
+fail:
+       v4l2_ctrl_handler_free(hdl);
+       v4l2_device_unregister(&cam->v4l2_dev);
+       kfree(cam);
+       return err;
 }
 
 
 static void zr364xx_disconnect(struct usb_interface *intf)
 {
        struct zr364xx_camera *cam = usb_get_intfdata(intf);
-       videobuf_mmap_free(&cam->vb_vidq);
+
+       mutex_lock(&cam->lock);
        usb_set_intfdata(intf, NULL);
        dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
-       zr364xx_destroy(cam);
+       video_unregister_device(&cam->vdev);
+       v4l2_device_disconnect(&cam->v4l2_dev);
+
+       /* stops the read pipe if it is running */
+       if (cam->b_acquire)
+               zr364xx_stop_acquire(cam);
+
+       zr364xx_stop_readpipe(cam);
+       mutex_unlock(&cam->lock);
+       v4l2_device_put(&cam->v4l2_dev);
 }
 
 
+#ifdef CONFIG_PM
+static int zr364xx_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct zr364xx_camera *cam = usb_get_intfdata(intf);
+
+       cam->was_streaming = cam->b_acquire;
+       if (!cam->was_streaming)
+               return 0;
+       zr364xx_stop_acquire(cam);
+       zr364xx_stop_readpipe(cam);
+       return 0;
+}
+
+static int zr364xx_resume(struct usb_interface *intf)
+{
+       struct zr364xx_camera *cam = usb_get_intfdata(intf);
+       int res;
+
+       if (!cam->was_streaming)
+               return 0;
+
+       zr364xx_start_readpipe(cam);
+       res = zr364xx_prepare(cam);
+       if (!res)
+               zr364xx_start_acquire(cam);
+       return res;
+}
+#endif
 
 /**********************/
 /* Module integration */
@@ -1690,6 +1627,11 @@ static struct usb_driver zr364xx_driver = {
        .name = "zr364xx",
        .probe = zr364xx_probe,
        .disconnect = zr364xx_disconnect,
+#ifdef CONFIG_PM
+       .suspend = zr364xx_suspend,
+       .resume = zr364xx_resume,
+       .reset_resume = zr364xx_resume,
+#endif
        .id_table = device_table
 };
 
index 098de2b35784a44cc4d5b9baeb08898a6a5ed805..9a49c243a6ac59c78c98cd9de021429d44aa8908 100644 (file)
@@ -188,6 +188,13 @@ static int i2o_cfg_parms(unsigned long arg, unsigned int type)
        if (!dev)
                return -ENXIO;
 
+       /*
+        * Stop users being able to try and allocate arbitary amounts
+        * of DMA space. 64K is way more than sufficient for this.
+        */
+       if (kcmd.oplen > 65536)
+               return -EMSGSIZE;
+
        ops = memdup_user(kcmd.opbuf, kcmd.oplen);
        if (IS_ERR(ops))
                return PTR_ERR(ops);
index 506c36f6e1db181d74ecf24809b82ef6c2abcb61..8001aa6bfb4809caf35c25ee758330dc3d08751a 100644 (file)
@@ -255,9 +255,8 @@ static char *scsi_devices[] = {
        "Array Controller Device"
 };
 
-static char *chtostr(u8 * chars, int n)
+static char *chtostr(char *tmp, u8 *chars, int n)
 {
-       char tmp[256];
        tmp[0] = 0;
        return strncat(tmp, (char *)chars, n);
 }
@@ -791,6 +790,7 @@ static int i2o_seq_show_ddm_table(struct seq_file *seq, void *v)
        } *result;
 
        i2o_exec_execute_ddm_table ddm_table;
+       char tmp[28 + 1];
 
        result = kmalloc(sizeof(*result), GFP_KERNEL);
        if (!result)
@@ -826,7 +826,7 @@ static int i2o_seq_show_ddm_table(struct seq_file *seq, void *v)
                seq_printf(seq, "%-#7x", ddm_table.i2o_vendor_id);
                seq_printf(seq, "%-#8x", ddm_table.module_id);
                seq_printf(seq, "%-29s",
-                          chtostr(ddm_table.module_name_version, 28));
+                          chtostr(tmp, ddm_table.module_name_version, 28));
                seq_printf(seq, "%9d  ", ddm_table.data_size);
                seq_printf(seq, "%8d", ddm_table.code_size);
 
@@ -893,6 +893,7 @@ static int i2o_seq_show_drivers_stored(struct seq_file *seq, void *v)
 
        i2o_driver_result_table *result;
        i2o_driver_store_table *dst;
+       char tmp[28 + 1];
 
        result = kmalloc(sizeof(i2o_driver_result_table), GFP_KERNEL);
        if (result == NULL)
@@ -927,8 +928,9 @@ static int i2o_seq_show_drivers_stored(struct seq_file *seq, void *v)
 
                seq_printf(seq, "%-#7x", dst->i2o_vendor_id);
                seq_printf(seq, "%-#8x", dst->module_id);
-               seq_printf(seq, "%-29s", chtostr(dst->module_name_version, 28));
-               seq_printf(seq, "%-9s", chtostr(dst->date, 8));
+               seq_printf(seq, "%-29s",
+                          chtostr(tmp, dst->module_name_version, 28));
+               seq_printf(seq, "%-9s", chtostr(tmp, dst->date, 8));
                seq_printf(seq, "%8d ", dst->module_size);
                seq_printf(seq, "%8d ", dst->mpb_size);
                seq_printf(seq, "0x%04x", dst->module_flags);
@@ -1248,6 +1250,7 @@ static int i2o_seq_show_dev_identity(struct seq_file *seq, void *v)
        // == (allow) 512d bytes (max)
        static u16 *work16 = (u16 *) work32;
        int token;
+       char tmp[16 + 1];
 
        token = i2o_parm_field_get(d, 0xF100, -1, &work32, sizeof(work32));
 
@@ -1260,13 +1263,13 @@ static int i2o_seq_show_dev_identity(struct seq_file *seq, void *v)
        seq_printf(seq, "Owner TID     : %0#5x\n", work16[2]);
        seq_printf(seq, "Parent TID    : %0#5x\n", work16[3]);
        seq_printf(seq, "Vendor info   : %s\n",
-                  chtostr((u8 *) (work32 + 2), 16));
+                  chtostr(tmp, (u8 *) (work32 + 2), 16));
        seq_printf(seq, "Product info  : %s\n",
-                  chtostr((u8 *) (work32 + 6), 16));
+                  chtostr(tmp, (u8 *) (work32 + 6), 16));
        seq_printf(seq, "Description   : %s\n",
-                  chtostr((u8 *) (work32 + 10), 16));
+                  chtostr(tmp, (u8 *) (work32 + 10), 16));
        seq_printf(seq, "Product rev.  : %s\n",
-                  chtostr((u8 *) (work32 + 14), 8));
+                  chtostr(tmp, (u8 *) (work32 + 14), 8));
 
        seq_printf(seq, "Serial number : ");
        print_serial_number(seq, (u8 *) (work32 + 16),
@@ -1303,6 +1306,8 @@ static int i2o_seq_show_ddm_identity(struct seq_file *seq, void *v)
                u8 pad[256];    // allow up to 256 byte (max) serial number
        } result;
 
+       char tmp[24 + 1];
+
        token = i2o_parm_field_get(d, 0xF101, -1, &result, sizeof(result));
 
        if (token < 0) {
@@ -1312,9 +1317,9 @@ static int i2o_seq_show_ddm_identity(struct seq_file *seq, void *v)
 
        seq_printf(seq, "Registering DDM TID : 0x%03x\n", result.ddm_tid);
        seq_printf(seq, "Module name         : %s\n",
-                  chtostr(result.module_name, 24));
+                  chtostr(tmp, result.module_name, 24));
        seq_printf(seq, "Module revision     : %s\n",
-                  chtostr(result.module_rev, 8));
+                  chtostr(tmp, result.module_rev, 8));
 
        seq_printf(seq, "Serial number       : ");
        print_serial_number(seq, result.serial_number, sizeof(result) - 36);
@@ -1338,6 +1343,8 @@ static int i2o_seq_show_uinfo(struct seq_file *seq, void *v)
                u8 instance_number[4];
        } result;
 
+       char tmp[64 + 1];
+
        token = i2o_parm_field_get(d, 0xF102, -1, &result, sizeof(result));
 
        if (token < 0) {
@@ -1346,13 +1353,13 @@ static int i2o_seq_show_uinfo(struct seq_file *seq, void *v)
        }
 
        seq_printf(seq, "Device name     : %s\n",
-                  chtostr(result.device_name, 64));
+                  chtostr(tmp, result.device_name, 64));
        seq_printf(seq, "Service name    : %s\n",
-                  chtostr(result.service_name, 64));
+                  chtostr(tmp, result.service_name, 64));
        seq_printf(seq, "Physical name   : %s\n",
-                  chtostr(result.physical_location, 64));
+                  chtostr(tmp, result.physical_location, 64));
        seq_printf(seq, "Instance number : %s\n",
-                  chtostr(result.instance_number, 4));
+                  chtostr(tmp, result.instance_number, 4));
 
        return 0;
 }
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
new file mode 100644 (file)
index 0000000..b67a301
--- /dev/null
@@ -0,0 +1,596 @@
+/*
+ * Base driver for Marvell 88PM800
+ *
+ * Copyright (C) 2012 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.com>
+ * Joseph(Yossi) Hanin <yhanin@marvell.com>
+ * Qiao Zhou <zhouqiao@marvell.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/88pm80x.h>
+#include <linux/slab.h>
+
+#define PM800_CHIP_ID                  (0x00)
+
+/* Interrupt Registers */
+#define PM800_INT_STATUS1              (0x05)
+#define PM800_ONKEY_INT_STS1           (1 << 0)
+#define PM800_EXTON_INT_STS1           (1 << 1)
+#define PM800_CHG_INT_STS1                     (1 << 2)
+#define PM800_BAT_INT_STS1                     (1 << 3)
+#define PM800_RTC_INT_STS1                     (1 << 4)
+#define PM800_CLASSD_OC_INT_STS1       (1 << 5)
+
+#define PM800_INT_STATUS2              (0x06)
+#define PM800_VBAT_INT_STS2            (1 << 0)
+#define PM800_VSYS_INT_STS2            (1 << 1)
+#define PM800_VCHG_INT_STS2            (1 << 2)
+#define PM800_TINT_INT_STS2            (1 << 3)
+#define PM800_GPADC0_INT_STS2  (1 << 4)
+#define PM800_TBAT_INT_STS2            (1 << 5)
+#define PM800_GPADC2_INT_STS2  (1 << 6)
+#define PM800_GPADC3_INT_STS2  (1 << 7)
+
+#define PM800_INT_STATUS3              (0x07)
+
+#define PM800_INT_STATUS4              (0x08)
+#define PM800_GPIO0_INT_STS4           (1 << 0)
+#define PM800_GPIO1_INT_STS4           (1 << 1)
+#define PM800_GPIO2_INT_STS4           (1 << 2)
+#define PM800_GPIO3_INT_STS4           (1 << 3)
+#define PM800_GPIO4_INT_STS4           (1 << 4)
+
+#define PM800_INT_ENA_1                (0x09)
+#define PM800_ONKEY_INT_ENA1           (1 << 0)
+#define PM800_EXTON_INT_ENA1           (1 << 1)
+#define PM800_CHG_INT_ENA1                     (1 << 2)
+#define PM800_BAT_INT_ENA1                     (1 << 3)
+#define PM800_RTC_INT_ENA1                     (1 << 4)
+#define PM800_CLASSD_OC_INT_ENA1       (1 << 5)
+
+#define PM800_INT_ENA_2                (0x0A)
+#define PM800_VBAT_INT_ENA2            (1 << 0)
+#define PM800_VSYS_INT_ENA2            (1 << 1)
+#define PM800_VCHG_INT_ENA2            (1 << 2)
+#define PM800_TINT_INT_ENA2            (1 << 3)
+
+#define PM800_INT_ENA_3                (0x0B)
+#define PM800_GPADC0_INT_ENA3          (1 << 0)
+#define PM800_GPADC1_INT_ENA3          (1 << 1)
+#define PM800_GPADC2_INT_ENA3          (1 << 2)
+#define PM800_GPADC3_INT_ENA3          (1 << 3)
+#define PM800_GPADC4_INT_ENA3          (1 << 4)
+
+#define PM800_INT_ENA_4                (0x0C)
+#define PM800_GPIO0_INT_ENA4           (1 << 0)
+#define PM800_GPIO1_INT_ENA4           (1 << 1)
+#define PM800_GPIO2_INT_ENA4           (1 << 2)
+#define PM800_GPIO3_INT_ENA4           (1 << 3)
+#define PM800_GPIO4_INT_ENA4           (1 << 4)
+
+/* number of INT_ENA & INT_STATUS regs */
+#define PM800_INT_REG_NUM                      (4)
+
+/* Interrupt Number in 88PM800 */
+enum {
+       PM800_IRQ_ONKEY,        /*EN1b0 *//*0 */
+       PM800_IRQ_EXTON,        /*EN1b1 */
+       PM800_IRQ_CHG,          /*EN1b2 */
+       PM800_IRQ_BAT,          /*EN1b3 */
+       PM800_IRQ_RTC,          /*EN1b4 */
+       PM800_IRQ_CLASSD,       /*EN1b5 *//*5 */
+       PM800_IRQ_VBAT,         /*EN2b0 */
+       PM800_IRQ_VSYS,         /*EN2b1 */
+       PM800_IRQ_VCHG,         /*EN2b2 */
+       PM800_IRQ_TINT,         /*EN2b3 */
+       PM800_IRQ_GPADC0,       /*EN3b0 *//*10 */
+       PM800_IRQ_GPADC1,       /*EN3b1 */
+       PM800_IRQ_GPADC2,       /*EN3b2 */
+       PM800_IRQ_GPADC3,       /*EN3b3 */
+       PM800_IRQ_GPADC4,       /*EN3b4 */
+       PM800_IRQ_GPIO0,        /*EN4b0 *//*15 */
+       PM800_IRQ_GPIO1,        /*EN4b1 */
+       PM800_IRQ_GPIO2,        /*EN4b2 */
+       PM800_IRQ_GPIO3,        /*EN4b3 */
+       PM800_IRQ_GPIO4,        /*EN4b4 *//*19 */
+       PM800_MAX_IRQ,
+};
+
+enum {
+       /* Procida */
+       PM800_CHIP_A0  = 0x60,
+       PM800_CHIP_A1  = 0x61,
+       PM800_CHIP_B0  = 0x62,
+       PM800_CHIP_C0  = 0x63,
+       PM800_CHIP_END = PM800_CHIP_C0,
+
+       /* Make sure to update this to the last stepping */
+       PM8XXX_CHIP_END = PM800_CHIP_END
+};
+
+static const struct i2c_device_id pm80x_id_table[] = {
+       {"88PM800", CHIP_PM800},
+       {} /* NULL terminated */
+};
+MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
+
+static struct resource rtc_resources[] = {
+       {
+        .name = "88pm80x-rtc",
+        .start = PM800_IRQ_RTC,
+        .end = PM800_IRQ_RTC,
+        .flags = IORESOURCE_IRQ,
+        },
+};
+
+static struct mfd_cell rtc_devs[] = {
+       {
+        .name = "88pm80x-rtc",
+        .num_resources = ARRAY_SIZE(rtc_resources),
+        .resources = &rtc_resources[0],
+        .id = -1,
+        },
+};
+
+static struct resource onkey_resources[] = {
+       {
+        .name = "88pm80x-onkey",
+        .start = PM800_IRQ_ONKEY,
+        .end = PM800_IRQ_ONKEY,
+        .flags = IORESOURCE_IRQ,
+        },
+};
+
+static struct mfd_cell onkey_devs[] = {
+       {
+        .name = "88pm80x-onkey",
+        .num_resources = 1,
+        .resources = &onkey_resources[0],
+        .id = -1,
+        },
+};
+
+static const struct regmap_irq pm800_irqs[] = {
+       /* INT0 */
+       [PM800_IRQ_ONKEY] = {
+               .mask = PM800_ONKEY_INT_ENA1,
+       },
+       [PM800_IRQ_EXTON] = {
+               .mask = PM800_EXTON_INT_ENA1,
+       },
+       [PM800_IRQ_CHG] = {
+               .mask = PM800_CHG_INT_ENA1,
+       },
+       [PM800_IRQ_BAT] = {
+               .mask = PM800_BAT_INT_ENA1,
+       },
+       [PM800_IRQ_RTC] = {
+               .mask = PM800_RTC_INT_ENA1,
+       },
+       [PM800_IRQ_CLASSD] = {
+               .mask = PM800_CLASSD_OC_INT_ENA1,
+       },
+       /* INT1 */
+       [PM800_IRQ_VBAT] = {
+               .reg_offset = 1,
+               .mask = PM800_VBAT_INT_ENA2,
+       },
+       [PM800_IRQ_VSYS] = {
+               .reg_offset = 1,
+               .mask = PM800_VSYS_INT_ENA2,
+       },
+       [PM800_IRQ_VCHG] = {
+               .reg_offset = 1,
+               .mask = PM800_VCHG_INT_ENA2,
+       },
+       [PM800_IRQ_TINT] = {
+               .reg_offset = 1,
+               .mask = PM800_TINT_INT_ENA2,
+       },
+       /* INT2 */
+       [PM800_IRQ_GPADC0] = {
+               .reg_offset = 2,
+               .mask = PM800_GPADC0_INT_ENA3,
+       },
+       [PM800_IRQ_GPADC1] = {
+               .reg_offset = 2,
+               .mask = PM800_GPADC1_INT_ENA3,
+       },
+       [PM800_IRQ_GPADC2] = {
+               .reg_offset = 2,
+               .mask = PM800_GPADC2_INT_ENA3,
+       },
+       [PM800_IRQ_GPADC3] = {
+               .reg_offset = 2,
+               .mask = PM800_GPADC3_INT_ENA3,
+       },
+       [PM800_IRQ_GPADC4] = {
+               .reg_offset = 2,
+               .mask = PM800_GPADC4_INT_ENA3,
+       },
+       /* INT3 */
+       [PM800_IRQ_GPIO0] = {
+               .reg_offset = 3,
+               .mask = PM800_GPIO0_INT_ENA4,
+       },
+       [PM800_IRQ_GPIO1] = {
+               .reg_offset = 3,
+               .mask = PM800_GPIO1_INT_ENA4,
+       },
+       [PM800_IRQ_GPIO2] = {
+               .reg_offset = 3,
+               .mask = PM800_GPIO2_INT_ENA4,
+       },
+       [PM800_IRQ_GPIO3] = {
+               .reg_offset = 3,
+               .mask = PM800_GPIO3_INT_ENA4,
+       },
+       [PM800_IRQ_GPIO4] = {
+               .reg_offset = 3,
+               .mask = PM800_GPIO4_INT_ENA4,
+       },
+};
+
+static int __devinit device_gpadc_init(struct pm80x_chip *chip,
+                                      struct pm80x_platform_data *pdata)
+{
+       struct pm80x_subchip *subchip = chip->subchip;
+       struct regmap *map = subchip->regmap_gpadc;
+       int data = 0, mask = 0, ret = 0;
+
+       if (!map) {
+               dev_warn(chip->dev,
+                        "Warning: gpadc regmap is not available!\n");
+               return -EINVAL;
+       }
+       /*
+        * initialize GPADC without activating it turn on GPADC
+        * measurments
+        */
+       ret = regmap_update_bits(map,
+                                PM800_GPADC_MISC_CONFIG2,
+                                PM800_GPADC_MISC_GPFSM_EN,
+                                PM800_GPADC_MISC_GPFSM_EN);
+       if (ret < 0)
+               goto out;
+       /*
+        * This function configures the ADC as requires for
+        * CP implementation.CP does not "own" the ADC configuration
+        * registers and relies on AP.
+        * Reason: enable automatic ADC measurements needed
+        * for CP to get VBAT and RF temperature readings.
+        */
+       ret = regmap_update_bits(map, PM800_GPADC_MEAS_EN1,
+                                PM800_MEAS_EN1_VBAT, PM800_MEAS_EN1_VBAT);
+       if (ret < 0)
+               goto out;
+       ret = regmap_update_bits(map, PM800_GPADC_MEAS_EN2,
+                                (PM800_MEAS_EN2_RFTMP | PM800_MEAS_GP0_EN),
+                                (PM800_MEAS_EN2_RFTMP | PM800_MEAS_GP0_EN));
+       if (ret < 0)
+               goto out;
+
+       /*
+        * the defult of PM800 is GPADC operates at 100Ks/s rate
+        * and Number of GPADC slots with active current bias prior
+        * to GPADC sampling = 1 slot for all GPADCs set for
+        * Temprature mesurmants
+        */
+       mask = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN1 |
+               PM800_GPADC_GP_BIAS_EN2 | PM800_GPADC_GP_BIAS_EN3);
+
+       if (pdata && (pdata->batt_det == 0))
+               data = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN1 |
+                       PM800_GPADC_GP_BIAS_EN2 | PM800_GPADC_GP_BIAS_EN3);
+       else
+               data = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN2 |
+                       PM800_GPADC_GP_BIAS_EN3);
+
+       ret = regmap_update_bits(map, PM800_GP_BIAS_ENA1, mask, data);
+       if (ret < 0)
+               goto out;
+
+       dev_info(chip->dev, "pm800 device_gpadc_init: Done\n");
+       return 0;
+
+out:
+       dev_info(chip->dev, "pm800 device_gpadc_init: Failed!\n");
+       return ret;
+}
+
+static int __devinit device_irq_init_800(struct pm80x_chip *chip)
+{
+       struct regmap *map = chip->regmap;
+       unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+       int data, mask, ret = -EINVAL;
+
+       if (!map || !chip->irq) {
+               dev_err(chip->dev, "incorrect parameters\n");
+               return -EINVAL;
+       }
+
+       /*
+        * irq_mode defines the way of clearing interrupt. it's read-clear by
+        * default.
+        */
+       mask =
+           PM800_WAKEUP2_INV_INT | PM800_WAKEUP2_INT_CLEAR |
+           PM800_WAKEUP2_INT_MASK;
+
+       data = PM800_WAKEUP2_INT_CLEAR;
+       ret = regmap_update_bits(map, PM800_WAKEUP2, mask, data);
+
+       if (ret < 0)
+               goto out;
+
+       ret =
+           regmap_add_irq_chip(chip->regmap, chip->irq, flags, -1,
+                               chip->regmap_irq_chip, &chip->irq_data);
+
+out:
+       return ret;
+}
+
+static void device_irq_exit_800(struct pm80x_chip *chip)
+{
+       regmap_del_irq_chip(chip->irq, chip->irq_data);
+}
+
+static struct regmap_irq_chip pm800_irq_chip = {
+       .name = "88pm800",
+       .irqs = pm800_irqs,
+       .num_irqs = ARRAY_SIZE(pm800_irqs),
+
+       .num_regs = 4,
+       .status_base = PM800_INT_STATUS1,
+       .mask_base = PM800_INT_ENA_1,
+       .ack_base = PM800_INT_STATUS1,
+};
+
+static int pm800_pages_init(struct pm80x_chip *chip)
+{
+       struct pm80x_subchip *subchip;
+       struct i2c_client *client = chip->client;
+
+       subchip = chip->subchip;
+       /* PM800 block power: i2c addr 0x31 */
+       if (subchip->power_page_addr) {
+               subchip->power_page =
+                   i2c_new_dummy(client->adapter, subchip->power_page_addr);
+               subchip->regmap_power =
+                   devm_regmap_init_i2c(subchip->power_page,
+                                        &pm80x_regmap_config);
+               i2c_set_clientdata(subchip->power_page, chip);
+       } else
+               dev_info(chip->dev,
+                        "PM800 block power 0x31: No power_page_addr\n");
+
+       /* PM800 block GPADC: i2c addr 0x32 */
+       if (subchip->gpadc_page_addr) {
+               subchip->gpadc_page = i2c_new_dummy(client->adapter,
+                                                   subchip->gpadc_page_addr);
+               subchip->regmap_gpadc =
+                   devm_regmap_init_i2c(subchip->gpadc_page,
+                                        &pm80x_regmap_config);
+               i2c_set_clientdata(subchip->gpadc_page, chip);
+       } else
+               dev_info(chip->dev,
+                        "PM800 block GPADC 0x32: No gpadc_page_addr\n");
+
+       return 0;
+}
+
+static void pm800_pages_exit(struct pm80x_chip *chip)
+{
+       struct pm80x_subchip *subchip;
+
+       regmap_exit(chip->regmap);
+       i2c_unregister_device(chip->client);
+
+       subchip = chip->subchip;
+       if (subchip->power_page) {
+               regmap_exit(subchip->regmap_power);
+               i2c_unregister_device(subchip->power_page);
+       }
+       if (subchip->gpadc_page) {
+               regmap_exit(subchip->regmap_gpadc);
+               i2c_unregister_device(subchip->gpadc_page);
+       }
+}
+
+static int __devinit device_800_init(struct pm80x_chip *chip,
+                                    struct pm80x_platform_data *pdata)
+{
+       int ret, pmic_id;
+       unsigned int val;
+
+       ret = regmap_read(chip->regmap, PM800_CHIP_ID, &val);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
+               goto out;
+       }
+
+       pmic_id = val & PM80X_VERSION_MASK;
+
+       if ((pmic_id >= PM800_CHIP_A0) && (pmic_id <= PM800_CHIP_END)) {
+               chip->version = val;
+               dev_info(chip->dev,
+                        "88PM80x:Marvell 88PM800 (ID:0x%x) detected\n", val);
+       } else {
+               dev_err(chip->dev,
+                       "Failed to detect Marvell 88PM800:ChipID[0x%x]\n", val);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /*
+        * alarm wake up bit will be clear in device_irq_init(),
+        * read before that
+        */
+       ret = regmap_read(chip->regmap, PM800_RTC_CONTROL, &val);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to read RTC register: %d\n", ret);
+               goto out;
+       }
+       if (val & PM800_ALARM_WAKEUP) {
+               if (pdata && pdata->rtc)
+                       pdata->rtc->rtc_wakeup = 1;
+       }
+
+       ret = device_gpadc_init(chip, pdata);
+       if (ret < 0) {
+               dev_err(chip->dev, "[%s]Failed to init gpadc\n", __func__);
+               goto out;
+       }
+
+       chip->regmap_irq_chip = &pm800_irq_chip;
+
+       ret = device_irq_init_800(chip);
+       if (ret < 0) {
+               dev_err(chip->dev, "[%s]Failed to init pm800 irq\n", __func__);
+               goto out;
+       }
+
+       ret =
+           mfd_add_devices(chip->dev, 0, &onkey_devs[0],
+                           ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to add onkey subdev\n");
+               goto out_dev;
+       } else
+               dev_info(chip->dev, "[%s]:Added mfd onkey_devs\n", __func__);
+
+       if (pdata && pdata->rtc) {
+               rtc_devs[0].platform_data = pdata->rtc;
+               rtc_devs[0].pdata_size = sizeof(struct pm80x_rtc_pdata);
+               ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
+                                     ARRAY_SIZE(rtc_devs), NULL, 0);
+               if (ret < 0) {
+                       dev_err(chip->dev, "Failed to add rtc subdev\n");
+                       goto out_dev;
+               } else
+                       dev_info(chip->dev,
+                                "[%s]:Added mfd rtc_devs\n", __func__);
+       }
+
+       return 0;
+out_dev:
+       mfd_remove_devices(chip->dev);
+       device_irq_exit_800(chip);
+out:
+       return ret;
+}
+
+static int __devinit pm800_probe(struct i2c_client *client,
+                                const struct i2c_device_id *id)
+{
+       int ret = 0;
+       struct pm80x_chip *chip;
+       struct pm80x_platform_data *pdata = client->dev.platform_data;
+       struct pm80x_subchip *subchip;
+
+       ret = pm80x_init(client, id);
+       if (ret) {
+               dev_err(&client->dev, "pm800_init fail\n");
+               goto out_init;
+       }
+
+       chip = i2c_get_clientdata(client);
+
+       /* init subchip for PM800 */
+       subchip =
+           devm_kzalloc(&client->dev, sizeof(struct pm80x_subchip),
+                        GFP_KERNEL);
+       if (!subchip) {
+               ret = -ENOMEM;
+               goto err_subchip_alloc;
+       }
+
+       subchip->power_page_addr = pdata->power_page_addr;
+       subchip->gpadc_page_addr = pdata->gpadc_page_addr;
+       chip->subchip = subchip;
+
+       ret = device_800_init(chip, pdata);
+       if (ret) {
+               dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
+               goto err_800_init;
+       }
+
+       ret = pm800_pages_init(chip);
+       if (ret) {
+               dev_err(&client->dev, "pm800_pages_init failed!\n");
+               goto err_page_init;
+       }
+
+       if (pdata->plat_config)
+               pdata->plat_config(chip, pdata);
+
+err_page_init:
+       mfd_remove_devices(chip->dev);
+       device_irq_exit_800(chip);
+err_800_init:
+       devm_kfree(&client->dev, subchip);
+err_subchip_alloc:
+       pm80x_deinit(client);
+out_init:
+       return ret;
+}
+
+static int __devexit pm800_remove(struct i2c_client *client)
+{
+       struct pm80x_chip *chip = i2c_get_clientdata(client);
+
+       mfd_remove_devices(chip->dev);
+       device_irq_exit_800(chip);
+
+       pm800_pages_exit(chip);
+       devm_kfree(&client->dev, chip->subchip);
+
+       pm80x_deinit(client);
+
+       return 0;
+}
+
+static struct i2c_driver pm800_driver = {
+       .driver = {
+               .name = "88PM80X",
+               .owner = THIS_MODULE,
+               .pm = &pm80x_pm_ops,
+               },
+       .probe = pm800_probe,
+       .remove = __devexit_p(pm800_remove),
+       .id_table = pm80x_id_table,
+};
+
+static int __init pm800_i2c_init(void)
+{
+       return i2c_add_driver(&pm800_driver);
+}
+subsys_initcall(pm800_i2c_init);
+
+static void __exit pm800_i2c_exit(void)
+{
+       i2c_del_driver(&pm800_driver);
+}
+module_exit(pm800_i2c_exit);
+
+MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM800");
+MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c
new file mode 100644 (file)
index 0000000..6146583
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * Base driver for Marvell 88PM805
+ *
+ * Copyright (C) 2012 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.com>
+ * Joseph(Yossi) Hanin <yhanin@marvell.com>
+ * Qiao Zhou <zhouqiao@marvell.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/88pm80x.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#define PM805_CHIP_ID                  (0x00)
+
+static const struct i2c_device_id pm80x_id_table[] = {
+       {"88PM805", CHIP_PM805},
+       {} /* NULL terminated */
+};
+MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
+
+/* Interrupt Number in 88PM805 */
+enum {
+       PM805_IRQ_LDO_OFF,      /*0 */
+       PM805_IRQ_SRC_DPLL_LOCK,        /*1 */
+       PM805_IRQ_CLIP_FAULT,
+       PM805_IRQ_MIC_CONFLICT,
+       PM805_IRQ_HP2_SHRT,
+       PM805_IRQ_HP1_SHRT,     /*5 */
+       PM805_IRQ_FINE_PLL_FAULT,
+       PM805_IRQ_RAW_PLL_FAULT,
+       PM805_IRQ_VOLP_BTN_DET,
+       PM805_IRQ_VOLM_BTN_DET,
+       PM805_IRQ_SHRT_BTN_DET, /*10 */
+       PM805_IRQ_MIC_DET,      /*11 */
+
+       PM805_MAX_IRQ,
+};
+
+static struct resource codec_resources[] = {
+       {
+        /* Headset microphone insertion or removal */
+        .name = "micin",
+        .start = PM805_IRQ_MIC_DET,
+        .end = PM805_IRQ_MIC_DET,
+        .flags = IORESOURCE_IRQ,
+        },
+       {
+        /* Audio short HP1 */
+        .name = "audio-short1",
+        .start = PM805_IRQ_HP1_SHRT,
+        .end = PM805_IRQ_HP1_SHRT,
+        .flags = IORESOURCE_IRQ,
+        },
+       {
+        /* Audio short HP2 */
+        .name = "audio-short2",
+        .start = PM805_IRQ_HP2_SHRT,
+        .end = PM805_IRQ_HP2_SHRT,
+        .flags = IORESOURCE_IRQ,
+        },
+};
+
+static struct mfd_cell codec_devs[] = {
+       {
+        .name = "88pm80x-codec",
+        .num_resources = ARRAY_SIZE(codec_resources),
+        .resources = &codec_resources[0],
+        .id = -1,
+        },
+};
+
+static struct regmap_irq pm805_irqs[] = {
+       /* INT0 */
+       [PM805_IRQ_LDO_OFF] = {
+               .mask = PM805_INT1_HP1_SHRT,
+       },
+       [PM805_IRQ_SRC_DPLL_LOCK] = {
+               .mask = PM805_INT1_HP2_SHRT,
+       },
+       [PM805_IRQ_CLIP_FAULT] = {
+               .mask = PM805_INT1_MIC_CONFLICT,
+       },
+       [PM805_IRQ_MIC_CONFLICT] = {
+               .mask = PM805_INT1_CLIP_FAULT,
+       },
+       [PM805_IRQ_HP2_SHRT] = {
+               .mask = PM805_INT1_LDO_OFF,
+       },
+       [PM805_IRQ_HP1_SHRT] = {
+               .mask = PM805_INT1_SRC_DPLL_LOCK,
+       },
+       /* INT1 */
+       [PM805_IRQ_FINE_PLL_FAULT] = {
+               .reg_offset = 1,
+               .mask = PM805_INT2_MIC_DET,
+       },
+       [PM805_IRQ_RAW_PLL_FAULT] = {
+               .reg_offset = 1,
+               .mask = PM805_INT2_SHRT_BTN_DET,
+       },
+       [PM805_IRQ_VOLP_BTN_DET] = {
+               .reg_offset = 1,
+               .mask = PM805_INT2_VOLM_BTN_DET,
+       },
+       [PM805_IRQ_VOLM_BTN_DET] = {
+               .reg_offset = 1,
+               .mask = PM805_INT2_VOLP_BTN_DET,
+       },
+       [PM805_IRQ_SHRT_BTN_DET] = {
+               .reg_offset = 1,
+               .mask = PM805_INT2_RAW_PLL_FAULT,
+       },
+       [PM805_IRQ_MIC_DET] = {
+               .reg_offset = 1,
+               .mask = PM805_INT2_FINE_PLL_FAULT,
+       },
+};
+
+static int __devinit device_irq_init_805(struct pm80x_chip *chip)
+{
+       struct regmap *map = chip->regmap;
+       unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+       int data, mask, ret = -EINVAL;
+
+       if (!map || !chip->irq) {
+               dev_err(chip->dev, "incorrect parameters\n");
+               return -EINVAL;
+       }
+
+       /*
+        * irq_mode defines the way of clearing interrupt. it's read-clear by
+        * default.
+        */
+       mask =
+           PM805_STATUS0_INT_CLEAR | PM805_STATUS0_INV_INT |
+           PM800_STATUS0_INT_MASK;
+
+       data = PM805_STATUS0_INT_CLEAR;
+       ret = regmap_update_bits(map, PM805_INT_STATUS0, mask, data);
+       /*
+        * PM805_INT_STATUS is under 32K clock domain, so need to
+        * add proper delay before the next I2C register access.
+        */
+       msleep(1);
+
+       if (ret < 0)
+               goto out;
+
+       ret =
+           regmap_add_irq_chip(chip->regmap, chip->irq, flags, -1,
+                               chip->regmap_irq_chip, &chip->irq_data);
+
+out:
+       return ret;
+}
+
+static void device_irq_exit_805(struct pm80x_chip *chip)
+{
+       regmap_del_irq_chip(chip->irq, chip->irq_data);
+}
+
+static struct regmap_irq_chip pm805_irq_chip = {
+       .name = "88pm805",
+       .irqs = pm805_irqs,
+       .num_irqs = ARRAY_SIZE(pm805_irqs),
+
+       .num_regs = 2,
+       .status_base = PM805_INT_STATUS1,
+       .mask_base = PM805_INT_MASK1,
+       .ack_base = PM805_INT_STATUS1,
+};
+
+static int __devinit device_805_init(struct pm80x_chip *chip)
+{
+       int ret = 0;
+       unsigned int val;
+       struct regmap *map = chip->regmap;
+
+       if (!map) {
+               dev_err(chip->dev, "regmap is invalid\n");
+               return -EINVAL;
+       }
+
+       ret = regmap_read(map, PM805_CHIP_ID, &val);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
+               goto out_irq_init;
+       }
+       chip->version = val;
+
+       chip->regmap_irq_chip = &pm805_irq_chip;
+
+       ret = device_irq_init_805(chip);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to init pm805 irq!\n");
+               goto out_irq_init;
+       }
+
+       ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
+                             ARRAY_SIZE(codec_devs), &codec_resources[0], 0);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to add codec subdev\n");
+               goto out_codec;
+       } else
+               dev_info(chip->dev, "[%s]:Added mfd codec_devs\n", __func__);
+
+       return 0;
+
+out_codec:
+       device_irq_exit_805(chip);
+out_irq_init:
+       return ret;
+}
+
+static int __devinit pm805_probe(struct i2c_client *client,
+                                const struct i2c_device_id *id)
+{
+       int ret = 0;
+       struct pm80x_chip *chip;
+       struct pm80x_platform_data *pdata = client->dev.platform_data;
+
+       ret = pm80x_init(client, id);
+       if (ret) {
+               dev_err(&client->dev, "pm805_init fail!\n");
+               goto out_init;
+       }
+
+       chip = i2c_get_clientdata(client);
+
+       ret = device_805_init(chip);
+       if (ret) {
+               dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
+               goto err_805_init;
+       }
+
+       if (pdata->plat_config)
+               pdata->plat_config(chip, pdata);
+
+err_805_init:
+       pm80x_deinit(client);
+out_init:
+       return ret;
+}
+
+static int __devexit pm805_remove(struct i2c_client *client)
+{
+       struct pm80x_chip *chip = i2c_get_clientdata(client);
+
+       mfd_remove_devices(chip->dev);
+       device_irq_exit_805(chip);
+
+       pm80x_deinit(client);
+
+       return 0;
+}
+
+static struct i2c_driver pm805_driver = {
+       .driver = {
+               .name = "88PM80X",
+               .owner = THIS_MODULE,
+               .pm = &pm80x_pm_ops,
+               },
+       .probe = pm805_probe,
+       .remove = __devexit_p(pm805_remove),
+       .id_table = pm80x_id_table,
+};
+
+static int __init pm805_i2c_init(void)
+{
+       return i2c_add_driver(&pm805_driver);
+}
+subsys_initcall(pm805_i2c_init);
+
+static void __exit pm805_i2c_exit(void)
+{
+       i2c_del_driver(&pm805_driver);
+}
+module_exit(pm805_i2c_exit);
+
+MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM805");
+MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/88pm80x.c b/drivers/mfd/88pm80x.c
new file mode 100644 (file)
index 0000000..cd0bf52
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * I2C driver for Marvell 88PM80x
+ *
+ * Copyright (C) 2012 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang@marvell.com>
+ * Joseph(Yossi) Hanin <yhanin@marvell.com>
+ * Qiao Zhou <zhouqiao@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/mfd/88pm80x.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/err.h>
+
+/*
+ * workaround: some registers needed by pm805 are defined in pm800, so
+ * need to use this global variable to maintain the relation between
+ * pm800 and pm805. would remove it after HW chip fixes the issue.
+ */
+static struct pm80x_chip *g_pm80x_chip;
+
+const struct regmap_config pm80x_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+EXPORT_SYMBOL_GPL(pm80x_regmap_config);
+
+int __devinit pm80x_init(struct i2c_client *client,
+                                const struct i2c_device_id *id)
+{
+       struct pm80x_chip *chip;
+       struct regmap *map;
+       int ret = 0;
+
+       chip =
+           devm_kzalloc(&client->dev, sizeof(struct pm80x_chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       map = devm_regmap_init_i2c(client, &pm80x_regmap_config);
+       if (IS_ERR(map)) {
+               ret = PTR_ERR(map);
+               dev_err(&client->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               goto err_regmap_init;
+       }
+
+       chip->id = id->driver_data;
+       if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805) {
+               ret = -EINVAL;
+               goto err_chip_id;
+       }
+
+       chip->client = client;
+       chip->regmap = map;
+
+       chip->irq = client->irq;
+
+       chip->dev = &client->dev;
+       dev_set_drvdata(chip->dev, chip);
+       i2c_set_clientdata(chip->client, chip);
+
+       device_init_wakeup(&client->dev, 1);
+
+       /*
+        * workaround: set g_pm80x_chip to the first probed chip. if the
+        * second chip is probed, just point to the companion to each
+        * other so that pm805 can access those specific register. would
+        * remove it after HW chip fixes the issue.
+        */
+       if (!g_pm80x_chip)
+               g_pm80x_chip = chip;
+       else {
+               chip->companion = g_pm80x_chip->client;
+               g_pm80x_chip->companion = chip->client;
+       }
+
+       return 0;
+
+err_chip_id:
+       regmap_exit(map);
+err_regmap_init:
+       devm_kfree(&client->dev, chip);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pm80x_init);
+
+int pm80x_deinit(struct i2c_client *client)
+{
+       struct pm80x_chip *chip = i2c_get_clientdata(client);
+
+       /*
+        * workaround: clear the dependency between pm800 and pm805.
+        * would remove it after HW chip fixes the issue.
+        */
+       if (g_pm80x_chip->companion)
+               g_pm80x_chip->companion = NULL;
+       else
+               g_pm80x_chip = NULL;
+
+       regmap_exit(chip->regmap);
+       devm_kfree(&client->dev, chip);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pm80x_deinit);
+
+#ifdef CONFIG_PM_SLEEP
+static int pm80x_suspend(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct pm80x_chip *chip = i2c_get_clientdata(client);
+
+       if (chip && chip->wu_flag)
+               if (device_may_wakeup(chip->dev))
+                       enable_irq_wake(chip->irq);
+
+       return 0;
+}
+
+static int pm80x_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct pm80x_chip *chip = i2c_get_clientdata(client);
+
+       if (chip && chip->wu_flag)
+               if (device_may_wakeup(chip->dev))
+                       disable_irq_wake(chip->irq);
+
+       return 0;
+}
+#endif
+
+SIMPLE_DEV_PM_OPS(pm80x_pm_ops, pm80x_suspend, pm80x_resume);
+EXPORT_SYMBOL_GPL(pm80x_pm_ops);
+
+MODULE_DESCRIPTION("I2C Driver for Marvell 88PM80x");
+MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>");
+MODULE_LICENSE("GPL");
index 87bd5ba38d5b649db355f252d326fe28116041c0..d09918cf1b1556a74edb622e0174d3ceffdf7ca6 100644 (file)
@@ -90,6 +90,10 @@ static struct resource charger_resources[] __devinitdata = {
        {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage",    IORESOURCE_IRQ,},
 };
 
+static struct resource preg_resources[] __devinitdata = {
+       {PM8606_ID_PREG,  PM8606_ID_PREG,  "preg",   IORESOURCE_IO,},
+};
+
 static struct resource rtc_resources[] __devinitdata = {
        {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,},
 };
@@ -142,9 +146,19 @@ static struct mfd_cell codec_devs[] = {
        {"88pm860x-codec", -1,},
 };
 
+static struct regulator_consumer_supply preg_supply[] = {
+       REGULATOR_SUPPLY("preg", "charger-manager"),
+};
+
+static struct regulator_init_data preg_init_data = {
+       .num_consumer_supplies  = ARRAY_SIZE(preg_supply),
+       .consumer_supplies      = &preg_supply[0],
+};
+
 static struct mfd_cell power_devs[] = {
        {"88pm860x-battery", -1,},
        {"88pm860x-charger", -1,},
+       {"88pm860x-preg",    -1,},
 };
 
 static struct mfd_cell rtc_devs[] = {
@@ -768,6 +782,15 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
                              &charger_resources[0], chip->irq_base);
        if (ret < 0)
                dev_err(chip->dev, "Failed to add charger subdev\n");
+
+       power_devs[2].platform_data = &preg_init_data;
+       power_devs[2].pdata_size = sizeof(struct regulator_init_data);
+       power_devs[2].num_resources = ARRAY_SIZE(preg_resources);
+       power_devs[2].resources = &preg_resources[0],
+       ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1,
+                             &preg_resources[0], chip->irq_base);
+       if (ret < 0)
+               dev_err(chip->dev, "Failed to add preg subdev\n");
 }
 
 static void __devinit device_onkey_init(struct pm860x_chip *chip,
index 92144ed1ad469d8257eab6636c4d7f8cc4c65180..d1facef28a60d77bc4f3eb8264e7fffeab1fc445 100644 (file)
@@ -7,6 +7,7 @@ menu "Multifunction device drivers"
 
 config MFD_CORE
        tristate
+       select IRQ_DOMAIN
        default n
 
 config MFD_88PM860X
@@ -20,6 +21,30 @@ config MFD_88PM860X
          select individual components like voltage regulators, RTC and
          battery-charger under the corresponding menus.
 
+config MFD_88PM800
+       tristate "Support Marvell 88PM800"
+       depends on I2C=y && GENERIC_HARDIRQS
+       select REGMAP_I2C
+       select REGMAP_IRQ
+       select MFD_CORE
+       help
+         This supports for Marvell 88PM800 Power Management IC.
+         This includes the I2C driver and the core APIs _only_, you have to
+         select individual components like voltage regulators, RTC and
+         battery-charger under the corresponding menus.
+
+config MFD_88PM805
+       tristate "Support Marvell 88PM805"
+       depends on I2C=y && GENERIC_HARDIRQS
+       select REGMAP_I2C
+       select REGMAP_IRQ
+       select MFD_CORE
+       help
+         This supports for Marvell 88PM805 Power Management IC. This includes
+         the I2C driver and the core APIs _only_, you have to select individual
+         components like codec device, headset/Mic device under the
+         corresponding menus.
+
 config MFD_SM501
        tristate "Support for Silicon Motion SM501"
         ---help---
@@ -173,8 +198,9 @@ config MFD_TPS65217
 
 config MFD_TPS6586X
        bool "TPS6586x Power Management chips"
-       depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
+       depends on I2C=y && GENERIC_HARDIRQS
        select MFD_CORE
+       select REGMAP_I2C
        depends on REGULATOR
        help
          If you say yes here you get support for the TPS6586X series of
@@ -276,6 +302,7 @@ config TWL6030_PWM
        tristate "TWL6030 PWM (Pulse Width Modulator) Support"
        depends on TWL4030_CORE
        select HAVE_PWM
+       depends on !PWM
        default n
        help
          Say yes here if you want support for TWL6030 PWM.
@@ -423,6 +450,19 @@ config PMIC_ADP5520
          individual components like LCD backlight, LEDs, GPIOs and Kepad
          under the corresponding menus.
 
+config MFD_MAX77686
+       bool "Maxim Semiconductor MAX77686 PMIC Support"
+       depends on I2C=y && GENERIC_HARDIRQS
+       select MFD_CORE
+       select REGMAP_I2C
+       select IRQ_DOMAIN
+       help
+         Say yes here to support for Maxim Semiconductor MAX77686.
+         This is a Power Management IC with RTC on chip.
+         This driver provides common support for accessing the device;
+         additional drivers must be enabled in order to use the functionality
+         of the device.
+
 config MFD_MAX77693
        bool "Maxim Semiconductor MAX77693 PMIC Support"
        depends on I2C=y && GENERIC_HARDIRQS
@@ -450,6 +490,7 @@ config MFD_MAX8997
        bool "Maxim Semiconductor MAX8997/8966 PMIC Support"
        depends on I2C=y && GENERIC_HARDIRQS
        select MFD_CORE
+       select IRQ_DOMAIN
        help
          Say yes here to support for Maxim Semiconductor MAX8997/8966.
          This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
@@ -469,17 +510,56 @@ config MFD_MAX8998
          additional drivers must be enabled in order to use the functionality
          of the device.
 
-config MFD_S5M_CORE
-       bool "SAMSUNG S5M Series Support"
+config MFD_SEC_CORE
+       bool "SAMSUNG Electronics PMIC Series Support"
        depends on I2C=y && GENERIC_HARDIRQS
        select MFD_CORE
        select REGMAP_I2C
+       select REGMAP_IRQ
        help
-        Support for the Samsung Electronics S5M MFD series.
+        Support for the Samsung Electronics MFD series.
         This driver provides common support for accessing the device,
         additional drivers must be enabled in order to use the functionality
         of the device
 
+config MFD_ARIZONA
+       select REGMAP
+       select REGMAP_IRQ
+       select MFD_CORE
+       bool
+
+config MFD_ARIZONA_I2C
+       tristate "Support Wolfson Microelectronics Arizona platform with I2C"
+       select MFD_ARIZONA
+       select MFD_CORE
+       select REGMAP_I2C
+       depends on I2C
+       help
+         Support for the Wolfson Microelectronics Arizona platform audio SoC
+         core functionality controlled via I2C.
+
+config MFD_ARIZONA_SPI
+       tristate "Support Wolfson Microelectronics Arizona platform with SPI"
+       select MFD_ARIZONA
+       select MFD_CORE
+       select REGMAP_SPI
+       depends on SPI_MASTER
+       help
+         Support for the Wolfson Microelectronics Arizona platform audio SoC
+         core functionality controlled via I2C.
+
+config MFD_WM5102
+       bool "Support Wolfson Microelectronics WM5102"
+       depends on MFD_ARIZONA
+       help
+         Support for Wolfson Microelectronics WM5102 low power audio SoC
+
+config MFD_WM5110
+       bool "Support Wolfson Microelectronics WM5110"
+       depends on MFD_ARIZONA
+       help
+         Support for Wolfson Microelectronics WM5110 low power audio SoC
+
 config MFD_WM8400
        bool "Support Wolfson Microelectronics WM8400"
        select MFD_CORE
@@ -697,6 +777,7 @@ config AB8500_CORE
        bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
        depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU
        select MFD_CORE
+       select IRQ_DOMAIN
        help
          Select this option to enable access to AB8500 power management
          chip. This connects to U8500 either on the SSP/SPI bus (deprecated
@@ -704,16 +785,6 @@ config AB8500_CORE
          the irq_chip parts for handling the Mixed Signal chip events.
          This chip embeds various other multimedia funtionalities as well.
 
-config AB8500_I2C_CORE
-       bool "AB8500 register access via PRCMU I2C"
-       depends on AB8500_CORE && MFD_DB8500_PRCMU
-       default y
-       help
-         This enables register access to the AB8500 chip via PRCMU I2C.
-         The AB8500 chip can be accessed via SPI or I2C. On DB8500 hardware
-         the I2C bus is connected to the Power Reset
-         and Mangagement Unit, PRCMU.
-
 config AB8500_DEBUG
        bool "Enable debug info via debugfs"
        depends on AB8500_CORE && DEBUG_FS
index 75f6ed68a4b9e259616795e41bba94eea0b755ea..79dd22d1dc3d16d68232047b843464e0b743b4b0 100644 (file)
@@ -4,6 +4,8 @@
 
 88pm860x-objs                  := 88pm860x-core.o 88pm860x-i2c.o
 obj-$(CONFIG_MFD_88PM860X)     += 88pm860x.o
+obj-$(CONFIG_MFD_88PM800)      += 88pm800.o 88pm80x.o
+obj-$(CONFIG_MFD_88PM805)      += 88pm805.o 88pm80x.o
 obj-$(CONFIG_MFD_SM501)                += sm501.o
 obj-$(CONFIG_MFD_ASIC3)                += asic3.o tmio_core.o
 
@@ -24,6 +26,16 @@ obj-$(CONFIG_MFD_T7L66XB)    += t7l66xb.o tmio_core.o
 obj-$(CONFIG_MFD_TC6387XB)     += tc6387xb.o tmio_core.o
 obj-$(CONFIG_MFD_TC6393XB)     += tc6393xb.o tmio_core.o
 
+obj-$(CONFIG_MFD_ARIZONA)      += arizona-core.o
+obj-$(CONFIG_MFD_ARIZONA)      += arizona-irq.o
+obj-$(CONFIG_MFD_ARIZONA_I2C)  += arizona-i2c.o
+obj-$(CONFIG_MFD_ARIZONA_SPI)  += arizona-spi.o
+ifneq ($(CONFIG_MFD_WM5102),n)
+obj-$(CONFIG_MFD_ARIZONA)      += wm5102-tables.o
+endif
+ifneq ($(CONFIG_MFD_WM5110),n)
+obj-$(CONFIG_MFD_ARIZONA)      += wm5110-tables.o
+endif
 obj-$(CONFIG_MFD_WM8400)       += wm8400-core.o
 wm831x-objs                    := wm831x-core.o wm831x-irq.o wm831x-otp.o
 wm831x-objs                    += wm831x-auxadc.o
@@ -78,6 +90,7 @@ obj-$(CONFIG_PMIC_DA9052)     += da9052-core.o
 obj-$(CONFIG_MFD_DA9052_SPI)   += da9052-spi.o
 obj-$(CONFIG_MFD_DA9052_I2C)   += da9052-i2c.o
 
+obj-$(CONFIG_MFD_MAX77686)     += max77686.o max77686-irq.o
 obj-$(CONFIG_MFD_MAX77693)     += max77693.o max77693-irq.o
 max8925-objs                   := max8925-core.o max8925-i2c.o
 obj-$(CONFIG_MFD_MAX8925)      += max8925.o
@@ -116,6 +129,6 @@ obj-$(CONFIG_MFD_AAT2870_CORE)      += aat2870-core.o
 obj-$(CONFIG_MFD_INTEL_MSIC)   += intel_msic.o
 obj-$(CONFIG_MFD_PALMAS)       += palmas.o
 obj-$(CONFIG_MFD_RC5T583)      += rc5t583.o rc5t583-irq.o
-obj-$(CONFIG_MFD_S5M_CORE)     += s5m-core.o s5m-irq.o
+obj-$(CONFIG_MFD_SEC_CORE)     += sec-core.o sec-irq.o
 obj-$(CONFIG_MFD_ANATOP)       += anatop-mfd.o
 obj-$(CONFIG_MFD_LM3533)       += lm3533-core.o lm3533-ctrlbank.o
index 1efad20fb1757523713359ff5af65f3d13ca4302..4276aab4f1963bcc34eaceb94c5018e345b72a82 100644 (file)
@@ -867,7 +867,7 @@ static int __devinit ab3100_probe(struct i2c_client *client,
        int err;
        int i;
 
-       ab3100 = kzalloc(sizeof(struct ab3100), GFP_KERNEL);
+       ab3100 = devm_kzalloc(&client->dev, sizeof(struct ab3100), GFP_KERNEL);
        if (!ab3100) {
                dev_err(&client->dev, "could not allocate AB3100 device\n");
                return -ENOMEM;
@@ -921,7 +921,7 @@ static int __devinit ab3100_probe(struct i2c_client *client,
 
        /* Attach a second dummy i2c_client to the test register address */
        ab3100->testreg_client = i2c_new_dummy(client->adapter,
-                                                    client->addr + 1);
+                                              client->addr + 1);
        if (!ab3100->testreg_client) {
                err = -ENOMEM;
                goto exit_no_testreg_client;
@@ -931,13 +931,13 @@ static int __devinit ab3100_probe(struct i2c_client *client,
        if (err)
                goto exit_no_setup;
 
-       err = request_threaded_irq(client->irq, NULL, ab3100_irq_handler,
-                               IRQF_ONESHOT, "ab3100-core", ab3100);
-       /* This real unpredictable IRQ is of course sampled for entropy */
-       rand_initialize_irq(client->irq);
-
+       err = devm_request_threaded_irq(&client->dev,
+                                       client->irq, NULL, ab3100_irq_handler,
+                                       IRQF_ONESHOT, "ab3100-core", ab3100);
        if (err)
                goto exit_no_irq;
+       /* This real unpredictable IRQ is of course sampled for entropy */
+       rand_initialize_irq(client->irq);
 
        err = abx500_register_ops(&client->dev, &ab3100_ops);
        if (err)
@@ -962,7 +962,6 @@ static int __devinit ab3100_probe(struct i2c_client *client,
        i2c_unregister_device(ab3100->testreg_client);
  exit_no_testreg_client:
  exit_no_detect:
-       kfree(ab3100);
        return err;
 }
 
@@ -972,16 +971,8 @@ static int __devexit ab3100_remove(struct i2c_client *client)
 
        /* Unregister subdevices */
        mfd_remove_devices(&client->dev);
-
        ab3100_remove_debugfs();
        i2c_unregister_device(ab3100->testreg_client);
-
-       /*
-        * At this point, all subscribers should have unregistered
-        * their notifiers so deactivate IRQ
-        */
-       free_irq(client->irq, ab3100);
-       kfree(ab3100);
        return 0;
 }
 
index dac0e299860353f0a299a8b66c14c745e587a133..626b4ecaf64761fdd3cd43ac3f02986d6830e467 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
@@ -140,7 +141,7 @@ static const char ab8500_version_str[][7] = {
        [AB8500_VERSION_AB8540] = "AB8540",
 };
 
-static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
+static int ab8500_prcmu_write(struct ab8500 *ab8500, u16 addr, u8 data)
 {
        int ret;
 
@@ -150,7 +151,7 @@ static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
        return ret;
 }
 
-static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
+static int ab8500_prcmu_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
        u8 data)
 {
        int ret;
@@ -162,7 +163,7 @@ static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
        return ret;
 }
 
-static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
+static int ab8500_prcmu_read(struct ab8500 *ab8500, u16 addr)
 {
        int ret;
        u8 data;
@@ -361,7 +362,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
 static void ab8500_irq_mask(struct irq_data *data)
 {
        struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
-       int offset = data->irq - ab8500->irq_base;
+       int offset = data->hwirq;
        int index = offset / 8;
        int mask = 1 << (offset % 8);
 
@@ -371,7 +372,7 @@ static void ab8500_irq_mask(struct irq_data *data)
 static void ab8500_irq_unmask(struct irq_data *data)
 {
        struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
-       int offset = data->irq - ab8500->irq_base;
+       int offset = data->hwirq;
        int index = offset / 8;
        int mask = 1 << (offset % 8);
 
@@ -510,38 +511,51 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
-static int ab8500_irq_init(struct ab8500 *ab8500)
+/**
+ * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
+ *
+ * @ab8500: ab8500_irq controller to operate on.
+ * @irq: index of the interrupt requested in the chip IRQs
+ *
+ * Useful for drivers to request their own IRQs.
+ */
+int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq)
 {
-       int base = ab8500->irq_base;
-       int irq;
-       int num_irqs;
+       if (!ab8500)
+               return -EINVAL;
 
-       if (is_ab9540(ab8500))
-               num_irqs = AB9540_NR_IRQS;
-       else if (is_ab8505(ab8500))
-               num_irqs = AB8505_NR_IRQS;
-       else
-               num_irqs = AB8500_NR_IRQS;
+       return irq_create_mapping(ab8500->domain, irq);
+}
+EXPORT_SYMBOL_GPL(ab8500_irq_get_virq);
+
+static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
+                               irq_hw_number_t hwirq)
+{
+       struct ab8500 *ab8500 = d->host_data;
 
-       for (irq = base; irq < base + num_irqs; irq++) {
-               irq_set_chip_data(irq, ab8500);
-               irq_set_chip_and_handler(irq, &ab8500_irq_chip,
-                                        handle_simple_irq);
-               irq_set_nested_thread(irq, 1);
+       if (!ab8500)
+               return -EINVAL;
+
+       irq_set_chip_data(virq, ab8500);
+       irq_set_chip_and_handler(virq, &ab8500_irq_chip,
+                               handle_simple_irq);
+       irq_set_nested_thread(virq, 1);
 #ifdef CONFIG_ARM
-               set_irq_flags(irq, IRQF_VALID);
+       set_irq_flags(virq, IRQF_VALID);
 #else
-               irq_set_noprobe(irq);
+       irq_set_noprobe(virq);
 #endif
-       }
 
        return 0;
 }
 
-static void ab8500_irq_remove(struct ab8500 *ab8500)
+static struct irq_domain_ops ab8500_irq_ops = {
+        .map    = ab8500_irq_map,
+        .xlate  = irq_domain_xlate_twocell,
+};
+
+static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
 {
-       int base = ab8500->irq_base;
-       int irq;
        int num_irqs;
 
        if (is_ab9540(ab8500))
@@ -551,13 +565,22 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
        else
                num_irqs = AB8500_NR_IRQS;
 
-       for (irq = base; irq < base + num_irqs; irq++) {
-#ifdef CONFIG_ARM
-               set_irq_flags(irq, 0);
-#endif
-               irq_set_chip_and_handler(irq, NULL, NULL);
-               irq_set_chip_data(irq, NULL);
+       if (ab8500->irq_base) {
+               ab8500->domain = irq_domain_add_legacy(
+                       NULL, num_irqs, ab8500->irq_base,
+                       0, &ab8500_irq_ops, ab8500);
+       }
+       else {
+               ab8500->domain = irq_domain_add_linear(
+                       np, num_irqs, &ab8500_irq_ops, ab8500);
+       }
+
+       if (!ab8500->domain) {
+               dev_err(ab8500->dev, "Failed to create irqdomain\n");
+               return -ENOSYS;
        }
+
+       return 0;
 }
 
 int ab8500_suspend(struct ab8500 *ab8500)
@@ -947,54 +970,69 @@ static struct mfd_cell __devinitdata abx500_common_devs[] = {
 #ifdef CONFIG_DEBUG_FS
        {
                .name = "ab8500-debug",
+               .of_compatible = "stericsson,ab8500-debug",
                .num_resources = ARRAY_SIZE(ab8500_debug_resources),
                .resources = ab8500_debug_resources,
        },
 #endif
        {
                .name = "ab8500-sysctrl",
+               .of_compatible = "stericsson,ab8500-sysctrl",
        },
        {
                .name = "ab8500-regulator",
+               .of_compatible = "stericsson,ab8500-regulator",
        },
        {
                .name = "ab8500-gpadc",
+               .of_compatible = "stericsson,ab8500-gpadc",
                .num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
                .resources = ab8500_gpadc_resources,
        },
        {
                .name = "ab8500-rtc",
+               .of_compatible = "stericsson,ab8500-rtc",
                .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
                .resources = ab8500_rtc_resources,
        },
        {
                .name = "ab8500-acc-det",
+               .of_compatible = "stericsson,ab8500-acc-det",
                .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
                .resources = ab8500_av_acc_detect_resources,
        },
        {
                .name = "ab8500-poweron-key",
+               .of_compatible = "stericsson,ab8500-poweron-key",
                .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
                .resources = ab8500_poweronkey_db_resources,
        },
        {
                .name = "ab8500-pwm",
+               .of_compatible = "stericsson,ab8500-pwm",
                .id = 1,
        },
        {
                .name = "ab8500-pwm",
+               .of_compatible = "stericsson,ab8500-pwm",
                .id = 2,
        },
        {
                .name = "ab8500-pwm",
+               .of_compatible = "stericsson,ab8500-pwm",
                .id = 3,
        },
-       { .name = "ab8500-leds", },
+       {
+               .name = "ab8500-leds",
+               .of_compatible = "stericsson,ab8500-leds",
+       },
        {
                .name = "ab8500-denc",
+               .of_compatible = "stericsson,ab8500-denc",
        },
        {
                .name = "ab8500-temp",
+               .of_compatible = "stericsson,ab8500-temp",
                .num_resources = ARRAY_SIZE(ab8500_temp_resources),
                .resources = ab8500_temp_resources,
        },
@@ -1026,11 +1064,13 @@ static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
 static struct mfd_cell __devinitdata ab8500_devs[] = {
        {
                .name = "ab8500-gpio",
+               .of_compatible = "stericsson,ab8500-gpio",
                .num_resources = ARRAY_SIZE(ab8500_gpio_resources),
                .resources = ab8500_gpio_resources,
        },
        {
                .name = "ab8500-usb",
+               .of_compatible = "stericsson,ab8500-usb",
                .num_resources = ARRAY_SIZE(ab8500_usb_resources),
                .resources = ab8500_usb_resources,
        },
@@ -1207,16 +1247,17 @@ static struct attribute_group ab9540_attr_group = {
        .attrs  = ab9540_sysfs_entries,
 };
 
-static const struct of_device_id ab8500_match[] = {
-       {
-               .compatible = "stericsson,ab8500",
-               .data = (void *)AB8500_VERSION_AB8500,
-       },
-       {},
-};
-
 static int __devinit ab8500_probe(struct platform_device *pdev)
 {
+       static char *switch_off_status[] = {
+               "Swoff bit programming",
+               "Thermal protection activation",
+               "Vbat lower then BattOk falling threshold",
+               "Watchdog expired",
+               "Non presence of 32kHz clock",
+               "Battery level lower than power on reset threshold",
+               "Power on key 1 pressed longer than 10 seconds",
+               "DB8500 thermal shutdown"};
        struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev);
        const struct platform_device_id *platid = platform_get_device_id(pdev);
        enum ab8500_version version = AB8500_VERSION_UNDEFINED;
@@ -1233,14 +1274,6 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
 
        if (plat)
                ab8500->irq_base = plat->irq_base;
-       else if (np)
-               ret = of_property_read_u32(np, "stericsson,irq-base", &ab8500->irq_base);
-
-       if (!ab8500->irq_base) {
-               dev_info(&pdev->dev, "couldn't find irq-base\n");
-               ret = -EINVAL;
-               goto out_free_ab8500;
-       }
 
        ab8500->dev = &pdev->dev;
 
@@ -1252,9 +1285,9 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
 
        ab8500->irq = resource->start;
 
-       ab8500->read = ab8500_i2c_read;
-       ab8500->write = ab8500_i2c_write;
-       ab8500->write_masked = ab8500_i2c_write_masked;
+       ab8500->read = ab8500_prcmu_read;
+       ab8500->write = ab8500_prcmu_write;
+       ab8500->write_masked = ab8500_prcmu_write_masked;
 
        mutex_init(&ab8500->lock);
        mutex_init(&ab8500->irq_lock);
@@ -1264,9 +1297,6 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
 
        if (platid)
                version = platid->driver_data;
-       else if (np)
-               version = (unsigned int)
-                       of_match_device(ab8500_match, &pdev->dev)->data;
 
        if (version != AB8500_VERSION_UNDEFINED)
                ab8500->version = version;
@@ -1323,7 +1353,20 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
                AB8500_SWITCH_OFF_STATUS, &value);
        if (ret < 0)
                return ret;
-       dev_info(ab8500->dev, "switch off status: %#x", value);
+       dev_info(ab8500->dev, "switch off cause(s) (%#x): ", value);
+
+       if (value) {
+               for (i = 0; i < ARRAY_SIZE(switch_off_status); i++) {
+                       if (value & 1)
+                               printk(KERN_CONT " \"%s\"",
+                                      switch_off_status[i]);
+                       value = value >> 1;
+
+               }
+               printk(KERN_CONT "\n");
+       } else {
+               printk(KERN_CONT " None\n");
+       }
 
        if (plat && plat->init)
                plat->init(ab8500);
@@ -1352,53 +1395,50 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
        for (i = 0; i < ab8500->mask_size; i++)
                ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
 
-       if (ab8500->irq_base) {
-               ret = ab8500_irq_init(ab8500);
-               if (ret)
-                       goto out_freeoldmask;
+       ret = ab8500_irq_init(ab8500, np);
+       if (ret)
+               goto out_freeoldmask;
 
-               /*  Activate this feature only in ab9540 */
-               /*  till tests are done on ab8500 1p2 or later*/
-               if (is_ab9540(ab8500))
-                       ret = request_threaded_irq(ab8500->irq, NULL,
+       /*  Activate this feature only in ab9540 */
+       /*  till tests are done on ab8500 1p2 or later*/
+       if (is_ab9540(ab8500)) {
+               ret = request_threaded_irq(ab8500->irq, NULL,
                                        ab8500_hierarchical_irq,
                                        IRQF_ONESHOT | IRQF_NO_SUSPEND,
                                        "ab8500", ab8500);
-               else
-                       ret = request_threaded_irq(ab8500->irq, NULL,
+       }
+       else {
+               ret = request_threaded_irq(ab8500->irq, NULL,
                                        ab8500_irq,
                                        IRQF_ONESHOT | IRQF_NO_SUSPEND,
                                        "ab8500", ab8500);
                if (ret)
-                       goto out_removeirq;
+                       goto out_freeoldmask;
        }
 
-       if (!np) {
-               ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
-                               ARRAY_SIZE(abx500_common_devs), NULL,
-                               ab8500->irq_base);
+       ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
+                       ARRAY_SIZE(abx500_common_devs), NULL,
+                       ab8500->irq_base);
+       if (ret)
+               goto out_freeirq;
 
-               if (ret)
-                       goto out_freeirq;
-
-               if (is_ab9540(ab8500))
-                       ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
-                                       ARRAY_SIZE(ab9540_devs), NULL,
-                                       ab8500->irq_base);
-               else
-                       ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
-                                       ARRAY_SIZE(ab8500_devs), NULL,
-                                       ab8500->irq_base);
-               if (ret)
-                       goto out_freeirq;
+       if (is_ab9540(ab8500))
+               ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
+                               ARRAY_SIZE(ab9540_devs), NULL,
+                               ab8500->irq_base);
+       else
+               ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
+                               ARRAY_SIZE(ab8500_devs), NULL,
+                               ab8500->irq_base);
+       if (ret)
+               goto out_freeirq;
 
-               if (is_ab9540(ab8500) || is_ab8505(ab8500))
-                       ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs,
-                                       ARRAY_SIZE(ab9540_ab8505_devs), NULL,
-                                       ab8500->irq_base);
-               if (ret)
-                       goto out_freeirq;
-       }
+       if (is_ab9540(ab8500) || is_ab8505(ab8500))
+               ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs,
+                               ARRAY_SIZE(ab9540_ab8505_devs), NULL,
+                               ab8500->irq_base);
+       if (ret)
+               goto out_freeirq;
 
        if (!no_bm) {
                /* Add battery management devices */
@@ -1417,15 +1457,11 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
                                        &ab8500_attr_group);
        if (ret)
                dev_err(ab8500->dev, "error creating sysfs entries\n");
-       else
-               return ret;
+
+       return ret;
 
 out_freeirq:
-       if (ab8500->irq_base)
-               free_irq(ab8500->irq, ab8500);
-out_removeirq:
-       if (ab8500->irq_base)
-               ab8500_irq_remove(ab8500);
+       free_irq(ab8500->irq, ab8500);
 out_freeoldmask:
        kfree(ab8500->oldmask);
 out_freemask:
@@ -1444,11 +1480,10 @@ static int __devexit ab8500_remove(struct platform_device *pdev)
                sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
        else
                sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
+
        mfd_remove_devices(ab8500->dev);
-       if (ab8500->irq_base) {
-               free_irq(ab8500->irq, ab8500);
-               ab8500_irq_remove(ab8500);
-       }
+       free_irq(ab8500->irq, ab8500);
+
        kfree(ab8500->oldmask);
        kfree(ab8500->mask);
        kfree(ab8500);
@@ -1468,7 +1503,6 @@ static struct platform_driver ab8500_core_driver = {
        .driver = {
                .name = "ab8500-core",
                .owner = THIS_MODULE,
-               .of_match_table = ab8500_match,
        },
        .probe  = ab8500_probe,
        .remove = __devexit_p(ab8500_remove),
@@ -1484,7 +1518,7 @@ static void __exit ab8500_core_exit(void)
 {
        platform_driver_unregister(&ab8500_core_driver);
 }
-arch_initcall(ab8500_core_init);
+core_initcall(ab8500_core_init);
 module_exit(ab8500_core_exit);
 
 MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
index 50c4c89ab2202fba117a05087799bfaf9ddba9df..c4cb806978acd62603bc76a6780a2cad633fe4e9 100644 (file)
@@ -31,12 +31,12 @@ struct ab8500_reg_range {
 };
 
 /**
- * struct ab8500_i2c_ranges
+ * struct ab8500_prcmu_ranges
  * @num_ranges: the number of ranges in the list
  * @bankid: bank identifier
  * @range: the list of register ranges
  */
-struct ab8500_i2c_ranges {
+struct ab8500_prcmu_ranges {
        u8 num_ranges;
        u8 bankid;
        const struct ab8500_reg_range *range;
@@ -47,7 +47,7 @@ struct ab8500_i2c_ranges {
 
 #define AB8500_REV_REG 0x80
 
-static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = {
+static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
        [0x0] = {
                .num_ranges = 0,
                .range = 0,
@@ -608,16 +608,10 @@ static int __devexit ab8500_debug_remove(struct platform_device *plf)
        return 0;
 }
 
-static const struct of_device_id ab8500_debug_match[] = {
-        { .compatible = "stericsson,ab8500-debug", },
-        {}
-};
-
 static struct platform_driver ab8500_debug_driver = {
        .driver = {
                .name = "ab8500-debug",
                .owner = THIS_MODULE,
-               .of_match_table = ab8500_debug_match,
        },
        .probe  = ab8500_debug_probe,
        .remove = __devexit_p(ab8500_debug_remove)
index b86fd8e1ec3fbae7c4bf6770c1598a777d657d78..866f95960b4b69b34f2fd2e6347842f9b9b096b8 100644 (file)
@@ -599,7 +599,8 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev)
        /* Register interrupt  - SwAdcComplete */
        ret = request_threaded_irq(gpadc->irq, NULL,
                ab8500_bm_gpswadcconvend_handler,
-               IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc", gpadc);
+               IRQF_ONESHOT | IRQF_NO_SUSPEND | IRQF_SHARED,
+                               "ab8500-gpadc", gpadc);
        if (ret < 0) {
                dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n",
                        gpadc->irq);
@@ -648,18 +649,12 @@ static int __devexit ab8500_gpadc_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id ab8500_gpadc_match[] = {
-       { .compatible = "stericsson,ab8500-gpadc", },
-       {}
-};
-
 static struct platform_driver ab8500_gpadc_driver = {
        .probe = ab8500_gpadc_probe,
        .remove = __devexit_p(ab8500_gpadc_remove),
        .driver = {
                .name = "ab8500-gpadc",
                .owner = THIS_MODULE,
-               .of_match_table = ab8500_gpadc_match,
        },
 };
 
index 5a3e51ccf25863b94dccd26b25f4e7002b90ac97..c28d4eb1eff019517d166476c590652f2ac1b8b1 100644 (file)
@@ -61,16 +61,10 @@ static int __devexit ab8500_sysctrl_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id ab8500_sysctrl_match[] = {
-       { .compatible = "stericsson,ab8500-sysctrl", },
-       {}
-};
-
 static struct platform_driver ab8500_sysctrl_driver = {
        .driver = {
                .name = "ab8500-sysctrl",
                .owner = THIS_MODULE,
-               .of_match_table = ab8500_sysctrl_match,
        },
        .probe = ab8500_sysctrl_probe,
        .remove = __devexit_p(ab8500_sysctrl_remove),
index 8d816cce8322ebecdf8d40e29f0c0b0a3aedcbdb..ea8b9475731dd9fc48958f13eaa7aa0af262c573 100644 (file)
@@ -320,7 +320,7 @@ static int __devexit adp5520_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int adp5520_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
index 6da06341f6c909312afea387e875fe82cc1592b8..5576e07576decb0684abbc3d2c3d36d80784965f 100644 (file)
@@ -83,7 +83,7 @@ static int __devinit of_anatop_probe(struct platform_device *pdev)
        drvdata->ioreg = ioreg;
        spin_lock_init(&drvdata->reglock);
        platform_set_drvdata(pdev, drvdata);
-       of_platform_populate(np, of_anatop_match, NULL, dev);
+       of_platform_populate(np, NULL, NULL, dev);
 
        return 0;
 }
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
new file mode 100644 (file)
index 0000000..c7983e8
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * Arizona core driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+
+static const char *wm5102_core_supplies[] = {
+       "AVDD",
+       "DBVDD1",
+};
+
+int arizona_clk32k_enable(struct arizona *arizona)
+{
+       int ret = 0;
+
+       mutex_lock(&arizona->clk_lock);
+
+       arizona->clk32k_ref++;
+
+       if (arizona->clk32k_ref == 1)
+               ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
+                                        ARIZONA_CLK_32K_ENA,
+                                        ARIZONA_CLK_32K_ENA);
+
+       if (ret != 0)
+               arizona->clk32k_ref--;
+
+       mutex_unlock(&arizona->clk_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_clk32k_enable);
+
+int arizona_clk32k_disable(struct arizona *arizona)
+{
+       int ret = 0;
+
+       mutex_lock(&arizona->clk_lock);
+
+       BUG_ON(arizona->clk32k_ref <= 0);
+
+       arizona->clk32k_ref--;
+
+       if (arizona->clk32k_ref == 0)
+               regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
+                                  ARIZONA_CLK_32K_ENA, 0);
+
+       mutex_unlock(&arizona->clk_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_clk32k_disable);
+
+static irqreturn_t arizona_clkgen_err(int irq, void *data)
+{
+       struct arizona *arizona = data;
+
+       dev_err(arizona->dev, "CLKGEN error\n");
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t arizona_underclocked(int irq, void *data)
+{
+       struct arizona *arizona = data;
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8,
+                         &val);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to read underclock status: %d\n",
+                       ret);
+               return IRQ_NONE;
+       }
+
+       if (val & ARIZONA_AIF3_UNDERCLOCKED_STS)
+               dev_err(arizona->dev, "AIF3 underclocked\n");
+       if (val & ARIZONA_AIF3_UNDERCLOCKED_STS)
+               dev_err(arizona->dev, "AIF3 underclocked\n");
+       if (val & ARIZONA_AIF2_UNDERCLOCKED_STS)
+               dev_err(arizona->dev, "AIF1 underclocked\n");
+       if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS)
+               dev_err(arizona->dev, "ISRC2 underclocked\n");
+       if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS)
+               dev_err(arizona->dev, "ISRC1 underclocked\n");
+       if (val & ARIZONA_FX_UNDERCLOCKED_STS)
+               dev_err(arizona->dev, "FX underclocked\n");
+       if (val & ARIZONA_ASRC_UNDERCLOCKED_STS)
+               dev_err(arizona->dev, "ASRC underclocked\n");
+       if (val & ARIZONA_DAC_UNDERCLOCKED_STS)
+               dev_err(arizona->dev, "DAC underclocked\n");
+       if (val & ARIZONA_ADC_UNDERCLOCKED_STS)
+               dev_err(arizona->dev, "ADC underclocked\n");
+       if (val & ARIZONA_MIXER_UNDERCLOCKED_STS)
+               dev_err(arizona->dev, "Mixer underclocked\n");
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t arizona_overclocked(int irq, void *data)
+{
+       struct arizona *arizona = data;
+       unsigned int val[2];
+       int ret;
+       
+       ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6,
+                              &val[0], 2);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to read overclock status: %d\n",
+                       ret);
+               return IRQ_NONE;
+       }
+
+       if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "PWM overclocked\n");
+       if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "FX core overclocked\n");
+       if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "DAC SYS overclocked\n");
+       if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "DAC WARP overclocked\n");
+       if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "ADC overclocked\n");
+       if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "Mixer overclocked\n");
+       if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "AIF3 overclocked\n");
+       if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "AIF2 overclocked\n");
+       if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "AIF1 overclocked\n");
+       if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "Pad control overclocked\n");
+
+       if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "Slimbus subsystem overclocked\n");
+       if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "Slimbus async overclocked\n");
+       if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "Slimbus sync overclocked\n");
+       if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "ASRC async system overclocked\n");
+       if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "ASRC async WARP overclocked\n");
+       if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "ASRC sync system overclocked\n");
+       if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "ASRC sync WARP overclocked\n");
+       if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "DSP1 overclocked\n");
+       if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "ISRC2 overclocked\n");
+       if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS)
+               dev_err(arizona->dev, "ISRC1 overclocked\n");
+
+       return IRQ_HANDLED;
+}
+
+static int arizona_wait_for_boot(struct arizona *arizona)
+{
+       unsigned int reg;
+       int ret, i;
+
+       /*
+        * We can't use an interrupt as we need to runtime resume to do so,
+        * we won't race with the interrupt handler as it'll be blocked on
+        * runtime resume.
+        */
+       for (i = 0; i < 5; i++) {
+               msleep(1);
+
+               ret = regmap_read(arizona->regmap,
+                                 ARIZONA_INTERRUPT_RAW_STATUS_5, &reg);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to read boot state: %d\n",
+                               ret);
+                       continue;
+               }
+
+               if (reg & ARIZONA_BOOT_DONE_STS)
+                       break;
+       }
+
+       if (reg & ARIZONA_BOOT_DONE_STS) {
+               regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5,
+                            ARIZONA_BOOT_DONE_STS);
+       } else {
+               dev_err(arizona->dev, "Device boot timed out: %x\n", reg);
+               return -ETIMEDOUT;
+       }
+
+       pm_runtime_mark_last_busy(arizona->dev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int arizona_runtime_resume(struct device *dev)
+{
+       struct arizona *arizona = dev_get_drvdata(dev);
+       int ret;
+
+       dev_dbg(arizona->dev, "Leaving AoD mode\n");
+
+       ret = regulator_enable(arizona->dcvdd);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret);
+               return ret;
+       }
+
+       regcache_cache_only(arizona->regmap, false);
+
+       ret = arizona_wait_for_boot(arizona);
+       if (ret != 0) {
+               regulator_disable(arizona->dcvdd);
+               return ret;
+       }
+
+       regcache_sync(arizona->regmap);
+
+       return 0;
+}
+
+static int arizona_runtime_suspend(struct device *dev)
+{
+       struct arizona *arizona = dev_get_drvdata(dev);
+
+       dev_dbg(arizona->dev, "Entering AoD mode\n");
+
+       regulator_disable(arizona->dcvdd);
+       regcache_cache_only(arizona->regmap, true);
+       regcache_mark_dirty(arizona->regmap);
+
+       return 0;
+}
+#endif
+
+const struct dev_pm_ops arizona_pm_ops = {
+       SET_RUNTIME_PM_OPS(arizona_runtime_suspend,
+                          arizona_runtime_resume,
+                          NULL)
+};
+EXPORT_SYMBOL_GPL(arizona_pm_ops);
+
+static struct mfd_cell early_devs[] = {
+       { .name = "arizona-ldo1" },
+};
+
+static struct mfd_cell wm5102_devs[] = {
+       { .name = "arizona-extcon" },
+       { .name = "arizona-gpio" },
+       { .name = "arizona-micsupp" },
+       { .name = "arizona-pwm" },
+       { .name = "wm5102-codec" },
+};
+
+static struct mfd_cell wm5110_devs[] = {
+       { .name = "arizona-extcon" },
+       { .name = "arizona-gpio" },
+       { .name = "arizona-micsupp" },
+       { .name = "arizona-pwm" },
+       { .name = "wm5110-codec" },
+};
+
+int __devinit arizona_dev_init(struct arizona *arizona)
+{
+       struct device *dev = arizona->dev;
+       const char *type_name;
+       unsigned int reg, val;
+       int ret, i;
+
+       dev_set_drvdata(arizona->dev, arizona);
+       mutex_init(&arizona->clk_lock);
+
+       if (dev_get_platdata(arizona->dev))
+               memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
+                      sizeof(arizona->pdata));
+
+       regcache_cache_only(arizona->regmap, true);
+
+       switch (arizona->type) {
+       case WM5102:
+       case WM5110:
+               for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++)
+                       arizona->core_supplies[i].supply
+                               = wm5102_core_supplies[i];
+               arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies);
+               break;
+       default:
+               dev_err(arizona->dev, "Unknown device type %d\n",
+                       arizona->type);
+               return -EINVAL;
+       }
+
+       ret = mfd_add_devices(arizona->dev, -1, early_devs,
+                             ARRAY_SIZE(early_devs), NULL, 0);
+       if (ret != 0) {
+               dev_err(dev, "Failed to add early children: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies,
+                                     arizona->core_supplies);
+       if (ret != 0) {
+               dev_err(dev, "Failed to request core supplies: %d\n",
+                       ret);
+               goto err_early;
+       }
+
+       arizona->dcvdd = devm_regulator_get(arizona->dev, "DCVDD");
+       if (IS_ERR(arizona->dcvdd)) {
+               ret = PTR_ERR(arizona->dcvdd);
+               dev_err(dev, "Failed to request DCVDD: %d\n", ret);
+               goto err_early;
+       }
+
+       ret = regulator_bulk_enable(arizona->num_core_supplies,
+                                   arizona->core_supplies);
+       if (ret != 0) {
+               dev_err(dev, "Failed to enable core supplies: %d\n",
+                       ret);
+               goto err_early;
+       }
+
+       ret = regulator_enable(arizona->dcvdd);
+       if (ret != 0) {
+               dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
+               goto err_enable;
+       }
+
+       if (arizona->pdata.reset) {
+               /* Start out with /RESET low to put the chip into reset */
+               ret = gpio_request_one(arizona->pdata.reset,
+                                      GPIOF_DIR_OUT | GPIOF_INIT_LOW,
+                                      "arizona /RESET");
+               if (ret != 0) {
+                       dev_err(dev, "Failed to request /RESET: %d\n", ret);
+                       goto err_dcvdd;
+               }
+
+               gpio_set_value_cansleep(arizona->pdata.reset, 1);
+       }
+
+       regcache_cache_only(arizona->regmap, false);
+
+       ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
+       if (ret != 0) {
+               dev_err(dev, "Failed to read ID register: %d\n", ret);
+               goto err_reset;
+       }
+
+       ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION,
+                         &arizona->rev);
+       if (ret != 0) {
+               dev_err(dev, "Failed to read revision register: %d\n", ret);
+               goto err_reset;
+       }
+       arizona->rev &= ARIZONA_DEVICE_REVISION_MASK;
+
+       switch (reg) {
+#ifdef CONFIG_MFD_WM5102
+       case 0x5102:
+               type_name = "WM5102";
+               if (arizona->type != WM5102) {
+                       dev_err(arizona->dev, "WM5102 registered as %d\n",
+                               arizona->type);
+                       arizona->type = WM5102;
+               }
+               ret = wm5102_patch(arizona);
+               break;
+#endif
+#ifdef CONFIG_MFD_WM5110
+       case 0x5110:
+               type_name = "WM5110";
+               if (arizona->type != WM5110) {
+                       dev_err(arizona->dev, "WM5110 registered as %d\n",
+                               arizona->type);
+                       arizona->type = WM5110;
+               }
+               ret = wm5110_patch(arizona);
+               break;
+#endif
+       default:
+               dev_err(arizona->dev, "Unknown device ID %x\n", reg);
+               goto err_reset;
+       }
+
+       dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A');
+
+       if (ret != 0)
+               dev_err(arizona->dev, "Failed to apply patch: %d\n", ret);
+
+       /* If we have a /RESET GPIO we'll already be reset */
+       if (!arizona->pdata.reset) {
+               ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to reset device: %d\n", ret);
+                       goto err_reset;
+               }
+       }
+
+       ret = arizona_wait_for_boot(arizona);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Device failed initial boot: %d\n", ret);
+               goto err_reset;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
+               if (!arizona->pdata.gpio_defaults[i])
+                       continue;
+
+               regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i,
+                            arizona->pdata.gpio_defaults[i]);
+       }
+
+       pm_runtime_set_autosuspend_delay(arizona->dev, 100);
+       pm_runtime_use_autosuspend(arizona->dev);
+       pm_runtime_enable(arizona->dev);
+
+       /* Chip default */
+       if (!arizona->pdata.clk32k_src)
+               arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2;
+
+       switch (arizona->pdata.clk32k_src) {
+       case ARIZONA_32KZ_MCLK1:
+       case ARIZONA_32KZ_MCLK2:
+               regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
+                                  ARIZONA_CLK_32K_SRC_MASK,
+                                  arizona->pdata.clk32k_src - 1);
+               break;
+       case ARIZONA_32KZ_NONE:
+               regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
+                                  ARIZONA_CLK_32K_SRC_MASK, 2);
+               break;
+       default:
+               dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n",
+                       arizona->pdata.clk32k_src);
+               ret = -EINVAL;
+               goto err_reset;
+       }
+
+       for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
+               /* Default for both is 0 so noop with defaults */
+               val = arizona->pdata.dmic_ref[i]
+                       << ARIZONA_IN1_DMIC_SUP_SHIFT;
+               val |= arizona->pdata.inmode[i] << ARIZONA_IN1_MODE_SHIFT;
+
+               regmap_update_bits(arizona->regmap,
+                                  ARIZONA_IN1L_CONTROL + (i * 8),
+                                  ARIZONA_IN1_DMIC_SUP_MASK |
+                                  ARIZONA_IN1_MODE_MASK, val);
+       }
+
+       for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) {
+               /* Default is 0 so noop with defaults */
+               if (arizona->pdata.out_mono[i])
+                       val = ARIZONA_OUT1_MONO;
+               else
+                       val = 0;
+
+               regmap_update_bits(arizona->regmap,
+                                  ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8),
+                                  ARIZONA_OUT1_MONO, val);
+       }
+
+       for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) {
+               if (arizona->pdata.spk_mute[i])
+                       regmap_update_bits(arizona->regmap,
+                                          ARIZONA_PDM_SPK1_CTRL_1 + (i * 2),
+                                          ARIZONA_SPK1_MUTE_ENDIAN_MASK |
+                                          ARIZONA_SPK1_MUTE_SEQ1_MASK,
+                                          arizona->pdata.spk_mute[i]);
+
+               if (arizona->pdata.spk_fmt[i])
+                       regmap_update_bits(arizona->regmap,
+                                          ARIZONA_PDM_SPK1_CTRL_2 + (i * 2),
+                                          ARIZONA_SPK1_FMT_MASK,
+                                          arizona->pdata.spk_fmt[i]);
+       }
+
+       /* Set up for interrupts */
+       ret = arizona_irq_init(arizona);
+       if (ret != 0)
+               goto err_reset;
+
+       arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error",
+                           arizona_clkgen_err, arizona);
+       arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked",
+                           arizona_overclocked, arizona);
+       arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked",
+                           arizona_underclocked, arizona);
+
+       switch (arizona->type) {
+       case WM5102:
+               ret = mfd_add_devices(arizona->dev, -1, wm5102_devs,
+                                     ARRAY_SIZE(wm5102_devs), NULL, 0);
+               break;
+       case WM5110:
+               ret = mfd_add_devices(arizona->dev, -1, wm5110_devs,
+                                     ARRAY_SIZE(wm5102_devs), NULL, 0);
+               break;
+       }
+
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret);
+               goto err_irq;
+       }
+
+#ifdef CONFIG_PM_RUNTIME
+       regulator_disable(arizona->dcvdd);
+#endif
+
+       return 0;
+
+err_irq:
+       arizona_irq_exit(arizona);
+err_reset:
+       if (arizona->pdata.reset) {
+               gpio_set_value_cansleep(arizona->pdata.reset, 1);
+               gpio_free(arizona->pdata.reset);
+       }
+err_dcvdd:
+       regulator_disable(arizona->dcvdd);
+err_enable:
+       regulator_bulk_disable(arizona->num_core_supplies,
+                              arizona->core_supplies);
+err_early:
+       mfd_remove_devices(dev);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(arizona_dev_init);
+
+int __devexit arizona_dev_exit(struct arizona *arizona)
+{
+       mfd_remove_devices(arizona->dev);
+       arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona);
+       arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona);
+       arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona);
+       pm_runtime_disable(arizona->dev);
+       arizona_irq_exit(arizona);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_dev_exit);
diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c
new file mode 100644 (file)
index 0000000..570c4b4
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Arizona-i2c.c  --  Arizona I2C bus interface
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/arizona/core.h>
+
+#include "arizona.h"
+
+static __devinit int arizona_i2c_probe(struct i2c_client *i2c,
+                                         const struct i2c_device_id *id)
+{
+       struct arizona *arizona;
+       const struct regmap_config *regmap_config;
+       int ret;
+
+       switch (id->driver_data) {
+#ifdef CONFIG_MFD_WM5102
+       case WM5102:
+               regmap_config = &wm5102_i2c_regmap;
+               break;
+#endif
+#ifdef CONFIG_MFD_WM5110
+       case WM5110:
+               regmap_config = &wm5110_i2c_regmap;
+               break;
+#endif
+       default:
+               dev_err(&i2c->dev, "Unknown device type %ld\n",
+                       id->driver_data);
+               return -EINVAL;
+       }
+
+       arizona = devm_kzalloc(&i2c->dev, sizeof(*arizona), GFP_KERNEL);
+       if (arizona == NULL)
+               return -ENOMEM;
+
+       arizona->regmap = devm_regmap_init_i2c(i2c, regmap_config);
+       if (IS_ERR(arizona->regmap)) {
+               ret = PTR_ERR(arizona->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       arizona->type = id->driver_data;
+       arizona->dev = &i2c->dev;
+       arizona->irq = i2c->irq;
+
+       return arizona_dev_init(arizona);
+}
+
+static int __devexit arizona_i2c_remove(struct i2c_client *i2c)
+{
+       struct arizona *arizona = dev_get_drvdata(&i2c->dev);
+       arizona_dev_exit(arizona);
+       return 0;
+}
+
+static const struct i2c_device_id arizona_i2c_id[] = {
+       { "wm5102", WM5102 },
+       { "wm5110", WM5110 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, arizona_i2c_id);
+
+static struct i2c_driver arizona_i2c_driver = {
+       .driver = {
+               .name   = "arizona",
+               .owner  = THIS_MODULE,
+               .pm     = &arizona_pm_ops,
+       },
+       .probe          = arizona_i2c_probe,
+       .remove         = __devexit_p(arizona_i2c_remove),
+       .id_table       = arizona_i2c_id,
+};
+
+module_i2c_driver(arizona_i2c_driver);
+
+MODULE_DESCRIPTION("Arizona I2C bus interface");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c
new file mode 100644 (file)
index 0000000..98ac345
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Arizona interrupt support
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+
+static int arizona_map_irq(struct arizona *arizona, int irq)
+{
+       int ret;
+
+       ret = regmap_irq_get_virq(arizona->aod_irq_chip, irq);
+       if (ret < 0)
+               ret = regmap_irq_get_virq(arizona->irq_chip, irq);
+
+       return ret;
+}
+
+int arizona_request_irq(struct arizona *arizona, int irq, char *name,
+                          irq_handler_t handler, void *data)
+{
+       irq = arizona_map_irq(arizona, irq);
+       if (irq < 0)
+               return irq;
+
+       return request_threaded_irq(irq, NULL, handler, IRQF_ONESHOT,
+                                   name, data);
+}
+EXPORT_SYMBOL_GPL(arizona_request_irq);
+
+void arizona_free_irq(struct arizona *arizona, int irq, void *data)
+{
+       irq = arizona_map_irq(arizona, irq);
+       if (irq < 0)
+               return;
+
+       free_irq(irq, data);
+}
+EXPORT_SYMBOL_GPL(arizona_free_irq);
+
+int arizona_set_irq_wake(struct arizona *arizona, int irq, int on)
+{
+       irq = arizona_map_irq(arizona, irq);
+       if (irq < 0)
+               return irq;
+
+       return irq_set_irq_wake(irq, on);
+}
+EXPORT_SYMBOL_GPL(arizona_set_irq_wake);
+
+static irqreturn_t arizona_boot_done(int irq, void *data)
+{
+       struct arizona *arizona = data;
+
+       dev_dbg(arizona->dev, "Boot done\n");
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t arizona_ctrlif_err(int irq, void *data)
+{
+       struct arizona *arizona = data;
+
+       /*
+        * For pretty much all potential sources a register cache sync
+        * won't help, we've just got a software bug somewhere.
+        */
+       dev_err(arizona->dev, "Control interface error\n");
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t arizona_irq_thread(int irq, void *data)
+{
+       struct arizona *arizona = data;
+       int i, ret;
+
+       ret = pm_runtime_get_sync(arizona->dev);
+       if (ret < 0) {
+               dev_err(arizona->dev, "Failed to resume device: %d\n", ret);
+               return IRQ_NONE;
+       }
+
+       /* Check both domains */
+       for (i = 0; i < 2; i++)
+               handle_nested_irq(irq_find_mapping(arizona->virq, i));
+
+       pm_runtime_mark_last_busy(arizona->dev);
+       pm_runtime_put_autosuspend(arizona->dev);
+
+       return IRQ_HANDLED;
+}
+
+static void arizona_irq_enable(struct irq_data *data)
+{
+}
+
+static void arizona_irq_disable(struct irq_data *data)
+{
+}
+
+static struct irq_chip arizona_irq_chip = {
+       .name                   = "arizona",
+       .irq_disable            = arizona_irq_disable,
+       .irq_enable             = arizona_irq_enable,
+};
+
+static int arizona_irq_map(struct irq_domain *h, unsigned int virq,
+                             irq_hw_number_t hw)
+{
+       struct regmap_irq_chip_data *data = h->host_data;
+
+       irq_set_chip_data(virq, data);
+       irq_set_chip_and_handler(virq, &arizona_irq_chip, handle_edge_irq);
+       irq_set_nested_thread(virq, 1);
+
+       /* ARM needs us to explicitly flag the IRQ as valid
+        * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+       set_irq_flags(virq, IRQF_VALID);
+#else
+       irq_set_noprobe(virq);
+#endif
+
+       return 0;
+}
+
+static struct irq_domain_ops arizona_domain_ops = {
+       .map    = arizona_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+int arizona_irq_init(struct arizona *arizona)
+{
+       int flags = IRQF_ONESHOT;
+       int ret, i;
+       const struct regmap_irq_chip *aod, *irq;
+
+       switch (arizona->type) {
+#ifdef CONFIG_MFD_WM5102
+       case WM5102:
+               aod = &wm5102_aod;
+               irq = &wm5102_irq;
+               break;
+#endif
+#ifdef CONFIG_MFD_WM5110
+       case WM5110:
+               aod = &wm5110_aod;
+               irq = &wm5110_irq;
+               break;
+#endif
+       default:
+               BUG_ON("Unknown Arizona class device" == NULL);
+               return -EINVAL;
+       }
+
+       if (arizona->pdata.irq_active_high) {
+               ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1,
+                                        ARIZONA_IRQ_POL, 0);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Couldn't set IRQ polarity: %d\n",
+                               ret);
+                       goto err;
+               }
+
+               flags |= IRQF_TRIGGER_HIGH;
+       } else {
+               flags |= IRQF_TRIGGER_LOW;
+       }
+
+       /* Allocate a virtual IRQ domain to distribute to the regmap domains */
+       arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops,
+                                             arizona);
+       if (!arizona->virq) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = regmap_add_irq_chip(arizona->regmap,
+                                 irq_create_mapping(arizona->virq, 0),
+                                 IRQF_ONESHOT, -1, aod,
+                                 &arizona->aod_irq_chip);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to add AOD IRQs: %d\n", ret);
+               goto err_domain;
+       }
+
+       ret = regmap_add_irq_chip(arizona->regmap,
+                                 irq_create_mapping(arizona->virq, 1),
+                                 IRQF_ONESHOT, -1, irq,
+                                 &arizona->irq_chip);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to add AOD IRQs: %d\n", ret);
+               goto err_aod;
+       }
+
+       /* Make sure the boot done IRQ is unmasked for resumes */
+       i = arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE);
+       ret = request_threaded_irq(i, NULL, arizona_boot_done, IRQF_ONESHOT,
+                                  "Boot done", arizona);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to request boot done %d: %d\n",
+                       arizona->irq, ret);
+               goto err_boot_done;
+       }
+
+       /* Handle control interface errors in the core */
+       i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR);
+       ret = request_threaded_irq(i, NULL, arizona_ctrlif_err, IRQF_ONESHOT,
+                                  "Control interface error", arizona);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to request boot done %d: %d\n",
+                       arizona->irq, ret);
+               goto err_ctrlif;
+       }
+
+       ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread,
+                                  flags, "arizona", arizona);
+
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to request IRQ %d: %d\n",
+                       arizona->irq, ret);
+               goto err_main_irq;
+       }
+
+       return 0;
+
+err_main_irq:
+       free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR), arizona);
+err_ctrlif:
+       free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona);
+err_boot_done:
+       regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1),
+                           arizona->irq_chip);
+err_aod:
+       regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0),
+                           arizona->aod_irq_chip);
+err_domain:
+err:
+       return ret;
+}
+
+int arizona_irq_exit(struct arizona *arizona)
+{
+       free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR), arizona);
+       free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona);
+       regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1),
+                           arizona->irq_chip);
+       regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0),
+                           arizona->aod_irq_chip);
+       free_irq(arizona->irq, arizona);
+
+       return 0;
+}
diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c
new file mode 100644 (file)
index 0000000..df2e5a8
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * arizona-spi.c  --  Arizona SPI bus interface
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#include <linux/mfd/arizona/core.h>
+
+#include "arizona.h"
+
+static int __devinit arizona_spi_probe(struct spi_device *spi)
+{
+       const struct spi_device_id *id = spi_get_device_id(spi);
+       struct arizona *arizona;
+       const struct regmap_config *regmap_config;
+       int ret;
+
+       switch (id->driver_data) {
+#ifdef CONFIG_MFD_WM5102
+       case WM5102:
+               regmap_config = &wm5102_spi_regmap;
+               break;
+#endif
+#ifdef CONFIG_MFD_WM5110
+       case WM5110:
+               regmap_config = &wm5110_spi_regmap;
+               break;
+#endif
+       default:
+               dev_err(&spi->dev, "Unknown device type %ld\n",
+                       id->driver_data);
+               return -EINVAL;
+       }
+
+       arizona = devm_kzalloc(&spi->dev, sizeof(*arizona), GFP_KERNEL);
+       if (arizona == NULL)
+               return -ENOMEM;
+
+       arizona->regmap = devm_regmap_init_spi(spi, regmap_config);
+       if (IS_ERR(arizona->regmap)) {
+               ret = PTR_ERR(arizona->regmap);
+               dev_err(&spi->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       arizona->type = id->driver_data;
+       arizona->dev = &spi->dev;
+       arizona->irq = spi->irq;
+
+       return arizona_dev_init(arizona);
+}
+
+static int __devexit arizona_spi_remove(struct spi_device *spi)
+{
+       struct arizona *arizona = dev_get_drvdata(&spi->dev);
+       arizona_dev_exit(arizona);
+       return 0;
+}
+
+static const struct spi_device_id arizona_spi_ids[] = {
+       { "wm5102", WM5102 },
+       { "wm5110", WM5110 },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, arizona_spi_ids);
+
+static struct spi_driver arizona_spi_driver = {
+       .driver = {
+               .name   = "arizona",
+               .owner  = THIS_MODULE,
+               .pm     = &arizona_pm_ops,
+       },
+       .probe          = arizona_spi_probe,
+       .remove         = __devexit_p(arizona_spi_remove),
+       .id_table       = arizona_spi_ids,
+};
+
+module_spi_driver(arizona_spi_driver);
+
+MODULE_DESCRIPTION("Arizona SPI bus interface");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/arizona.h b/drivers/mfd/arizona.h
new file mode 100644 (file)
index 0000000..9798ae5
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * wm5102.h  --  WM5102 MFD internals
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM5102_H
+#define _WM5102_H
+
+#include <linux/regmap.h>
+#include <linux/pm.h>
+
+struct wm_arizona;
+
+extern const struct regmap_config wm5102_i2c_regmap;
+extern const struct regmap_config wm5102_spi_regmap;
+
+extern const struct regmap_config wm5110_i2c_regmap;
+extern const struct regmap_config wm5110_spi_regmap;
+
+extern const struct dev_pm_ops arizona_pm_ops;
+
+extern const struct regmap_irq_chip wm5102_aod;
+extern const struct regmap_irq_chip wm5102_irq;
+
+extern const struct regmap_irq_chip wm5110_aod;
+extern const struct regmap_irq_chip wm5110_irq;
+
+int arizona_dev_init(struct arizona *arizona);
+int arizona_dev_exit(struct arizona *arizona);
+int arizona_irq_init(struct arizona *arizona);
+int arizona_irq_exit(struct arizona *arizona);
+
+#endif
index 1f1313c905736f352d09c8f8d764be2464467cc5..2544910e1fd604f5f6184009a1a208fa5f838cf2 100644 (file)
@@ -772,7 +772,6 @@ EXPORT_SYMBOL_GPL(da9052_regmap_config);
 int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
 {
        struct da9052_pdata *pdata = da9052->dev->platform_data;
-       struct irq_desc *desc;
        int ret;
 
        mutex_init(&da9052->auxadc_lock);
index 50e83dc5dc49b7520dfab72c52c80bb02e485f4c..7040a0081130c93ce6b73145355abec0a8c571b8 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/uaccess.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/regulator/db8500-prcmu.h>
 #include <linux/regulator/machine.h>
 #include <asm/hardware/gic.h>
@@ -2269,10 +2270,10 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
 /**
  * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
  */
-void prcmu_ac_wake_req(void)
+int prcmu_ac_wake_req(void)
 {
        u32 val;
-       u32 status;
+       int ret = 0;
 
        mutex_lock(&mb0_transfer.ac_wake_lock);
 
@@ -2282,39 +2283,32 @@ void prcmu_ac_wake_req(void)
 
        atomic_set(&ac_wake_req_state, 1);
 
-retry:
-       writel((val | PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ), PRCM_HOSTACCESS_REQ);
+       /*
+        * Force Modem Wake-up before hostaccess_req ping-pong.
+        * It prevents Modem to enter in Sleep while acking the hostaccess
+        * request. The 31us delay has been calculated by HWI.
+        */
+       val |= PRCM_HOSTACCESS_REQ_WAKE_REQ;
+       writel(val, PRCM_HOSTACCESS_REQ);
+
+       udelay(31);
+
+       val |= PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ;
+       writel(val, PRCM_HOSTACCESS_REQ);
 
        if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work,
                        msecs_to_jiffies(5000))) {
+#if defined(CONFIG_DBX500_PRCMU_DEBUG)
+               db8500_prcmu_debug_dump(__func__, true, true);
+#endif
                pr_crit("prcmu: %s timed out (5 s) waiting for a reply.\n",
                        __func__);
-               goto unlock_and_return;
-       }
-
-       /*
-        * The modem can generate an AC_WAKE_ACK, and then still go to sleep.
-        * As a workaround, we wait, and then check that the modem is indeed
-        * awake (in terms of the value of the PRCM_MOD_AWAKE_STATUS
-        * register, which may not be the whole truth).
-        */
-       udelay(400);
-       status = (readl(PRCM_MOD_AWAKE_STATUS) & BITS(0, 2));
-       if (status != (PRCM_MOD_AWAKE_STATUS_PRCM_MOD_AAPD_AWAKE |
-                       PRCM_MOD_AWAKE_STATUS_PRCM_MOD_COREPD_AWAKE)) {
-               pr_err("prcmu: %s received ack, but modem not awake (0x%X).\n",
-                       __func__, status);
-               udelay(1200);
-               writel(val, PRCM_HOSTACCESS_REQ);
-               if (wait_for_completion_timeout(&mb0_transfer.ac_wake_work,
-                               msecs_to_jiffies(5000)))
-                       goto retry;
-               pr_crit("prcmu: %s timed out (5 s) waiting for AC_SLEEP_ACK.\n",
-                       __func__);
+               ret = -EFAULT;
        }
 
 unlock_and_return:
        mutex_unlock(&mb0_transfer.ac_wake_lock);
+       return ret;
 }
 
 /**
@@ -2945,14 +2939,31 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
        },
 };
 
+static struct resource ab8500_resources[] = {
+       [0] = {
+               .start  = IRQ_DB8500_AB8500,
+               .end    = IRQ_DB8500_AB8500,
+               .flags  = IORESOURCE_IRQ
+       }
+};
+
 static struct mfd_cell db8500_prcmu_devs[] = {
        {
                .name = "db8500-prcmu-regulators",
+               .of_compatible = "stericsson,db8500-prcmu-regulator",
                .platform_data = &db8500_regulators,
                .pdata_size = sizeof(db8500_regulators),
        },
        {
                .name = "cpufreq-u8500",
+               .of_compatible = "stericsson,cpufreq-u8500",
+       },
+       {
+               .name = "ab8500-core",
+               .of_compatible = "stericsson,ab8500",
+               .num_resources = ARRAY_SIZE(ab8500_resources),
+               .resources = ab8500_resources,
+               .id = AB8500_VERSION_AB8500,
        },
 };
 
@@ -2962,8 +2973,9 @@ static struct mfd_cell db8500_prcmu_devs[] = {
  */
 static int __devinit db8500_prcmu_probe(struct platform_device *pdev)
 {
+       struct ab8500_platform_data *ab8500_platdata = pdev->dev.platform_data;
        struct device_node *np = pdev->dev.of_node;
-       int irq = 0, err = 0;
+       int irq = 0, err = 0, i;
 
        if (ux500_is_svp())
                return -ENODEV;
@@ -2987,16 +2999,21 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev)
                goto no_irq_return;
        }
 
+       for (i = 0; i < ARRAY_SIZE(db8500_prcmu_devs); i++) {
+               if (!strcmp(db8500_prcmu_devs[i].name, "ab8500-core")) {
+                       db8500_prcmu_devs[i].platform_data = ab8500_platdata;
+                       db8500_prcmu_devs[i].pdata_size = sizeof(struct ab8500_platform_data);
+               }
+       }
+
        if (cpu_is_u8500v20_or_later())
                prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
 
-       if (!np) {
-               err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
-                               ARRAY_SIZE(db8500_prcmu_devs), NULL, 0);
-               if (err) {
-                       pr_err("prcmu: Failed to add subdevices\n");
-                       return err;
-               }
+       err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
+                       ARRAY_SIZE(db8500_prcmu_devs), NULL, 0);
+       if (err) {
+               pr_err("prcmu: Failed to add subdevices\n");
+               return err;
        }
 
        pr_info("DB8500 PRCMU initialized\n");
@@ -3004,11 +3021,16 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev)
 no_irq_return:
        return err;
 }
+static const struct of_device_id db8500_prcmu_match[] = {
+       { .compatible = "stericsson,db8500-prcmu"},
+       { },
+};
 
 static struct platform_driver db8500_prcmu_driver = {
        .driver = {
                .name = "db8500-prcmu",
                .owner = THIS_MODULE,
+               .of_match_table = db8500_prcmu_match,
        },
        .probe = db8500_prcmu_probe,
 };
@@ -3018,7 +3040,7 @@ static int __init db8500_prcmu_init(void)
        return platform_driver_register(&db8500_prcmu_driver);
 }
 
-arch_initcall(db8500_prcmu_init);
+core_initcall(db8500_prcmu_init);
 
 MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com>");
 MODULE_DESCRIPTION("DB8500 PRCM Unit driver");
index 3a0bf91d7780894a552f0f83d0cd9defb4637c63..23108a6e316782612eafda90cb2944b37a644e0e 100644 (file)
 
 #define PRCM_HOSTACCESS_REQ    (_PRCMU_BASE + 0x334)
 #define PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ 0x1
+#define PRCM_HOSTACCESS_REQ_WAKE_REQ   BIT(16)
 #define ARM_WAKEUP_MODEM       0x1
 
 #define PRCM_ARM_IT1_CLR       (_PRCMU_BASE + 0x48C)
diff --git a/drivers/mfd/max77686-irq.c b/drivers/mfd/max77686-irq.c
new file mode 100644 (file)
index 0000000..cdc3280
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * max77686-irq.c - Interrupt controller support for MAX77686
+ *
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * Chiwoong Byun <woong.byun@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max8997-irq.c
+ */
+
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/mfd/max77686.h>
+#include <linux/mfd/max77686-private.h>
+#include <linux/irqdomain.h>
+#include <linux/regmap.h>
+
+enum {
+       MAX77686_DEBUG_IRQ_INFO = 1 << 0,
+       MAX77686_DEBUG_IRQ_MASK = 1 << 1,
+       MAX77686_DEBUG_IRQ_INT = 1 << 2,
+};
+
+static int debug_mask = 0;
+module_param(debug_mask, int, 0);
+MODULE_PARM_DESC(debug_mask, "Set debug_mask : 0x0=off 0x1=IRQ_INFO  0x2=IRQ_MASK 0x4=IRQ_INI)");
+
+static const u8 max77686_mask_reg[] = {
+       [PMIC_INT1] = MAX77686_REG_INT1MSK,
+       [PMIC_INT2] = MAX77686_REG_INT2MSK,
+       [RTC_INT] = MAX77686_RTC_INTM,
+};
+
+static struct regmap *max77686_get_regmap(struct max77686_dev *max77686,
+                               enum max77686_irq_source src)
+{
+       switch (src) {
+       case PMIC_INT1 ... PMIC_INT2:
+               return max77686->regmap;
+       case RTC_INT:
+               return max77686->rtc_regmap;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+}
+
+struct max77686_irq_data {
+       int mask;
+       enum max77686_irq_source group;
+};
+
+#define DECLARE_IRQ(idx, _group, _mask)                \
+       [(idx)] = { .group = (_group), .mask = (_mask) }
+static const struct max77686_irq_data max77686_irqs[] = {
+       DECLARE_IRQ(MAX77686_PMICIRQ_PWRONF,    PMIC_INT1, 1 << 0),
+       DECLARE_IRQ(MAX77686_PMICIRQ_PWRONR,    PMIC_INT1, 1 << 1),
+       DECLARE_IRQ(MAX77686_PMICIRQ_JIGONBF,   PMIC_INT1, 1 << 2),
+       DECLARE_IRQ(MAX77686_PMICIRQ_JIGONBR,   PMIC_INT1, 1 << 3),
+       DECLARE_IRQ(MAX77686_PMICIRQ_ACOKBF,    PMIC_INT1, 1 << 4),
+       DECLARE_IRQ(MAX77686_PMICIRQ_ACOKBR,    PMIC_INT1, 1 << 5),
+       DECLARE_IRQ(MAX77686_PMICIRQ_ONKEY1S,   PMIC_INT1, 1 << 6),
+       DECLARE_IRQ(MAX77686_PMICIRQ_MRSTB,             PMIC_INT1, 1 << 7),
+       DECLARE_IRQ(MAX77686_PMICIRQ_140C,              PMIC_INT2, 1 << 0),
+       DECLARE_IRQ(MAX77686_PMICIRQ_120C,              PMIC_INT2, 1 << 1),
+       DECLARE_IRQ(MAX77686_RTCIRQ_RTC60S,             RTC_INT, 1 << 0),
+       DECLARE_IRQ(MAX77686_RTCIRQ_RTCA1,              RTC_INT, 1 << 1),
+       DECLARE_IRQ(MAX77686_RTCIRQ_RTCA2,              RTC_INT, 1 << 2),
+       DECLARE_IRQ(MAX77686_RTCIRQ_SMPL,               RTC_INT, 1 << 3),
+       DECLARE_IRQ(MAX77686_RTCIRQ_RTC1S,              RTC_INT, 1 << 4),
+       DECLARE_IRQ(MAX77686_RTCIRQ_WTSR,               RTC_INT, 1 << 5),
+};
+
+static void max77686_irq_lock(struct irq_data *data)
+{
+       struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
+
+       if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
+               pr_info("%s\n", __func__);
+
+       mutex_lock(&max77686->irqlock);
+}
+
+static void max77686_irq_sync_unlock(struct irq_data *data)
+{
+       struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
+       int i;
+
+       for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++) {
+               u8 mask_reg = max77686_mask_reg[i];
+               struct regmap *map = max77686_get_regmap(max77686, i);
+
+               if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
+                       pr_debug("%s: mask_reg[%d]=0x%x, cur=0x%x\n",
+                       __func__, i, mask_reg, max77686->irq_masks_cur[i]);
+
+               if (mask_reg == MAX77686_REG_INVALID ||
+                               IS_ERR_OR_NULL(map))
+                       continue;
+
+               max77686->irq_masks_cache[i] = max77686->irq_masks_cur[i];
+
+               regmap_write(map, max77686_mask_reg[i],
+                               max77686->irq_masks_cur[i]);
+       }
+
+       mutex_unlock(&max77686->irqlock);
+}
+
+static const inline struct max77686_irq_data *to_max77686_irq(int irq)
+{
+       struct irq_data *data = irq_get_irq_data(irq);
+       return &max77686_irqs[data->hwirq];
+}
+
+static void max77686_irq_mask(struct irq_data *data)
+{
+       struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
+       const struct max77686_irq_data *irq_data = to_max77686_irq(data->irq);
+
+       max77686->irq_masks_cur[irq_data->group] |= irq_data->mask;
+
+       if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
+               pr_info("%s: group=%d, cur=0x%x\n",
+                       __func__, irq_data->group,
+                       max77686->irq_masks_cur[irq_data->group]);
+}
+
+static void max77686_irq_unmask(struct irq_data *data)
+{
+       struct max77686_dev *max77686 = irq_get_chip_data(data->irq);
+       const struct max77686_irq_data *irq_data = to_max77686_irq(data->irq);
+
+       max77686->irq_masks_cur[irq_data->group] &= ~irq_data->mask;
+
+       if (debug_mask & MAX77686_DEBUG_IRQ_MASK)
+               pr_info("%s: group=%d, cur=0x%x\n",
+                       __func__, irq_data->group,
+                       max77686->irq_masks_cur[irq_data->group]);
+}
+
+static struct irq_chip max77686_irq_chip = {
+       .name                   = "max77686",
+       .irq_bus_lock           = max77686_irq_lock,
+       .irq_bus_sync_unlock    = max77686_irq_sync_unlock,
+       .irq_mask               = max77686_irq_mask,
+       .irq_unmask             = max77686_irq_unmask,
+};
+
+static irqreturn_t max77686_irq_thread(int irq, void *data)
+{
+       struct max77686_dev *max77686 = data;
+       unsigned int irq_reg[MAX77686_IRQ_GROUP_NR] = {};
+       unsigned int irq_src;
+       int ret;
+       int i, cur_irq;
+
+       ret = regmap_read(max77686->regmap,  MAX77686_REG_INTSRC, &irq_src);
+       if (ret < 0) {
+               dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
+                               ret);
+               return IRQ_NONE;
+       }
+
+       if (debug_mask & MAX77686_DEBUG_IRQ_INT)
+               pr_info("%s: irq_src=0x%x\n", __func__, irq_src);
+
+       if (irq_src == MAX77686_IRQSRC_PMIC) {
+               ret = regmap_bulk_read(max77686->regmap,
+                                        MAX77686_REG_INT1, irq_reg, 2);
+               if (ret < 0) {
+                       dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
+                                       ret);
+                       return IRQ_NONE;
+               }
+
+               if (debug_mask & MAX77686_DEBUG_IRQ_INT)
+                       pr_info("%s: int1=0x%x, int2=0x%x\n", __func__,
+                                irq_reg[PMIC_INT1], irq_reg[PMIC_INT2]);
+       }
+
+       if (irq_src & MAX77686_IRQSRC_RTC) {
+               ret = regmap_read(max77686->rtc_regmap,
+                                       MAX77686_RTC_INT, &irq_reg[RTC_INT]);
+               if (ret < 0) {
+                       dev_err(max77686->dev, "Failed to read interrupt source: %d\n",
+                                       ret);
+                       return IRQ_NONE;
+               }
+
+               if (debug_mask & MAX77686_DEBUG_IRQ_INT)
+                       pr_info("%s: rtc int=0x%x\n", __func__,
+                                                        irq_reg[RTC_INT]);
+
+       }
+
+       for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++)
+               irq_reg[i] &= ~max77686->irq_masks_cur[i];
+
+       for (i = 0; i < MAX77686_IRQ_NR; i++) {
+               if (irq_reg[max77686_irqs[i].group] & max77686_irqs[i].mask) {
+                       cur_irq = irq_find_mapping(max77686->irq_domain, i);
+                       if (cur_irq)
+                               handle_nested_irq(cur_irq);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int max77686_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                                       irq_hw_number_t hw)
+{
+       struct max77686_dev *max77686 = d->host_data;
+
+       irq_set_chip_data(irq, max77686);
+       irq_set_chip_and_handler(irq, &max77686_irq_chip, handle_edge_irq);
+       irq_set_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+       set_irq_flags(irq, IRQF_VALID);
+#else
+       irq_set_noprobe(irq);
+#endif
+       return 0;
+}
+
+static struct irq_domain_ops max77686_irq_domain_ops = {
+       .map = max77686_irq_domain_map,
+};
+
+int max77686_irq_init(struct max77686_dev *max77686)
+{
+       struct irq_domain *domain;
+       int i;
+       int ret;
+       int val;
+       struct regmap *map;
+
+       mutex_init(&max77686->irqlock);
+
+       if (max77686->irq_gpio && !max77686->irq) {
+               max77686->irq = gpio_to_irq(max77686->irq_gpio);
+
+               if (debug_mask & MAX77686_DEBUG_IRQ_INT) {
+                       ret = gpio_request(max77686->irq_gpio, "pmic_irq");
+                       if (ret < 0) {
+                               dev_err(max77686->dev,
+                                       "Failed to request gpio %d with ret:"
+                                       "%d\n", max77686->irq_gpio, ret);
+                               return IRQ_NONE;
+                       }
+
+                       gpio_direction_input(max77686->irq_gpio);
+                       val = gpio_get_value(max77686->irq_gpio);
+                       gpio_free(max77686->irq_gpio);
+                       pr_info("%s: gpio_irq=%x\n", __func__, val);
+               }
+       }
+
+       if (!max77686->irq) {
+               dev_err(max77686->dev, "irq is not specified\n");
+               return -ENODEV;
+       }
+
+       /* Mask individual interrupt sources */
+       for (i = 0; i < MAX77686_IRQ_GROUP_NR; i++) {
+               max77686->irq_masks_cur[i] = 0xff;
+               max77686->irq_masks_cache[i] = 0xff;
+               map = max77686_get_regmap(max77686, i);
+
+               if (IS_ERR_OR_NULL(map))
+                       continue;
+               if (max77686_mask_reg[i] == MAX77686_REG_INVALID)
+                       continue;
+
+               regmap_write(map, max77686_mask_reg[i], 0xff);
+       }
+       domain = irq_domain_add_linear(NULL, MAX77686_IRQ_NR,
+                                       &max77686_irq_domain_ops, max77686);
+       if (!domain) {
+               dev_err(max77686->dev, "could not create irq domain\n");
+               return -ENODEV;
+       }
+       max77686->irq_domain = domain;
+
+       ret = request_threaded_irq(max77686->irq, NULL, max77686_irq_thread,
+                                  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                  "max77686-irq", max77686);
+
+       if (ret)
+               dev_err(max77686->dev, "Failed to request IRQ %d: %d\n",
+                       max77686->irq, ret);
+
+
+       if (debug_mask & MAX77686_DEBUG_IRQ_INFO)
+               pr_info("%s-\n", __func__);
+
+       return 0;
+}
+
+void max77686_irq_exit(struct max77686_dev *max77686)
+{
+       if (max77686->irq)
+               free_irq(max77686->irq, max77686);
+}
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c
new file mode 100644 (file)
index 0000000..c03e12b
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * max77686.c - mfd core driver for the Maxim 77686
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Chiwoong Byun <woong.byun@smasung.com>
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max8997.c
+ */
+
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max77686.h>
+#include <linux/mfd/max77686-private.h>
+#include <linux/err.h>
+
+#define I2C_ADDR_RTC   (0x0C >> 1)
+
+static struct mfd_cell max77686_devs[] = {
+       { .name = "max77686-pmic", },
+       { .name = "max77686-rtc", },
+};
+
+static struct regmap_config max77686_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+#ifdef CONFIG_OF
+static struct of_device_id __devinitdata max77686_pmic_dt_match[] = {
+       {.compatible = "maxim,max77686",        .data = 0},
+       {},
+};
+
+static struct max77686_platform_data *max77686_i2c_parse_dt_pdata(struct device
+                                                                 *dev)
+{
+       struct max77686_platform_data *pd;
+
+       pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+       if (!pd) {
+               dev_err(dev, "could not allocate memory for pdata\n");
+               return NULL;
+       }
+
+       dev->platform_data = pd;
+       return pd;
+}
+#else
+static struct max77686_platform_data *max77686_i2c_parse_dt_pdata(struct device
+                                                                 *dev)
+{
+       return 0;
+}
+#endif
+
+static int max77686_i2c_probe(struct i2c_client *i2c,
+                             const struct i2c_device_id *id)
+{
+       struct max77686_dev *max77686 = NULL;
+       struct max77686_platform_data *pdata = i2c->dev.platform_data;
+       unsigned int data;
+       int ret = 0;
+
+       if (i2c->dev.of_node)
+               pdata = max77686_i2c_parse_dt_pdata(&i2c->dev);
+
+       if (!pdata) {
+               ret = -EIO;
+               dev_err(&i2c->dev, "No platform data found.\n");
+               goto err;
+       }
+
+       max77686 = kzalloc(sizeof(struct max77686_dev), GFP_KERNEL);
+       if (max77686 == NULL)
+               return -ENOMEM;
+
+       max77686->regmap = regmap_init_i2c(i2c, &max77686_regmap_config);
+       if (IS_ERR(max77686->regmap)) {
+               ret = PTR_ERR(max77686->regmap);
+               dev_err(max77686->dev, "Failed to allocate register map: %d\n",
+                               ret);
+               kfree(max77686);
+               return ret;
+       }
+
+       i2c_set_clientdata(i2c, max77686);
+       max77686->dev = &i2c->dev;
+       max77686->i2c = i2c;
+       max77686->type = id->driver_data;
+
+       max77686->wakeup = pdata->wakeup;
+       max77686->irq_gpio = pdata->irq_gpio;
+       max77686->irq = i2c->irq;
+
+       if (regmap_read(max77686->regmap,
+                        MAX77686_REG_DEVICE_ID, &data) < 0) {
+               dev_err(max77686->dev,
+                       "device not found on this channel (this is not an error)\n");
+               ret = -ENODEV;
+               goto err;
+       } else
+               dev_info(max77686->dev, "device found\n");
+
+       max77686->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
+       i2c_set_clientdata(max77686->rtc, max77686);
+
+       max77686_irq_init(max77686);
+
+       ret = mfd_add_devices(max77686->dev, -1, max77686_devs,
+                             ARRAY_SIZE(max77686_devs), NULL, 0);
+
+       if (ret < 0)
+               goto err_mfd;
+
+       return ret;
+
+err_mfd:
+       mfd_remove_devices(max77686->dev);
+       i2c_unregister_device(max77686->rtc);
+err:
+       kfree(max77686);
+       return ret;
+}
+
+static int max77686_i2c_remove(struct i2c_client *i2c)
+{
+       struct max77686_dev *max77686 = i2c_get_clientdata(i2c);
+
+       mfd_remove_devices(max77686->dev);
+       i2c_unregister_device(max77686->rtc);
+       kfree(max77686);
+
+       return 0;
+}
+
+static const struct i2c_device_id max77686_i2c_id[] = {
+       { "max77686", TYPE_MAX77686 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max77686_i2c_id);
+
+static struct i2c_driver max77686_i2c_driver = {
+       .driver = {
+                  .name = "max77686",
+                  .owner = THIS_MODULE,
+                  .of_match_table = of_match_ptr(max77686_pmic_dt_match),
+       },
+       .probe = max77686_i2c_probe,
+       .remove = max77686_i2c_remove,
+       .id_table = max77686_i2c_id,
+};
+
+static int __init max77686_i2c_init(void)
+{
+       return i2c_add_driver(&max77686_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(max77686_i2c_init);
+
+static void __exit max77686_i2c_exit(void)
+{
+       i2c_del_driver(&max77686_i2c_driver);
+}
+module_exit(max77686_i2c_exit);
+
+MODULE_DESCRIPTION("MAXIM 77686 multi-function core driver");
+MODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>");
+MODULE_LICENSE("GPL");
index e9e4278722f3af307fdfb53b5413c2d5dc61daf1..a1811cb50ec75fc7c1dffd02aca98f132d7e4810 100644 (file)
@@ -138,8 +138,6 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
 
        max77693->wakeup = pdata->wakeup;
 
-       mutex_init(&max77693->iolock);
-
        if (max77693_read_reg(max77693->regmap,
                                MAX77693_PMIC_REG_PMIC_ID2, &reg_data) < 0) {
                dev_err(max77693->dev, "device not found on this channel\n");
@@ -156,7 +154,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
 
        ret = max77693_irq_init(max77693);
        if (ret < 0)
-               goto err_mfd;
+               goto err_irq;
 
        pm_runtime_set_active(max77693->dev);
 
@@ -170,11 +168,11 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
        return ret;
 
 err_mfd:
+       max77693_irq_exit(max77693);
+err_irq:
        i2c_unregister_device(max77693->muic);
        i2c_unregister_device(max77693->haptic);
 err_regmap:
-       kfree(max77693);
-
        return ret;
 }
 
@@ -183,6 +181,7 @@ static int max77693_i2c_remove(struct i2c_client *i2c)
        struct max77693_dev *max77693 = i2c_get_clientdata(i2c);
 
        mfd_remove_devices(max77693->dev);
+       max77693_irq_exit(max77693);
        i2c_unregister_device(max77693->muic);
        i2c_unregister_device(max77693->haptic);
 
@@ -215,7 +214,7 @@ static int max77693_resume(struct device *dev)
        return max77693_irq_resume(max77693);
 }
 
-const struct dev_pm_ops max77693_pm = {
+static const struct dev_pm_ops max77693_pm = {
        .suspend = max77693_suspend,
        .resume = max77693_resume,
 };
index ca881efedf75a43f7543e19d506702ab1518e0ec..825a7f06d9ba5ade6281810bec19c209187561b2 100644 (file)
@@ -75,9 +75,9 @@ static struct mfd_cell power_devs[] = {
 static struct resource rtc_resources[] = {
        {
                .name   = "max8925-rtc",
-               .start  = MAX8925_RTC_IRQ,
-               .end    = MAX8925_RTC_IRQ_MASK,
-               .flags  = IORESOURCE_IO,
+               .start  = MAX8925_IRQ_RTC_ALARM0,
+               .end    = MAX8925_IRQ_RTC_ALARM0,
+               .flags  = IORESOURCE_IRQ,
        },
 };
 
@@ -598,7 +598,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
 
        ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
                              ARRAY_SIZE(rtc_devs),
-                             &rtc_resources[0], 0);
+                             &rtc_resources[0], chip->irq_base);
        if (ret < 0) {
                dev_err(chip->dev, "Failed to add rtc subdev\n");
                goto out;
index 09274cf7c33bd0bd7d21ca2ee4cd12f78330bcfb..43fa61413e935d5c5ce4a46016df34895ecb2b1d 100644 (file)
@@ -142,7 +142,8 @@ static void max8997_irq_sync_unlock(struct irq_data *data)
 static const inline struct max8997_irq_data *
 irq_to_max8997_irq(struct max8997_dev *max8997, int irq)
 {
-       return &max8997_irqs[irq - max8997->irq_base];
+       struct irq_data *data = irq_get_irq_data(irq);
+       return &max8997_irqs[data->hwirq];
 }
 
 static void max8997_irq_mask(struct irq_data *data)
@@ -182,7 +183,7 @@ static irqreturn_t max8997_irq_thread(int irq, void *data)
        u8 irq_reg[MAX8997_IRQ_GROUP_NR] = {};
        u8 irq_src;
        int ret;
-       int i;
+       int i, cur_irq;
 
        ret = max8997_read_reg(max8997->i2c, MAX8997_REG_INTSRC, &irq_src);
        if (ret < 0) {
@@ -269,8 +270,11 @@ static irqreturn_t max8997_irq_thread(int irq, void *data)
 
        /* Report */
        for (i = 0; i < MAX8997_IRQ_NR; i++) {
-               if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask)
-                       handle_nested_irq(max8997->irq_base + i);
+               if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask) {
+                       cur_irq = irq_find_mapping(max8997->irq_domain, i);
+                       if (cur_irq)
+                               handle_nested_irq(cur_irq);
+               }
        }
 
        return IRQ_HANDLED;
@@ -278,26 +282,40 @@ static irqreturn_t max8997_irq_thread(int irq, void *data)
 
 int max8997_irq_resume(struct max8997_dev *max8997)
 {
-       if (max8997->irq && max8997->irq_base)
-               max8997_irq_thread(max8997->irq_base, max8997);
+       if (max8997->irq && max8997->irq_domain)
+               max8997_irq_thread(0, max8997);
+       return 0;
+}
+
+static int max8997_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                                       irq_hw_number_t hw)
+{
+       struct max8997_dev *max8997 = d->host_data;
+
+       irq_set_chip_data(irq, max8997);
+       irq_set_chip_and_handler(irq, &max8997_irq_chip, handle_edge_irq);
+       irq_set_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+       set_irq_flags(irq, IRQF_VALID);
+#else
+       irq_set_noprobe(irq);
+#endif
        return 0;
 }
 
+static struct irq_domain_ops max8997_irq_domain_ops = {
+       .map = max8997_irq_domain_map,
+};
+
 int max8997_irq_init(struct max8997_dev *max8997)
 {
+       struct irq_domain *domain;
        int i;
-       int cur_irq;
        int ret;
        u8 val;
 
        if (!max8997->irq) {
                dev_warn(max8997->dev, "No interrupt specified.\n");
-               max8997->irq_base = 0;
-               return 0;
-       }
-
-       if (!max8997->irq_base) {
-               dev_err(max8997->dev, "No interrupt base specified.\n");
                return 0;
        }
 
@@ -327,19 +345,13 @@ int max8997_irq_init(struct max8997_dev *max8997)
                                        true : false;
        }
 
-       /* Register with genirq */
-       for (i = 0; i < MAX8997_IRQ_NR; i++) {
-               cur_irq = i + max8997->irq_base;
-               irq_set_chip_data(cur_irq, max8997);
-               irq_set_chip_and_handler(cur_irq, &max8997_irq_chip,
-                               handle_edge_irq);
-               irq_set_nested_thread(cur_irq, 1);
-#ifdef CONFIG_ARM
-               set_irq_flags(cur_irq, IRQF_VALID);
-#else
-               irq_set_noprobe(cur_irq);
-#endif
+       domain = irq_domain_add_linear(NULL, MAX8997_IRQ_NR,
+                                       &max8997_irq_domain_ops, max8997);
+       if (!domain) {
+               dev_err(max8997->dev, "could not create irq domain\n");
+               return -ENODEV;
        }
+       max8997->irq_domain = domain;
 
        ret = request_threaded_irq(max8997->irq, NULL, max8997_irq_thread,
                        IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
index cb83a7ab53e73b9825c4eb527211ab49ccd33a7e..10b629c245b6770d304dde9bf978891c2a5ac800 100644 (file)
@@ -143,7 +143,6 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
        if (!pdata)
                goto err;
 
-       max8997->irq_base = pdata->irq_base;
        max8997->ono = pdata->ono;
 
        mutex_init(&max8997->iolock);
@@ -206,7 +205,7 @@ static const struct i2c_device_id max8997_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
 
-u8 max8997_dumpaddr_pmic[] = {
+static u8 max8997_dumpaddr_pmic[] = {
        MAX8997_REG_INT1MSK,
        MAX8997_REG_INT2MSK,
        MAX8997_REG_INT3MSK,
@@ -331,7 +330,7 @@ u8 max8997_dumpaddr_pmic[] = {
        MAX8997_REG_DVSOKTIMER5,
 };
 
-u8 max8997_dumpaddr_muic[] = {
+static u8 max8997_dumpaddr_muic[] = {
        MAX8997_MUIC_REG_INTMASK1,
        MAX8997_MUIC_REG_INTMASK2,
        MAX8997_MUIC_REG_INTMASK3,
@@ -341,7 +340,7 @@ u8 max8997_dumpaddr_muic[] = {
        MAX8997_MUIC_REG_CONTROL3,
 };
 
-u8 max8997_dumpaddr_haptic[] = {
+static u8 max8997_dumpaddr_haptic[] = {
        MAX8997_HAPTIC_REG_CONF1,
        MAX8997_HAPTIC_REG_CONF2,
        MAX8997_HAPTIC_REG_DRVCONF,
@@ -423,7 +422,7 @@ static int max8997_resume(struct device *dev)
        return max8997_irq_resume(max8997);
 }
 
-const struct dev_pm_ops max8997_pm = {
+static const struct dev_pm_ops max8997_pm = {
        .suspend = max8997_suspend,
        .resume = max8997_resume,
        .freeze = max8997_freeze,
index f0ea3b8b3e4ad979d5e1d5fe53bde83a7392dfd2..b801dc72f041a125fcf9a52e25e6d594ee052d92 100644 (file)
@@ -723,10 +723,6 @@ void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx)
        free_irq(mc13xxx->irq, mc13xxx);
 
        mfd_remove_devices(mc13xxx->dev);
-
-       regmap_exit(mc13xxx->regmap);
-
-       kfree(mc13xxx);
 }
 EXPORT_SYMBOL_GPL(mc13xxx_common_cleanup);
 
index d22501dad6a688c11512f27ca2b0477188b57cf9..9d18dde3cd2aafd690ad85246ad0f78a70014a08 100644 (file)
@@ -53,17 +53,11 @@ static struct regmap_config mc13xxx_regmap_i2c_config = {
 static int mc13xxx_i2c_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
-       const struct of_device_id *of_id;
-       struct i2c_driver *idrv = to_i2c_driver(client->dev.driver);
        struct mc13xxx *mc13xxx;
        struct mc13xxx_platform_data *pdata = dev_get_platdata(&client->dev);
        int ret;
 
-       of_id = of_match_device(mc13xxx_dt_ids, &client->dev);
-       if (of_id)
-               idrv->id_table = (const struct i2c_device_id*) of_id->data;
-
-       mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
+       mc13xxx = devm_kzalloc(&client->dev, sizeof(*mc13xxx), GFP_KERNEL);
        if (!mc13xxx)
                return -ENOMEM;
 
@@ -72,13 +66,13 @@ static int mc13xxx_i2c_probe(struct i2c_client *client,
        mc13xxx->dev = &client->dev;
        mutex_init(&mc13xxx->lock);
 
-       mc13xxx->regmap = regmap_init_i2c(client, &mc13xxx_regmap_i2c_config);
+       mc13xxx->regmap = devm_regmap_init_i2c(client,
+                                              &mc13xxx_regmap_i2c_config);
        if (IS_ERR(mc13xxx->regmap)) {
                ret = PTR_ERR(mc13xxx->regmap);
                dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n",
                                ret);
                dev_set_drvdata(&client->dev, NULL);
-               kfree(mc13xxx);
                return ret;
        }
 
index 03df422feb763ab075ac5fa741ef09b71c066d1d..0bdb43a0aff0756513a06d2184bc16db41fdc88c 100644 (file)
@@ -119,17 +119,11 @@ static struct regmap_bus regmap_mc13xxx_bus = {
 
 static int mc13xxx_spi_probe(struct spi_device *spi)
 {
-       const struct of_device_id *of_id;
-       struct spi_driver *sdrv = to_spi_driver(spi->dev.driver);
        struct mc13xxx *mc13xxx;
        struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
        int ret;
 
-       of_id = of_match_device(mc13xxx_dt_ids, &spi->dev);
-       if (of_id)
-               sdrv->id_table = &mc13xxx_device_id[(enum mc13xxx_id) of_id->data];
-
-       mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
+       mc13xxx = devm_kzalloc(&spi->dev, sizeof(*mc13xxx), GFP_KERNEL);
        if (!mc13xxx)
                return -ENOMEM;
 
@@ -139,15 +133,14 @@ static int mc13xxx_spi_probe(struct spi_device *spi)
        mc13xxx->dev = &spi->dev;
        mutex_init(&mc13xxx->lock);
 
-       mc13xxx->regmap = regmap_init(&spi->dev, &regmap_mc13xxx_bus, &spi->dev,
-                                       &mc13xxx_regmap_spi_config);
-
+       mc13xxx->regmap = devm_regmap_init(&spi->dev, &regmap_mc13xxx_bus,
+                                          &spi->dev,
+                                          &mc13xxx_regmap_spi_config);
        if (IS_ERR(mc13xxx->regmap)) {
                ret = PTR_ERR(mc13xxx->regmap);
                dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n",
                                ret);
                dev_set_drvdata(&spi->dev, NULL);
-               kfree(mc13xxx);
                return ret;
        }
 
index ffc3d48676ae67c5c838700d212310025ec8f2da..0c3a01cde2f7615960fb2c9cc20ba7489bf00fbd 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
 
 int mfd_cell_enable(struct platform_device *pdev)
 {
@@ -76,6 +78,8 @@ static int mfd_add_device(struct device *parent, int id,
 {
        struct resource *res;
        struct platform_device *pdev;
+       struct device_node *np = NULL;
+       struct irq_domain *domain = NULL;
        int ret = -ENOMEM;
        int r;
 
@@ -89,6 +93,16 @@ static int mfd_add_device(struct device *parent, int id,
 
        pdev->dev.parent = parent;
 
+       if (parent->of_node && cell->of_compatible) {
+               for_each_child_of_node(parent->of_node, np) {
+                       if (of_device_is_compatible(np, cell->of_compatible)) {
+                               pdev->dev.of_node = np;
+                               domain = irq_find_host(parent->of_node);
+                               break;
+                       }
+               }
+       }
+
        if (cell->pdata_size) {
                ret = platform_device_add_data(pdev,
                                        cell->platform_data, cell->pdata_size);
@@ -112,10 +126,18 @@ static int mfd_add_device(struct device *parent, int id,
                        res[r].end = mem_base->start +
                                cell->resources[r].end;
                } else if (cell->resources[r].flags & IORESOURCE_IRQ) {
-                       res[r].start = irq_base +
-                               cell->resources[r].start;
-                       res[r].end   = irq_base +
-                               cell->resources[r].end;
+                       if (domain) {
+                               /* Unable to create mappings for IRQ ranges. */
+                               WARN_ON(cell->resources[r].start !=
+                                       cell->resources[r].end);
+                               res[r].start = res[r].end = irq_create_mapping(
+                                       domain, cell->resources[r].start);
+                       } else {
+                               res[r].start = irq_base +
+                                       cell->resources[r].start;
+                               res[r].end   = irq_base +
+                                       cell->resources[r].end;
+                       }
                } else {
                        res[r].parent = cell->resources[r].parent;
                        res[r].start = cell->resources[r].start;
index 29c122bf28ea723e36cafccda86eb09319d595ac..45ce1fb5a54998dee46e4f523c3428e172cba2a4 100644 (file)
@@ -253,8 +253,13 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
                }
 
                pdev->dev.parent = pcf->dev;
-               platform_device_add_data(pdev, &pdata->reg_init_data[i],
-                                       sizeof(pdata->reg_init_data[i]));
+               if (platform_device_add_data(pdev, &pdata->reg_init_data[i],
+                                       sizeof(pdata->reg_init_data[i])) < 0) {
+                       platform_device_put(pdev);
+                       dev_err(pcf->dev, "Out of memory for regulator parameters %d\n",
+                                                                       i);
+                       continue;
+               }
                pcf->regulator_pdev[i] = pdev;
 
                platform_device_add(pdev);
diff --git a/drivers/mfd/s5m-core.c b/drivers/mfd/s5m-core.c
deleted file mode 100644 (file)
index dd17030..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * s5m87xx.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd
- *              http://www.samsung.com
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/pm_runtime.h>
-#include <linux/mutex.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/s5m87xx/s5m-core.h>
-#include <linux/mfd/s5m87xx/s5m-pmic.h>
-#include <linux/mfd/s5m87xx/s5m-rtc.h>
-#include <linux/regmap.h>
-
-static struct mfd_cell s5m8751_devs[] = {
-       {
-               .name = "s5m8751-pmic",
-       }, {
-               .name = "s5m-charger",
-       }, {
-               .name = "s5m8751-codec",
-       },
-};
-
-static struct mfd_cell s5m8763_devs[] = {
-       {
-               .name = "s5m8763-pmic",
-       }, {
-               .name = "s5m-rtc",
-       }, {
-               .name = "s5m-charger",
-       },
-};
-
-static struct mfd_cell s5m8767_devs[] = {
-       {
-               .name = "s5m8767-pmic",
-       }, {
-               .name = "s5m-rtc",
-       },
-};
-
-int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest)
-{
-       return regmap_read(s5m87xx->regmap, reg, dest);
-}
-EXPORT_SYMBOL_GPL(s5m_reg_read);
-
-int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
-{
-       return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);
-}
-EXPORT_SYMBOL_GPL(s5m_bulk_read);
-
-int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value)
-{
-       return regmap_write(s5m87xx->regmap, reg, value);
-}
-EXPORT_SYMBOL_GPL(s5m_reg_write);
-
-int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
-{
-       return regmap_raw_write(s5m87xx->regmap, reg, buf, count);
-}
-EXPORT_SYMBOL_GPL(s5m_bulk_write);
-
-int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask)
-{
-       return regmap_update_bits(s5m87xx->regmap, reg, mask, val);
-}
-EXPORT_SYMBOL_GPL(s5m_reg_update);
-
-static struct regmap_config s5m_regmap_config = {
-       .reg_bits = 8,
-       .val_bits = 8,
-};
-
-static int s5m87xx_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
-{
-       struct s5m_platform_data *pdata = i2c->dev.platform_data;
-       struct s5m87xx_dev *s5m87xx;
-       int ret;
-
-       s5m87xx = devm_kzalloc(&i2c->dev, sizeof(struct s5m87xx_dev),
-                               GFP_KERNEL);
-       if (s5m87xx == NULL)
-               return -ENOMEM;
-
-       i2c_set_clientdata(i2c, s5m87xx);
-       s5m87xx->dev = &i2c->dev;
-       s5m87xx->i2c = i2c;
-       s5m87xx->irq = i2c->irq;
-       s5m87xx->type = id->driver_data;
-
-       if (pdata) {
-               s5m87xx->device_type = pdata->device_type;
-               s5m87xx->ono = pdata->ono;
-               s5m87xx->irq_base = pdata->irq_base;
-               s5m87xx->wakeup = pdata->wakeup;
-       }
-
-       s5m87xx->regmap = devm_regmap_init_i2c(i2c, &s5m_regmap_config);
-       if (IS_ERR(s5m87xx->regmap)) {
-               ret = PTR_ERR(s5m87xx->regmap);
-               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
-                       ret);
-               return ret;
-       }
-
-       s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
-       i2c_set_clientdata(s5m87xx->rtc, s5m87xx);
-
-       if (pdata && pdata->cfg_pmic_irq)
-               pdata->cfg_pmic_irq();
-
-       s5m_irq_init(s5m87xx);
-
-       pm_runtime_set_active(s5m87xx->dev);
-
-       switch (s5m87xx->device_type) {
-       case S5M8751X:
-               ret = mfd_add_devices(s5m87xx->dev, -1, s5m8751_devs,
-                                       ARRAY_SIZE(s5m8751_devs), NULL, 0);
-               break;
-       case S5M8763X:
-               ret = mfd_add_devices(s5m87xx->dev, -1, s5m8763_devs,
-                                       ARRAY_SIZE(s5m8763_devs), NULL, 0);
-               break;
-       case S5M8767X:
-               ret = mfd_add_devices(s5m87xx->dev, -1, s5m8767_devs,
-                                       ARRAY_SIZE(s5m8767_devs), NULL, 0);
-               break;
-       default:
-               /* If this happens the probe function is problem */
-               BUG();
-       }
-
-       if (ret < 0)
-               goto err;
-
-       return ret;
-
-err:
-       mfd_remove_devices(s5m87xx->dev);
-       s5m_irq_exit(s5m87xx);
-       i2c_unregister_device(s5m87xx->rtc);
-       return ret;
-}
-
-static int s5m87xx_i2c_remove(struct i2c_client *i2c)
-{
-       struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
-
-       mfd_remove_devices(s5m87xx->dev);
-       s5m_irq_exit(s5m87xx);
-       i2c_unregister_device(s5m87xx->rtc);
-       return 0;
-}
-
-static const struct i2c_device_id s5m87xx_i2c_id[] = {
-       { "s5m87xx", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, s5m87xx_i2c_id);
-
-static struct i2c_driver s5m87xx_i2c_driver = {
-       .driver = {
-                  .name = "s5m87xx",
-                  .owner = THIS_MODULE,
-       },
-       .probe = s5m87xx_i2c_probe,
-       .remove = s5m87xx_i2c_remove,
-       .id_table = s5m87xx_i2c_id,
-};
-
-static int __init s5m87xx_i2c_init(void)
-{
-       return i2c_add_driver(&s5m87xx_i2c_driver);
-}
-
-subsys_initcall(s5m87xx_i2c_init);
-
-static void __exit s5m87xx_i2c_exit(void)
-{
-       i2c_del_driver(&s5m87xx_i2c_driver);
-}
-module_exit(s5m87xx_i2c_exit);
-
-MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
-MODULE_DESCRIPTION("Core support for the S5M MFD");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/s5m-irq.c b/drivers/mfd/s5m-irq.c
deleted file mode 100644 (file)
index 0236676..0000000
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * s5m-irq.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd
- *              http://www.samsung.com
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
-
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/mfd/s5m87xx/s5m-core.h>
-
-struct s5m_irq_data {
-       int reg;
-       int mask;
-};
-
-static struct s5m_irq_data s5m8767_irqs[] = {
-       [S5M8767_IRQ_PWRR] = {
-               .reg = 1,
-               .mask = S5M8767_IRQ_PWRR_MASK,
-       },
-       [S5M8767_IRQ_PWRF] = {
-               .reg = 1,
-               .mask = S5M8767_IRQ_PWRF_MASK,
-       },
-       [S5M8767_IRQ_PWR1S] = {
-               .reg = 1,
-               .mask = S5M8767_IRQ_PWR1S_MASK,
-       },
-       [S5M8767_IRQ_JIGR] = {
-               .reg = 1,
-               .mask = S5M8767_IRQ_JIGR_MASK,
-       },
-       [S5M8767_IRQ_JIGF] = {
-               .reg = 1,
-               .mask = S5M8767_IRQ_JIGF_MASK,
-       },
-       [S5M8767_IRQ_LOWBAT2] = {
-               .reg = 1,
-               .mask = S5M8767_IRQ_LOWBAT2_MASK,
-       },
-       [S5M8767_IRQ_LOWBAT1] = {
-               .reg = 1,
-               .mask = S5M8767_IRQ_LOWBAT1_MASK,
-       },
-       [S5M8767_IRQ_MRB] = {
-               .reg = 2,
-               .mask = S5M8767_IRQ_MRB_MASK,
-       },
-       [S5M8767_IRQ_DVSOK2] = {
-               .reg = 2,
-               .mask = S5M8767_IRQ_DVSOK2_MASK,
-       },
-       [S5M8767_IRQ_DVSOK3] = {
-               .reg = 2,
-               .mask = S5M8767_IRQ_DVSOK3_MASK,
-       },
-       [S5M8767_IRQ_DVSOK4] = {
-               .reg = 2,
-               .mask = S5M8767_IRQ_DVSOK4_MASK,
-       },
-       [S5M8767_IRQ_RTC60S] = {
-               .reg = 3,
-               .mask = S5M8767_IRQ_RTC60S_MASK,
-       },
-       [S5M8767_IRQ_RTCA1] = {
-               .reg = 3,
-               .mask = S5M8767_IRQ_RTCA1_MASK,
-       },
-       [S5M8767_IRQ_RTCA2] = {
-               .reg = 3,
-               .mask = S5M8767_IRQ_RTCA2_MASK,
-       },
-       [S5M8767_IRQ_SMPL] = {
-               .reg = 3,
-               .mask = S5M8767_IRQ_SMPL_MASK,
-       },
-       [S5M8767_IRQ_RTC1S] = {
-               .reg = 3,
-               .mask = S5M8767_IRQ_RTC1S_MASK,
-       },
-       [S5M8767_IRQ_WTSR] = {
-               .reg = 3,
-               .mask = S5M8767_IRQ_WTSR_MASK,
-       },
-};
-
-static struct s5m_irq_data s5m8763_irqs[] = {
-       [S5M8763_IRQ_DCINF] = {
-               .reg = 1,
-               .mask = S5M8763_IRQ_DCINF_MASK,
-       },
-       [S5M8763_IRQ_DCINR] = {
-               .reg = 1,
-               .mask = S5M8763_IRQ_DCINR_MASK,
-       },
-       [S5M8763_IRQ_JIGF] = {
-               .reg = 1,
-               .mask = S5M8763_IRQ_JIGF_MASK,
-       },
-       [S5M8763_IRQ_JIGR] = {
-               .reg = 1,
-               .mask = S5M8763_IRQ_JIGR_MASK,
-       },
-       [S5M8763_IRQ_PWRONF] = {
-               .reg = 1,
-               .mask = S5M8763_IRQ_PWRONF_MASK,
-       },
-       [S5M8763_IRQ_PWRONR] = {
-               .reg = 1,
-               .mask = S5M8763_IRQ_PWRONR_MASK,
-       },
-       [S5M8763_IRQ_WTSREVNT] = {
-               .reg = 2,
-               .mask = S5M8763_IRQ_WTSREVNT_MASK,
-       },
-       [S5M8763_IRQ_SMPLEVNT] = {
-               .reg = 2,
-               .mask = S5M8763_IRQ_SMPLEVNT_MASK,
-       },
-       [S5M8763_IRQ_ALARM1] = {
-               .reg = 2,
-               .mask = S5M8763_IRQ_ALARM1_MASK,
-       },
-       [S5M8763_IRQ_ALARM0] = {
-               .reg = 2,
-               .mask = S5M8763_IRQ_ALARM0_MASK,
-       },
-       [S5M8763_IRQ_ONKEY1S] = {
-               .reg = 3,
-               .mask = S5M8763_IRQ_ONKEY1S_MASK,
-       },
-       [S5M8763_IRQ_TOPOFFR] = {
-               .reg = 3,
-               .mask = S5M8763_IRQ_TOPOFFR_MASK,
-       },
-       [S5M8763_IRQ_DCINOVPR] = {
-               .reg = 3,
-               .mask = S5M8763_IRQ_DCINOVPR_MASK,
-       },
-       [S5M8763_IRQ_CHGRSTF] = {
-               .reg = 3,
-               .mask = S5M8763_IRQ_CHGRSTF_MASK,
-       },
-       [S5M8763_IRQ_DONER] = {
-               .reg = 3,
-               .mask = S5M8763_IRQ_DONER_MASK,
-       },
-       [S5M8763_IRQ_CHGFAULT] = {
-               .reg = 3,
-               .mask = S5M8763_IRQ_CHGFAULT_MASK,
-       },
-       [S5M8763_IRQ_LOBAT1] = {
-               .reg = 4,
-               .mask = S5M8763_IRQ_LOBAT1_MASK,
-       },
-       [S5M8763_IRQ_LOBAT2] = {
-               .reg = 4,
-               .mask = S5M8763_IRQ_LOBAT2_MASK,
-       },
-};
-
-static inline struct s5m_irq_data *
-irq_to_s5m8767_irq(struct s5m87xx_dev *s5m87xx, int irq)
-{
-       return &s5m8767_irqs[irq - s5m87xx->irq_base];
-}
-
-static void s5m8767_irq_lock(struct irq_data *data)
-{
-       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
-
-       mutex_lock(&s5m87xx->irqlock);
-}
-
-static void s5m8767_irq_sync_unlock(struct irq_data *data)
-{
-       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
-               if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
-                       s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
-                       s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i,
-                                       s5m87xx->irq_masks_cur[i]);
-               }
-       }
-
-       mutex_unlock(&s5m87xx->irqlock);
-}
-
-static void s5m8767_irq_unmask(struct irq_data *data)
-{
-       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
-       struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
-                                                              data->irq);
-
-       s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
-}
-
-static void s5m8767_irq_mask(struct irq_data *data)
-{
-       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
-       struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
-                                                              data->irq);
-
-       s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
-}
-
-static struct irq_chip s5m8767_irq_chip = {
-       .name = "s5m8767",
-       .irq_bus_lock = s5m8767_irq_lock,
-       .irq_bus_sync_unlock = s5m8767_irq_sync_unlock,
-       .irq_mask = s5m8767_irq_mask,
-       .irq_unmask = s5m8767_irq_unmask,
-};
-
-static inline struct s5m_irq_data *
-irq_to_s5m8763_irq(struct s5m87xx_dev *s5m87xx, int irq)
-{
-       return &s5m8763_irqs[irq - s5m87xx->irq_base];
-}
-
-static void s5m8763_irq_lock(struct irq_data *data)
-{
-       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
-
-       mutex_lock(&s5m87xx->irqlock);
-}
-
-static void s5m8763_irq_sync_unlock(struct irq_data *data)
-{
-       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
-               if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
-                       s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
-                       s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i,
-                                       s5m87xx->irq_masks_cur[i]);
-               }
-       }
-
-       mutex_unlock(&s5m87xx->irqlock);
-}
-
-static void s5m8763_irq_unmask(struct irq_data *data)
-{
-       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
-       struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
-                                                              data->irq);
-
-       s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
-}
-
-static void s5m8763_irq_mask(struct irq_data *data)
-{
-       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
-       struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
-                                                              data->irq);
-
-       s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
-}
-
-static struct irq_chip s5m8763_irq_chip = {
-       .name = "s5m8763",
-       .irq_bus_lock = s5m8763_irq_lock,
-       .irq_bus_sync_unlock = s5m8763_irq_sync_unlock,
-       .irq_mask = s5m8763_irq_mask,
-       .irq_unmask = s5m8763_irq_unmask,
-};
-
-
-static irqreturn_t s5m8767_irq_thread(int irq, void *data)
-{
-       struct s5m87xx_dev *s5m87xx = data;
-       u8 irq_reg[NUM_IRQ_REGS-1];
-       int ret;
-       int i;
-
-
-       ret = s5m_bulk_read(s5m87xx, S5M8767_REG_INT1,
-                               NUM_IRQ_REGS - 1, irq_reg);
-       if (ret < 0) {
-               dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
-                               ret);
-               return IRQ_NONE;
-       }
-
-       for (i = 0; i < NUM_IRQ_REGS - 1; i++)
-               irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
-
-       for (i = 0; i < S5M8767_IRQ_NR; i++) {
-               if (irq_reg[s5m8767_irqs[i].reg - 1] & s5m8767_irqs[i].mask)
-                       handle_nested_irq(s5m87xx->irq_base + i);
-       }
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t s5m8763_irq_thread(int irq, void *data)
-{
-       struct s5m87xx_dev *s5m87xx = data;
-       u8 irq_reg[NUM_IRQ_REGS];
-       int ret;
-       int i;
-
-       ret = s5m_bulk_read(s5m87xx, S5M8763_REG_IRQ1,
-                               NUM_IRQ_REGS, irq_reg);
-       if (ret < 0) {
-               dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
-                               ret);
-               return IRQ_NONE;
-       }
-
-       for (i = 0; i < NUM_IRQ_REGS; i++)
-               irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
-
-       for (i = 0; i < S5M8763_IRQ_NR; i++) {
-               if (irq_reg[s5m8763_irqs[i].reg - 1] & s5m8763_irqs[i].mask)
-                       handle_nested_irq(s5m87xx->irq_base + i);
-       }
-
-       return IRQ_HANDLED;
-}
-
-int s5m_irq_resume(struct s5m87xx_dev *s5m87xx)
-{
-       if (s5m87xx->irq && s5m87xx->irq_base){
-               switch (s5m87xx->device_type) {
-               case S5M8763X:
-                       s5m8763_irq_thread(s5m87xx->irq_base, s5m87xx);
-                       break;
-               case S5M8767X:
-                       s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
-                       break;
-               default:
-                       dev_err(s5m87xx->dev,
-                               "Unknown device type %d\n",
-                               s5m87xx->device_type);
-                       return -EINVAL;
-
-               }
-       }
-       return 0;
-}
-
-int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
-{
-       int i;
-       int cur_irq;
-       int ret = 0;
-       int type = s5m87xx->device_type;
-
-       if (!s5m87xx->irq) {
-               dev_warn(s5m87xx->dev,
-                        "No interrupt specified, no interrupts\n");
-               s5m87xx->irq_base = 0;
-               return 0;
-       }
-
-       if (!s5m87xx->irq_base) {
-               dev_err(s5m87xx->dev,
-                       "No interrupt base specified, no interrupts\n");
-               return 0;
-       }
-
-       mutex_init(&s5m87xx->irqlock);
-
-       switch (type) {
-       case S5M8763X:
-               for (i = 0; i < NUM_IRQ_REGS; i++) {
-                       s5m87xx->irq_masks_cur[i] = 0xff;
-                       s5m87xx->irq_masks_cache[i] = 0xff;
-                       s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i,
-                                               0xff);
-               }
-
-               s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM1, 0xff);
-               s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM2, 0xff);
-
-               for (i = 0; i < S5M8763_IRQ_NR; i++) {
-                       cur_irq = i + s5m87xx->irq_base;
-                       irq_set_chip_data(cur_irq, s5m87xx);
-                       irq_set_chip_and_handler(cur_irq, &s5m8763_irq_chip,
-                                                handle_edge_irq);
-                       irq_set_nested_thread(cur_irq, 1);
-#ifdef CONFIG_ARM
-                       set_irq_flags(cur_irq, IRQF_VALID);
-#else
-                       irq_set_noprobe(cur_irq);
-#endif
-               }
-
-               ret = request_threaded_irq(s5m87xx->irq, NULL,
-                                       s5m8763_irq_thread,
-                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                                       "s5m87xx-irq", s5m87xx);
-               if (ret) {
-                       dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
-                               s5m87xx->irq, ret);
-                       return ret;
-               }
-               break;
-       case S5M8767X:
-               for (i = 0; i < NUM_IRQ_REGS - 1; i++) {
-                       s5m87xx->irq_masks_cur[i] = 0xff;
-                       s5m87xx->irq_masks_cache[i] = 0xff;
-                       s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i,
-                                               0xff);
-               }
-               for (i = 0; i < S5M8767_IRQ_NR; i++) {
-                       cur_irq = i + s5m87xx->irq_base;
-                       irq_set_chip_data(cur_irq, s5m87xx);
-                       if (ret) {
-                               dev_err(s5m87xx->dev,
-                                       "Failed to irq_set_chip_data %d: %d\n",
-                                       s5m87xx->irq, ret);
-                               return ret;
-                       }
-
-                       irq_set_chip_and_handler(cur_irq, &s5m8767_irq_chip,
-                                                handle_edge_irq);
-                       irq_set_nested_thread(cur_irq, 1);
-#ifdef CONFIG_ARM
-                       set_irq_flags(cur_irq, IRQF_VALID);
-#else
-                       irq_set_noprobe(cur_irq);
-#endif
-               }
-
-               ret = request_threaded_irq(s5m87xx->irq, NULL,
-                                          s5m8767_irq_thread,
-                                          IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                                          "s5m87xx-irq", s5m87xx);
-               if (ret) {
-                       dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
-                               s5m87xx->irq, ret);
-                       return ret;
-               }
-               break;
-       default:
-               dev_err(s5m87xx->dev,
-                       "Unknown device type %d\n", s5m87xx->device_type);
-               return -EINVAL;
-       }
-
-       if (!s5m87xx->ono)
-               return 0;
-
-       switch (type) {
-       case S5M8763X:
-               ret = request_threaded_irq(s5m87xx->ono, NULL,
-                                               s5m8763_irq_thread,
-                                               IRQF_TRIGGER_FALLING |
-                                               IRQF_TRIGGER_RISING |
-                                               IRQF_ONESHOT, "s5m87xx-ono",
-                                               s5m87xx);
-               break;
-       case S5M8767X:
-               ret = request_threaded_irq(s5m87xx->ono, NULL,
-                                       s5m8767_irq_thread,
-                                       IRQF_TRIGGER_FALLING |
-                                       IRQF_TRIGGER_RISING |
-                                       IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       if (ret) {
-               dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
-                       s5m87xx->ono, ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-void s5m_irq_exit(struct s5m87xx_dev *s5m87xx)
-{
-       if (s5m87xx->ono)
-               free_irq(s5m87xx->ono, s5m87xx);
-
-       if (s5m87xx->irq)
-               free_irq(s5m87xx->irq, s5m87xx);
-}
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
new file mode 100644 (file)
index 0000000..2988efd
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * sec-core.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/samsung/core.h>
+#include <linux/mfd/samsung/irq.h>
+#include <linux/mfd/samsung/rtc.h>
+#include <linux/regmap.h>
+
+static struct mfd_cell s5m8751_devs[] = {
+       {
+               .name = "s5m8751-pmic",
+       }, {
+               .name = "s5m-charger",
+       }, {
+               .name = "s5m8751-codec",
+       },
+};
+
+static struct mfd_cell s5m8763_devs[] = {
+       {
+               .name = "s5m8763-pmic",
+       }, {
+               .name = "s5m-rtc",
+       }, {
+               .name = "s5m-charger",
+       },
+};
+
+static struct mfd_cell s5m8767_devs[] = {
+       {
+               .name = "s5m8767-pmic",
+       }, {
+               .name = "s5m-rtc",
+       },
+};
+
+static struct mfd_cell s2mps11_devs[] = {
+       {
+               .name = "s2mps11-pmic",
+       },
+};
+
+int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest)
+{
+       return regmap_read(sec_pmic->regmap, reg, dest);
+}
+EXPORT_SYMBOL_GPL(sec_reg_read);
+
+int sec_bulk_read(struct sec_pmic_dev *sec_pmic, u8 reg, int count, u8 *buf)
+{
+       return regmap_bulk_read(sec_pmic->regmap, reg, buf, count);
+}
+EXPORT_SYMBOL_GPL(sec_bulk_read);
+
+int sec_reg_write(struct sec_pmic_dev *sec_pmic, u8 reg, u8 value)
+{
+       return regmap_write(sec_pmic->regmap, reg, value);
+}
+EXPORT_SYMBOL_GPL(sec_reg_write);
+
+int sec_bulk_write(struct sec_pmic_dev *sec_pmic, u8 reg, int count, u8 *buf)
+{
+       return regmap_raw_write(sec_pmic->regmap, reg, buf, count);
+}
+EXPORT_SYMBOL_GPL(sec_bulk_write);
+
+int sec_reg_update(struct sec_pmic_dev *sec_pmic, u8 reg, u8 val, u8 mask)
+{
+       return regmap_update_bits(sec_pmic->regmap, reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(sec_reg_update);
+
+static struct regmap_config sec_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int sec_pmic_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct sec_platform_data *pdata = i2c->dev.platform_data;
+       struct sec_pmic_dev *sec_pmic;
+       int ret;
+
+       sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev),
+                               GFP_KERNEL);
+       if (sec_pmic == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, sec_pmic);
+       sec_pmic->dev = &i2c->dev;
+       sec_pmic->i2c = i2c;
+       sec_pmic->irq = i2c->irq;
+       sec_pmic->type = id->driver_data;
+
+       if (pdata) {
+               sec_pmic->device_type = pdata->device_type;
+               sec_pmic->ono = pdata->ono;
+               sec_pmic->irq_base = pdata->irq_base;
+               sec_pmic->wakeup = pdata->wakeup;
+       }
+
+       sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config);
+       if (IS_ERR(sec_pmic->regmap)) {
+               ret = PTR_ERR(sec_pmic->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
+       i2c_set_clientdata(sec_pmic->rtc, sec_pmic);
+
+       if (pdata && pdata->cfg_pmic_irq)
+               pdata->cfg_pmic_irq();
+
+       sec_irq_init(sec_pmic);
+
+       pm_runtime_set_active(sec_pmic->dev);
+
+       switch (sec_pmic->device_type) {
+       case S5M8751X:
+               ret = mfd_add_devices(sec_pmic->dev, -1, s5m8751_devs,
+                                       ARRAY_SIZE(s5m8751_devs), NULL, 0);
+               break;
+       case S5M8763X:
+               ret = mfd_add_devices(sec_pmic->dev, -1, s5m8763_devs,
+                                       ARRAY_SIZE(s5m8763_devs), NULL, 0);
+               break;
+       case S5M8767X:
+               ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs,
+                                       ARRAY_SIZE(s5m8767_devs), NULL, 0);
+               break;
+       case S2MPS11X:
+               ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs,
+                                       ARRAY_SIZE(s2mps11_devs), NULL, 0);
+               break;
+       default:
+               /* If this happens the probe function is problem */
+               BUG();
+       }
+
+       if (ret < 0)
+               goto err;
+
+       return ret;
+
+err:
+       mfd_remove_devices(sec_pmic->dev);
+       sec_irq_exit(sec_pmic);
+       i2c_unregister_device(sec_pmic->rtc);
+       return ret;
+}
+
+static int sec_pmic_remove(struct i2c_client *i2c)
+{
+       struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
+
+       mfd_remove_devices(sec_pmic->dev);
+       sec_irq_exit(sec_pmic);
+       i2c_unregister_device(sec_pmic->rtc);
+       return 0;
+}
+
+static const struct i2c_device_id sec_pmic_id[] = {
+       { "sec_pmic", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, sec_pmic_id);
+
+static struct i2c_driver sec_pmic_driver = {
+       .driver = {
+                  .name = "sec_pmic",
+                  .owner = THIS_MODULE,
+       },
+       .probe = sec_pmic_probe,
+       .remove = sec_pmic_remove,
+       .id_table = sec_pmic_id,
+};
+
+static int __init sec_pmic_init(void)
+{
+       return i2c_add_driver(&sec_pmic_driver);
+}
+
+subsys_initcall(sec_pmic_init);
+
+static void __exit sec_pmic_exit(void)
+{
+       i2c_del_driver(&sec_pmic_driver);
+}
+module_exit(sec_pmic_exit);
+
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_DESCRIPTION("Core support for the S5M MFD");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c
new file mode 100644 (file)
index 0000000..c901fa5
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * sec-irq.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/samsung/core.h>
+#include <linux/mfd/samsung/irq.h>
+#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s5m8763.h>
+#include <linux/mfd/samsung/s5m8767.h>
+
+static struct regmap_irq s2mps11_irqs[] = {
+       [S2MPS11_IRQ_PWRONF] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_PWRONF_MASK,
+       },
+       [S2MPS11_IRQ_PWRONR] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_PWRONR_MASK,
+       },
+       [S2MPS11_IRQ_JIGONBF] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_JIGONBF_MASK,
+       },
+       [S2MPS11_IRQ_JIGONBR] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_JIGONBR_MASK,
+       },
+       [S2MPS11_IRQ_ACOKBF] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_ACOKBF_MASK,
+       },
+       [S2MPS11_IRQ_ACOKBR] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_ACOKBR_MASK,
+       },
+       [S2MPS11_IRQ_PWRON1S] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_PWRON1S_MASK,
+       },
+       [S2MPS11_IRQ_MRB] = {
+               .reg_offset = 1,
+               .mask = S2MPS11_IRQ_MRB_MASK,
+       },
+       [S2MPS11_IRQ_RTC60S] = {
+               .reg_offset = 2,
+               .mask = S2MPS11_IRQ_RTC60S_MASK,
+       },
+       [S2MPS11_IRQ_RTCA1] = {
+               .reg_offset = 2,
+               .mask = S2MPS11_IRQ_RTCA1_MASK,
+       },
+       [S2MPS11_IRQ_RTCA2] = {
+               .reg_offset = 2,
+               .mask = S2MPS11_IRQ_RTCA2_MASK,
+       },
+       [S2MPS11_IRQ_SMPL] = {
+               .reg_offset = 2,
+               .mask = S2MPS11_IRQ_SMPL_MASK,
+       },
+       [S2MPS11_IRQ_RTC1S] = {
+               .reg_offset = 2,
+               .mask = S2MPS11_IRQ_RTC1S_MASK,
+       },
+       [S2MPS11_IRQ_WTSR] = {
+               .reg_offset = 2,
+               .mask = S2MPS11_IRQ_WTSR_MASK,
+       },
+       [S2MPS11_IRQ_INT120C] = {
+               .reg_offset = 3,
+               .mask = S2MPS11_IRQ_INT120C_MASK,
+       },
+       [S2MPS11_IRQ_INT140C] = {
+               .reg_offset = 3,
+               .mask = S2MPS11_IRQ_INT140C_MASK,
+       },
+};
+
+
+static struct regmap_irq s5m8767_irqs[] = {
+       [S5M8767_IRQ_PWRR] = {
+               .reg_offset = 1,
+               .mask = S5M8767_IRQ_PWRR_MASK,
+       },
+       [S5M8767_IRQ_PWRF] = {
+               .reg_offset = 1,
+               .mask = S5M8767_IRQ_PWRF_MASK,
+       },
+       [S5M8767_IRQ_PWR1S] = {
+               .reg_offset = 1,
+               .mask = S5M8767_IRQ_PWR1S_MASK,
+       },
+       [S5M8767_IRQ_JIGR] = {
+               .reg_offset = 1,
+               .mask = S5M8767_IRQ_JIGR_MASK,
+       },
+       [S5M8767_IRQ_JIGF] = {
+               .reg_offset = 1,
+               .mask = S5M8767_IRQ_JIGF_MASK,
+       },
+       [S5M8767_IRQ_LOWBAT2] = {
+               .reg_offset = 1,
+               .mask = S5M8767_IRQ_LOWBAT2_MASK,
+       },
+       [S5M8767_IRQ_LOWBAT1] = {
+               .reg_offset = 1,
+               .mask = S5M8767_IRQ_LOWBAT1_MASK,
+       },
+       [S5M8767_IRQ_MRB] = {
+               .reg_offset = 2,
+               .mask = S5M8767_IRQ_MRB_MASK,
+       },
+       [S5M8767_IRQ_DVSOK2] = {
+               .reg_offset = 2,
+               .mask = S5M8767_IRQ_DVSOK2_MASK,
+       },
+       [S5M8767_IRQ_DVSOK3] = {
+               .reg_offset = 2,
+               .mask = S5M8767_IRQ_DVSOK3_MASK,
+       },
+       [S5M8767_IRQ_DVSOK4] = {
+               .reg_offset = 2,
+               .mask = S5M8767_IRQ_DVSOK4_MASK,
+       },
+       [S5M8767_IRQ_RTC60S] = {
+               .reg_offset = 3,
+               .mask = S5M8767_IRQ_RTC60S_MASK,
+       },
+       [S5M8767_IRQ_RTCA1] = {
+               .reg_offset = 3,
+               .mask = S5M8767_IRQ_RTCA1_MASK,
+       },
+       [S5M8767_IRQ_RTCA2] = {
+               .reg_offset = 3,
+               .mask = S5M8767_IRQ_RTCA2_MASK,
+       },
+       [S5M8767_IRQ_SMPL] = {
+               .reg_offset = 3,
+               .mask = S5M8767_IRQ_SMPL_MASK,
+       },
+       [S5M8767_IRQ_RTC1S] = {
+               .reg_offset = 3,
+               .mask = S5M8767_IRQ_RTC1S_MASK,
+       },
+       [S5M8767_IRQ_WTSR] = {
+               .reg_offset = 3,
+               .mask = S5M8767_IRQ_WTSR_MASK,
+       },
+};
+
+static struct regmap_irq s5m8763_irqs[] = {
+       [S5M8763_IRQ_DCINF] = {
+               .reg_offset = 1,
+               .mask = S5M8763_IRQ_DCINF_MASK,
+       },
+       [S5M8763_IRQ_DCINR] = {
+               .reg_offset = 1,
+               .mask = S5M8763_IRQ_DCINR_MASK,
+       },
+       [S5M8763_IRQ_JIGF] = {
+               .reg_offset = 1,
+               .mask = S5M8763_IRQ_JIGF_MASK,
+       },
+       [S5M8763_IRQ_JIGR] = {
+               .reg_offset = 1,
+               .mask = S5M8763_IRQ_JIGR_MASK,
+       },
+       [S5M8763_IRQ_PWRONF] = {
+               .reg_offset = 1,
+               .mask = S5M8763_IRQ_PWRONF_MASK,
+       },
+       [S5M8763_IRQ_PWRONR] = {
+               .reg_offset = 1,
+               .mask = S5M8763_IRQ_PWRONR_MASK,
+       },
+       [S5M8763_IRQ_WTSREVNT] = {
+               .reg_offset = 2,
+               .mask = S5M8763_IRQ_WTSREVNT_MASK,
+       },
+       [S5M8763_IRQ_SMPLEVNT] = {
+               .reg_offset = 2,
+               .mask = S5M8763_IRQ_SMPLEVNT_MASK,
+       },
+       [S5M8763_IRQ_ALARM1] = {
+               .reg_offset = 2,
+               .mask = S5M8763_IRQ_ALARM1_MASK,
+       },
+       [S5M8763_IRQ_ALARM0] = {
+               .reg_offset = 2,
+               .mask = S5M8763_IRQ_ALARM0_MASK,
+       },
+       [S5M8763_IRQ_ONKEY1S] = {
+               .reg_offset = 3,
+               .mask = S5M8763_IRQ_ONKEY1S_MASK,
+       },
+       [S5M8763_IRQ_TOPOFFR] = {
+               .reg_offset = 3,
+               .mask = S5M8763_IRQ_TOPOFFR_MASK,
+       },
+       [S5M8763_IRQ_DCINOVPR] = {
+               .reg_offset = 3,
+               .mask = S5M8763_IRQ_DCINOVPR_MASK,
+       },
+       [S5M8763_IRQ_CHGRSTF] = {
+               .reg_offset = 3,
+               .mask = S5M8763_IRQ_CHGRSTF_MASK,
+       },
+       [S5M8763_IRQ_DONER] = {
+               .reg_offset = 3,
+               .mask = S5M8763_IRQ_DONER_MASK,
+       },
+       [S5M8763_IRQ_CHGFAULT] = {
+               .reg_offset = 3,
+               .mask = S5M8763_IRQ_CHGFAULT_MASK,
+       },
+       [S5M8763_IRQ_LOBAT1] = {
+               .reg_offset = 4,
+               .mask = S5M8763_IRQ_LOBAT1_MASK,
+       },
+       [S5M8763_IRQ_LOBAT2] = {
+               .reg_offset = 4,
+               .mask = S5M8763_IRQ_LOBAT2_MASK,
+       },
+};
+
+static struct regmap_irq_chip s2mps11_irq_chip = {
+       .name = "s2mps11",
+       .irqs = s2mps11_irqs,
+       .num_irqs = ARRAY_SIZE(s2mps11_irqs),
+       .num_regs = 3,
+       .status_base = S2MPS11_REG_INT1,
+       .mask_base = S2MPS11_REG_INT1M,
+       .ack_base = S2MPS11_REG_INT1,
+};
+
+static struct regmap_irq_chip s5m8767_irq_chip = {
+       .name = "s5m8767",
+       .irqs = s5m8767_irqs,
+       .num_irqs = ARRAY_SIZE(s5m8767_irqs),
+       .num_regs = 3,
+       .status_base = S5M8767_REG_INT1,
+       .mask_base = S5M8767_REG_INT1M,
+       .ack_base = S5M8767_REG_INT1,
+};
+
+static struct regmap_irq_chip s5m8763_irq_chip = {
+       .name = "s5m8763",
+       .irqs = s5m8763_irqs,
+       .num_irqs = ARRAY_SIZE(s5m8763_irqs),
+       .num_regs = 4,
+       .status_base = S5M8763_REG_IRQ1,
+       .mask_base = S5M8763_REG_IRQM1,
+       .ack_base = S5M8763_REG_IRQ1,
+};
+
+int sec_irq_init(struct sec_pmic_dev *sec_pmic)
+{
+       int ret = 0;
+       int type = sec_pmic->device_type;
+
+       if (!sec_pmic->irq) {
+               dev_warn(sec_pmic->dev,
+                        "No interrupt specified, no interrupts\n");
+               sec_pmic->irq_base = 0;
+               return 0;
+       }
+
+       switch (type) {
+       case S5M8763X:
+               ret = regmap_add_irq_chip(sec_pmic->regmap, sec_pmic->irq,
+                                 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                 sec_pmic->irq_base, &s5m8763_irq_chip,
+                                 &sec_pmic->irq_data);
+               break;
+       case S5M8767X:
+               ret = regmap_add_irq_chip(sec_pmic->regmap, sec_pmic->irq,
+                                 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                 sec_pmic->irq_base, &s5m8767_irq_chip,
+                                 &sec_pmic->irq_data);
+               break;
+       case S2MPS11X:
+               ret = regmap_add_irq_chip(sec_pmic->regmap, sec_pmic->irq,
+                                 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                 sec_pmic->irq_base, &s2mps11_irq_chip,
+                                 &sec_pmic->irq_data);
+               break;
+       default:
+               dev_err(sec_pmic->dev, "Unknown device type %d\n",
+                       sec_pmic->device_type);
+               return -EINVAL;
+       }
+
+       if (ret != 0) {
+               dev_err(sec_pmic->dev, "Failed to register IRQ chip: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+void sec_irq_exit(struct sec_pmic_dev *sec_pmic)
+{
+       regmap_del_irq_chip(sec_pmic->irq, sec_pmic->irq_data);
+}
index de979742c6fc1049cf49f858870034f3885eeb05..048bf0532a095014e03358b01af1f4cd58585b97 100644 (file)
@@ -357,7 +357,7 @@ static int __devexit tc3589x_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int tc3589x_suspend(struct device *dev)
 {
        struct tc3589x *tc3589x = dev_get_drvdata(dev);
@@ -385,11 +385,10 @@ static int tc3589x_resume(struct device *dev)
 
        return ret;
 }
-
-static const SIMPLE_DEV_PM_OPS(tc3589x_dev_pm_ops, tc3589x_suspend,
-                                               tc3589x_resume);
 #endif
 
+static SIMPLE_DEV_PM_OPS(tc3589x_dev_pm_ops, tc3589x_suspend, tc3589x_resume);
+
 static const struct i2c_device_id tc3589x_id[] = {
        { "tc3589x", 24 },
        { }
@@ -399,9 +398,7 @@ MODULE_DEVICE_TABLE(i2c, tc3589x_id);
 static struct i2c_driver tc3589x_driver = {
        .driver.name    = "tc3589x",
        .driver.owner   = THIS_MODULE,
-#ifdef CONFIG_PM
        .driver.pm      = &tc3589x_dev_pm_ops,
-#endif
        .probe          = tc3589x_probe,
        .remove         = __devexit_p(tc3589x_remove),
        .id_table       = tc3589x_id,
index 0ba26fb12cf532f948fefa1e4df6599ce7db347b..a447f4ec11fb757ee38755aa44da467f83229d1f 100644 (file)
@@ -83,7 +83,7 @@ timberdale_xiic_platform_data = {
 
 static __devinitdata struct ocores_i2c_platform_data
 timberdale_ocores_platform_data = {
-       .regstep = 4,
+       .reg_shift = 2,
        .clock_khz = 62500,
        .devices = timberdale_i2c_board_info,
        .num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
index 396b9d1b6bd68bc80ee0120693949461688b8b9f..80e24f4b47bffce67679b7e637627e9e7c769466 100644 (file)
@@ -71,10 +71,10 @@ static const struct tps65090_irq_data tps65090_irqs[] = {
 
 static struct mfd_cell tps65090s[] = {
        {
-               .name = "tps65910-pmic",
+               .name = "tps65090-pmic",
        },
        {
-               .name = "tps65910-regulator",
+               .name = "tps65090-regulator",
        },
 };
 
index c84b5506d5fbd06ee82d12b476abc6239ae4508f..353c34812120fc46e37140c0b6a04babdd5cb080 100644 (file)
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/gpio.h>
+#include <linux/err.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/regulator/of_regulator.h>
 
 #include <linux/mfd/core.h>
 #include <linux/mfd/tps6586x.h>
 
-/* GPIO control registers */
-#define TPS6586X_GPIOSET1      0x5d
-#define TPS6586X_GPIOSET2      0x5e
-
 /* interrupt control registers */
 #define TPS6586X_INT_ACK1      0xb5
 #define TPS6586X_INT_ACK2      0xb6
@@ -48,6 +45,9 @@
 /* device id */
 #define TPS6586X_VERSIONCRC    0xcd
 
+/* Maximum register */
+#define TPS6586X_MAX_REGISTER  (TPS6586X_VERSIONCRC + 1)
+
 struct tps6586x_irq_data {
        u8      mask_reg;
        u8      mask_mask;
@@ -89,226 +89,96 @@ static const struct tps6586x_irq_data tps6586x_irqs[] = {
        [TPS6586X_INT_RTC_ALM2] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 1),
 };
 
+static struct mfd_cell tps6586x_cell[] = {
+       {
+               .name = "tps6586x-gpio",
+       },
+       {
+               .name = "tps6586x-rtc",
+       },
+       {
+               .name = "tps6586x-onkey",
+       },
+};
+
 struct tps6586x {
-       struct mutex            lock;
        struct device           *dev;
        struct i2c_client       *client;
+       struct regmap           *regmap;
 
-       struct gpio_chip        gpio;
        struct irq_chip         irq_chip;
        struct mutex            irq_lock;
        int                     irq_base;
        u32                     irq_en;
-       u8                      mask_cache[5];
        u8                      mask_reg[5];
 };
 
-static inline int __tps6586x_read(struct i2c_client *client,
-                                 int reg, uint8_t *val)
-{
-       int ret;
-
-       ret = i2c_smbus_read_byte_data(client, reg);
-       if (ret < 0) {
-               dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
-               return ret;
-       }
-
-       *val = (uint8_t)ret;
-
-       return 0;
-}
-
-static inline int __tps6586x_reads(struct i2c_client *client, int reg,
-                                  int len, uint8_t *val)
-{
-       int ret;
-
-       ret = i2c_smbus_read_i2c_block_data(client, reg, len, val);
-       if (ret < 0) {
-               dev_err(&client->dev, "failed reading from 0x%02x\n", reg);
-               return ret;
-       }
-
-       return 0;
-}
-
-static inline int __tps6586x_write(struct i2c_client *client,
-                                int reg, uint8_t val)
+static inline struct tps6586x *dev_to_tps6586x(struct device *dev)
 {
-       int ret;
-
-       ret = i2c_smbus_write_byte_data(client, reg, val);
-       if (ret < 0) {
-               dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
-                               val, reg);
-               return ret;
-       }
-
-       return 0;
-}
-
-static inline int __tps6586x_writes(struct i2c_client *client, int reg,
-                                 int len, uint8_t *val)
-{
-       int ret, i;
-
-       for (i = 0; i < len; i++) {
-               ret = __tps6586x_write(client, reg + i, *(val + i));
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
+       return i2c_get_clientdata(to_i2c_client(dev));
 }
 
 int tps6586x_write(struct device *dev, int reg, uint8_t val)
 {
-       return __tps6586x_write(to_i2c_client(dev), reg, val);
+       struct tps6586x *tps6586x = dev_to_tps6586x(dev);
+
+       return regmap_write(tps6586x->regmap, reg, val);
 }
 EXPORT_SYMBOL_GPL(tps6586x_write);
 
 int tps6586x_writes(struct device *dev, int reg, int len, uint8_t *val)
 {
-       return __tps6586x_writes(to_i2c_client(dev), reg, len, val);
+       struct tps6586x *tps6586x = dev_to_tps6586x(dev);
+
+       return regmap_bulk_write(tps6586x->regmap, reg, val, len);
 }
 EXPORT_SYMBOL_GPL(tps6586x_writes);
 
 int tps6586x_read(struct device *dev, int reg, uint8_t *val)
 {
-       return __tps6586x_read(to_i2c_client(dev), reg, val);
+       struct tps6586x *tps6586x = dev_to_tps6586x(dev);
+       unsigned int rval;
+       int ret;
+
+       ret = regmap_read(tps6586x->regmap, reg, &rval);
+       if (!ret)
+               *val = rval;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(tps6586x_read);
 
 int tps6586x_reads(struct device *dev, int reg, int len, uint8_t *val)
 {
-       return __tps6586x_reads(to_i2c_client(dev), reg, len, val);
+       struct tps6586x *tps6586x = dev_to_tps6586x(dev);
+
+       return regmap_bulk_read(tps6586x->regmap, reg, val, len);
 }
 EXPORT_SYMBOL_GPL(tps6586x_reads);
 
 int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
 {
-       struct tps6586x *tps6586x = dev_get_drvdata(dev);
-       uint8_t reg_val;
-       int ret = 0;
-
-       mutex_lock(&tps6586x->lock);
+       struct tps6586x *tps6586x = dev_to_tps6586x(dev);
 
-       ret = __tps6586x_read(to_i2c_client(dev), reg, &reg_val);
-       if (ret)
-               goto out;
-
-       if ((reg_val & bit_mask) != bit_mask) {
-               reg_val |= bit_mask;
-               ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val);
-       }
-out:
-       mutex_unlock(&tps6586x->lock);
-       return ret;
+       return regmap_update_bits(tps6586x->regmap, reg, bit_mask, bit_mask);
 }
 EXPORT_SYMBOL_GPL(tps6586x_set_bits);
 
 int tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
 {
-       struct tps6586x *tps6586x = dev_get_drvdata(dev);
-       uint8_t reg_val;
-       int ret = 0;
-
-       mutex_lock(&tps6586x->lock);
+       struct tps6586x *tps6586x = dev_to_tps6586x(dev);
 
-       ret = __tps6586x_read(to_i2c_client(dev), reg, &reg_val);
-       if (ret)
-               goto out;
-
-       if (reg_val & bit_mask) {
-               reg_val &= ~bit_mask;
-               ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val);
-       }
-out:
-       mutex_unlock(&tps6586x->lock);
-       return ret;
+       return regmap_update_bits(tps6586x->regmap, reg, bit_mask, 0);
 }
 EXPORT_SYMBOL_GPL(tps6586x_clr_bits);
 
 int tps6586x_update(struct device *dev, int reg, uint8_t val, uint8_t mask)
 {
-       struct tps6586x *tps6586x = dev_get_drvdata(dev);
-       uint8_t reg_val;
-       int ret = 0;
-
-       mutex_lock(&tps6586x->lock);
+       struct tps6586x *tps6586x = dev_to_tps6586x(dev);
 
-       ret = __tps6586x_read(tps6586x->client, reg, &reg_val);
-       if (ret)
-               goto out;
-
-       if ((reg_val & mask) != val) {
-               reg_val = (reg_val & ~mask) | val;
-               ret = __tps6586x_write(tps6586x->client, reg, reg_val);
-       }
-out:
-       mutex_unlock(&tps6586x->lock);
-       return ret;
+       return regmap_update_bits(tps6586x->regmap, reg, mask, val);
 }
 EXPORT_SYMBOL_GPL(tps6586x_update);
 
-static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset)
-{
-       struct tps6586x *tps6586x = container_of(gc, struct tps6586x, gpio);
-       uint8_t val;
-       int ret;
-
-       ret = __tps6586x_read(tps6586x->client, TPS6586X_GPIOSET2, &val);
-       if (ret)
-               return ret;
-
-       return !!(val & (1 << offset));
-}
-
-
-static void tps6586x_gpio_set(struct gpio_chip *chip, unsigned offset,
-                             int value)
-{
-       struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio);
-
-       tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET2,
-                       value << offset, 1 << offset);
-}
-
-static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
-                               int value)
-{
-       struct tps6586x *tps6586x = container_of(gc, struct tps6586x, gpio);
-       uint8_t val, mask;
-
-       tps6586x_gpio_set(gc, offset, value);
-
-       val = 0x1 << (offset * 2);
-       mask = 0x3 << (offset * 2);
-
-       return tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET1, val, mask);
-}
-
-static int tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base)
-{
-       if (!gpio_base)
-               return 0;
-
-       tps6586x->gpio.owner            = THIS_MODULE;
-       tps6586x->gpio.label            = tps6586x->client->name;
-       tps6586x->gpio.dev              = tps6586x->dev;
-       tps6586x->gpio.base             = gpio_base;
-       tps6586x->gpio.ngpio            = 4;
-       tps6586x->gpio.can_sleep        = 1;
-
-       /* FIXME: add handling of GPIOs as dedicated inputs */
-       tps6586x->gpio.direction_output = tps6586x_gpio_output;
-       tps6586x->gpio.set              = tps6586x_gpio_set;
-       tps6586x->gpio.get              = tps6586x_gpio_get;
-
-       return gpiochip_add(&tps6586x->gpio);
-}
-
 static int __remove_subdev(struct device *dev, void *unused)
 {
        platform_device_unregister(to_platform_device(dev));
@@ -354,12 +224,11 @@ static void tps6586x_irq_sync_unlock(struct irq_data *data)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) {
-               if (tps6586x->mask_reg[i] != tps6586x->mask_cache[i]) {
-                       if (!WARN_ON(tps6586x_write(tps6586x->dev,
-                                                   TPS6586X_INT_MASK1 + i,
-                                                   tps6586x->mask_reg[i])))
-                               tps6586x->mask_cache[i] = tps6586x->mask_reg[i];
-               }
+               int ret;
+               ret = tps6586x_write(tps6586x->dev,
+                                           TPS6586X_INT_MASK1 + i,
+                                           tps6586x->mask_reg[i]);
+               WARN_ON(ret);
        }
 
        mutex_unlock(&tps6586x->irq_lock);
@@ -406,7 +275,6 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq,
 
        mutex_init(&tps6586x->irq_lock);
        for (i = 0; i < 5; i++) {
-               tps6586x->mask_cache[i] = 0xff;
                tps6586x->mask_reg[i] = 0xff;
                tps6586x_write(tps6586x->dev, TPS6586X_INT_MASK1 + i, 0xff);
        }
@@ -556,6 +424,23 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien
 }
 #endif
 
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       /* Cache all interrupt mask register */
+       if ((reg >= TPS6586X_INT_MASK1) && (reg <= TPS6586X_INT_MASK5))
+               return false;
+
+       return true;
+}
+
+static const struct regmap_config tps6586x_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = TPS6586X_MAX_REGISTER - 1,
+       .volatile_reg = is_volatile_reg,
+       .cache_type = REGCACHE_RBTREE,
+};
+
 static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
@@ -579,29 +464,39 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
 
        dev_info(&client->dev, "VERSIONCRC is %02x\n", ret);
 
-       tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL);
-       if (tps6586x == NULL)
+       tps6586x = devm_kzalloc(&client->dev, sizeof(*tps6586x), GFP_KERNEL);
+       if (tps6586x == NULL) {
+               dev_err(&client->dev, "memory for tps6586x alloc failed\n");
                return -ENOMEM;
+       }
 
        tps6586x->client = client;
        tps6586x->dev = &client->dev;
        i2c_set_clientdata(client, tps6586x);
 
-       mutex_init(&tps6586x->lock);
+       tps6586x->regmap = devm_regmap_init_i2c(client,
+                                       &tps6586x_regmap_config);
+       if (IS_ERR(tps6586x->regmap)) {
+               ret = PTR_ERR(tps6586x->regmap);
+               dev_err(&client->dev, "regmap init failed: %d\n", ret);
+               return ret;
+       }
+
 
        if (client->irq) {
                ret = tps6586x_irq_init(tps6586x, client->irq,
                                        pdata->irq_base);
                if (ret) {
                        dev_err(&client->dev, "IRQ init failed: %d\n", ret);
-                       goto err_irq_init;
+                       return ret;
                }
        }
 
-       ret = tps6586x_gpio_init(tps6586x, pdata->gpio_base);
-       if (ret) {
-               dev_err(&client->dev, "GPIO registration failed: %d\n", ret);
-               goto err_gpio_init;
+       ret = mfd_add_devices(tps6586x->dev, -1,
+                       tps6586x_cell, ARRAY_SIZE(tps6586x_cell), NULL, 0);
+       if (ret < 0) {
+               dev_err(&client->dev, "mfd_add_devices failed: %d\n", ret);
+               goto err_mfd_add;
        }
 
        ret = tps6586x_add_subdevs(tps6586x, pdata);
@@ -613,38 +508,21 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
        return 0;
 
 err_add_devs:
-       if (pdata->gpio_base) {
-               ret = gpiochip_remove(&tps6586x->gpio);
-               if (ret)
-                       dev_err(&client->dev, "Can't remove gpio chip: %d\n",
-                               ret);
-       }
-err_gpio_init:
+       mfd_remove_devices(tps6586x->dev);
+err_mfd_add:
        if (client->irq)
                free_irq(client->irq, tps6586x);
-err_irq_init:
-       kfree(tps6586x);
        return ret;
 }
 
 static int __devexit tps6586x_i2c_remove(struct i2c_client *client)
 {
        struct tps6586x *tps6586x = i2c_get_clientdata(client);
-       struct tps6586x_platform_data *pdata = client->dev.platform_data;
-       int ret;
 
+       tps6586x_remove_subdevs(tps6586x);
+       mfd_remove_devices(tps6586x->dev);
        if (client->irq)
                free_irq(client->irq, tps6586x);
-
-       if (pdata->gpio_base) {
-               ret = gpiochip_remove(&tps6586x->gpio);
-               if (ret)
-                       dev_err(&client->dev, "Can't remove gpio chip: %d\n",
-                               ret);
-       }
-
-       tps6586x_remove_subdevs(tps6586x);
-       kfree(tps6586x);
        return 0;
 }
 
index be9e07b77325a6afef8ed64253bc4a51e5cb4cc9..1c563792c777ba8f04c194a2a99c39159d8871f7 100644 (file)
@@ -68,6 +68,24 @@ static const struct regmap_config tps65910_regmap_config = {
        .cache_type = REGCACHE_RBTREE,
 };
 
+static int __devinit tps65910_ck32k_init(struct tps65910 *tps65910,
+                                       struct tps65910_board *pmic_pdata)
+{
+       int ret;
+
+       if (!pmic_pdata->en_ck32k_xtal)
+               return 0;
+
+       ret = tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL,
+                                               DEVCTRL_CK32K_CTRL_MASK);
+       if (ret < 0) {
+               dev_err(tps65910->dev, "clear ck32k_ctrl failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int __devinit tps65910_sleepinit(struct tps65910 *tps65910,
                struct tps65910_board *pmic_pdata)
 {
@@ -175,6 +193,9 @@ static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client,
        else if (*chip_id == TPS65911)
                dev_warn(&client->dev, "VMBCH2-Threshold not specified");
 
+       prop = of_property_read_bool(np, "ti,en-ck32k-xtal");
+       board_info->en_ck32k_xtal = prop;
+
        board_info->irq = client->irq;
        board_info->irq_base = -1;
 
@@ -243,7 +264,7 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c,
        init_data->irq_base = pmic_plat_data->irq_base;
 
        tps65910_irq_init(tps65910, init_data->irq, init_data);
-
+       tps65910_ck32k_init(tps65910, pmic_plat_data);
        tps65910_sleepinit(tps65910, pmic_plat_data);
 
        return ret;
index 6fc90befa79e415bbd377e978191b958abaf6fb1..1c32afed28aad0ade45943e6b20a6b7c22531e93 100644 (file)
@@ -568,7 +568,6 @@ add_numbered_child(unsigned chip, const char *name, int num,
                goto err;
        }
 
-       device_init_wakeup(&pdev->dev, can_wakeup);
        pdev->dev.parent = &twl->client->dev;
 
        if (pdata) {
@@ -593,6 +592,8 @@ add_numbered_child(unsigned chip, const char *name, int num,
        }
 
        status = platform_device_add(pdev);
+       if (status == 0)
+               device_init_wakeup(&pdev->dev, can_wakeup);
 
 err:
        if (status < 0) {
@@ -716,8 +717,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
                static struct regulator_consumer_supply usb1v8 = {
                        .supply =       "usb1v8",
                };
-               static struct regulator_consumer_supply usb3v1 = {
-                       .supply =       "usb3v1",
+               static struct regulator_consumer_supply usb3v1[] = {
+                       { .supply =     "usb3v1" },
+                       { .supply =     "bci3v1" },
                };
 
        /* First add the regulators so that they can be used by transceiver */
@@ -745,7 +747,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
                                return PTR_ERR(child);
 
                        child = add_regulator_linked(TWL4030_REG_VUSB3V1,
-                                                     &usb_fixed, &usb3v1, 1,
+                                                     &usb_fixed, usb3v1, 2,
                                                      features);
                        if (IS_ERR(child))
                                return PTR_ERR(child);
@@ -766,7 +768,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
                if (twl_has_regulator() && child) {
                        usb1v5.dev_name = dev_name(child);
                        usb1v8.dev_name = dev_name(child);
-                       usb3v1.dev_name = dev_name(child);
+                       usb3v1[0].dev_name = dev_name(child);
                }
        }
        if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
index 4ded9e7aa246efdc0e38347fab044f46ef2dc7ef..b0fad0ffca560b0714a9574b42d4c87c89ea3e4d 100644 (file)
@@ -64,19 +64,15 @@ int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg)
        int ret;
        unsigned int val;
 
-       mutex_lock(&twl6040->io_mutex);
        /* Vibra control registers from cache */
        if (unlikely(reg == TWL6040_REG_VIBCTLL ||
                     reg == TWL6040_REG_VIBCTLR)) {
                val = twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)];
        } else {
                ret = regmap_read(twl6040->regmap, reg, &val);
-               if (ret < 0) {
-                       mutex_unlock(&twl6040->io_mutex);
+               if (ret < 0)
                        return ret;
-               }
        }
-       mutex_unlock(&twl6040->io_mutex);
 
        return val;
 }
@@ -86,12 +82,10 @@ int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg, u8 val)
 {
        int ret;
 
-       mutex_lock(&twl6040->io_mutex);
        ret = regmap_write(twl6040->regmap, reg, val);
        /* Cache the vibra control registers */
        if (reg == TWL6040_REG_VIBCTLL || reg == TWL6040_REG_VIBCTLR)
                twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)] = val;
-       mutex_unlock(&twl6040->io_mutex);
 
        return ret;
 }
@@ -99,23 +93,13 @@ EXPORT_SYMBOL(twl6040_reg_write);
 
 int twl6040_set_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask)
 {
-       int ret;
-
-       mutex_lock(&twl6040->io_mutex);
-       ret = regmap_update_bits(twl6040->regmap, reg, mask, mask);
-       mutex_unlock(&twl6040->io_mutex);
-       return ret;
+       return regmap_update_bits(twl6040->regmap, reg, mask, mask);
 }
 EXPORT_SYMBOL(twl6040_set_bits);
 
 int twl6040_clear_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask)
 {
-       int ret;
-
-       mutex_lock(&twl6040->io_mutex);
-       ret = regmap_update_bits(twl6040->regmap, reg, mask, 0);
-       mutex_unlock(&twl6040->io_mutex);
-       return ret;
+       return regmap_update_bits(twl6040->regmap, reg, mask, 0);
 }
 EXPORT_SYMBOL(twl6040_clear_bits);
 
@@ -573,7 +557,6 @@ static int __devinit twl6040_probe(struct i2c_client *client,
        twl6040->irq = client->irq;
 
        mutex_init(&twl6040->mutex);
-       mutex_init(&twl6040->io_mutex);
        init_completion(&twl6040->ready);
 
        twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);
@@ -696,6 +679,7 @@ static int __devexit twl6040_remove(struct i2c_client *client)
 
 static const struct i2c_device_id twl6040_i2c_id[] = {
        { "twl6040", 0, },
+       { "twl6041", 0, },
        { },
 };
 MODULE_DEVICE_TABLE(i2c, twl6040_i2c_id);
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
new file mode 100644 (file)
index 0000000..01b9255
--- /dev/null
@@ -0,0 +1,2399 @@
+/*
+ * wm5102-tables.c  --  WM5102 data tables
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+
+#define WM5102_NUM_AOD_ISR 2
+#define WM5102_NUM_ISR 5
+
+static const struct reg_default wm5102_reva_patch[] = {
+       { 0x80, 0x0003 },
+       { 0x221, 0x0090 },
+       { 0x211, 0x0014 },
+       { 0x212, 0x0000 },
+       { 0x214, 0x000C },
+       { 0x171, 0x0002 },
+       { 0x171, 0x0000 },
+       { 0x461, 0x8000 },
+       { 0x463, 0x50F0 },
+       { 0x465, 0x4820 },
+       { 0x467, 0x4040 },
+       { 0x469, 0x3940 },
+       { 0x46B, 0x3310 },
+       { 0x46D, 0x2D80 },
+       { 0x46F, 0x2890 },
+       { 0x471, 0x1990 },
+       { 0x473, 0x1450 },
+       { 0x475, 0x1020 },
+       { 0x477, 0x0CD0 },
+       { 0x479, 0x0A30 },
+       { 0x47B, 0x0810 },
+       { 0x47D, 0x0510 },
+       { 0x500, 0x000D },
+       { 0x507, 0x1820 },
+       { 0x508, 0x1820 },
+       { 0x540, 0x000D },
+       { 0x547, 0x1820 },
+       { 0x548, 0x1820 },
+       { 0x580, 0x000D },
+       { 0x587, 0x1820 },
+       { 0x588, 0x1820 },
+       { 0x101, 0x8140 },
+       { 0x3000, 0x2225 },
+       { 0x3001, 0x3a03 },
+       { 0x3002, 0x0225 },
+       { 0x3003, 0x0801 },
+       { 0x3004, 0x6249 },
+       { 0x3005, 0x0c04 },
+       { 0x3006, 0x0225 },
+       { 0x3007, 0x5901 },
+       { 0x3008, 0xe249 },
+       { 0x3009, 0x030d },
+       { 0x300a, 0x0249 },
+       { 0x300b, 0x2c01 },
+       { 0x300c, 0xe249 },
+       { 0x300d, 0x4342 },
+       { 0x300e, 0xe249 },
+       { 0x300f, 0x73c0 },
+       { 0x3010, 0x4249 },
+       { 0x3011, 0x0c00 },
+       { 0x3012, 0x0225 },
+       { 0x3013, 0x1f01 },
+       { 0x3014, 0x0225 },
+       { 0x3015, 0x1e01 },
+       { 0x3016, 0x0225 },
+       { 0x3017, 0xfa00 },
+       { 0x3018, 0x0000 },
+       { 0x3019, 0xf000 },
+       { 0x301a, 0x0000 },
+       { 0x301b, 0xf000 },
+       { 0x301c, 0x0000 },
+       { 0x301d, 0xf000 },
+       { 0x301e, 0x0000 },
+       { 0x301f, 0xf000 },
+       { 0x3020, 0x0000 },
+       { 0x3021, 0xf000 },
+       { 0x3022, 0x0000 },
+       { 0x3023, 0xf000 },
+       { 0x3024, 0x0000 },
+       { 0x3025, 0xf000 },
+       { 0x3026, 0x0000 },
+       { 0x3027, 0xf000 },
+       { 0x3028, 0x0000 },
+       { 0x3029, 0xf000 },
+       { 0x302a, 0x0000 },
+       { 0x302b, 0xf000 },
+       { 0x302c, 0x0000 },
+       { 0x302d, 0xf000 },
+       { 0x302e, 0x0000 },
+       { 0x302f, 0xf000 },
+       { 0x3030, 0x0225 },
+       { 0x3031, 0x1a01 },
+       { 0x3032, 0x0225 },
+       { 0x3033, 0x1e00 },
+       { 0x3034, 0x0225 },
+       { 0x3035, 0x1f00 },
+       { 0x3036, 0x6225 },
+       { 0x3037, 0xf800 },
+       { 0x3038, 0x0000 },
+       { 0x3039, 0xf000 },
+       { 0x303a, 0x0000 },
+       { 0x303b, 0xf000 },
+       { 0x303c, 0x0000 },
+       { 0x303d, 0xf000 },
+       { 0x303e, 0x0000 },
+       { 0x303f, 0xf000 },
+       { 0x3040, 0x2226 },
+       { 0x3041, 0x3a03 },
+       { 0x3042, 0x0226 },
+       { 0x3043, 0x0801 },
+       { 0x3044, 0x6249 },
+       { 0x3045, 0x0c06 },
+       { 0x3046, 0x0226 },
+       { 0x3047, 0x5901 },
+       { 0x3048, 0xe249 },
+       { 0x3049, 0x030d },
+       { 0x304a, 0x0249 },
+       { 0x304b, 0x2c01 },
+       { 0x304c, 0xe249 },
+       { 0x304d, 0x4342 },
+       { 0x304e, 0xe249 },
+       { 0x304f, 0x73c0 },
+       { 0x3050, 0x4249 },
+       { 0x3051, 0x0c00 },
+       { 0x3052, 0x0226 },
+       { 0x3053, 0x1f01 },
+       { 0x3054, 0x0226 },
+       { 0x3055, 0x1e01 },
+       { 0x3056, 0x0226 },
+       { 0x3057, 0xfa00 },
+       { 0x3058, 0x0000 },
+       { 0x3059, 0xf000 },
+       { 0x305a, 0x0000 },
+       { 0x305b, 0xf000 },
+       { 0x305c, 0x0000 },
+       { 0x305d, 0xf000 },
+       { 0x305e, 0x0000 },
+       { 0x305f, 0xf000 },
+       { 0x3060, 0x0000 },
+       { 0x3061, 0xf000 },
+       { 0x3062, 0x0000 },
+       { 0x3063, 0xf000 },
+       { 0x3064, 0x0000 },
+       { 0x3065, 0xf000 },
+       { 0x3066, 0x0000 },
+       { 0x3067, 0xf000 },
+       { 0x3068, 0x0000 },
+       { 0x3069, 0xf000 },
+       { 0x306a, 0x0000 },
+       { 0x306b, 0xf000 },
+       { 0x306c, 0x0000 },
+       { 0x306d, 0xf000 },
+       { 0x306e, 0x0000 },
+       { 0x306f, 0xf000 },
+       { 0x3070, 0x0226 },
+       { 0x3071, 0x1a01 },
+       { 0x3072, 0x0226 },
+       { 0x3073, 0x1e00 },
+       { 0x3074, 0x0226 },
+       { 0x3075, 0x1f00 },
+       { 0x3076, 0x6226 },
+       { 0x3077, 0xf800 },
+       { 0x3078, 0x0000 },
+       { 0x3079, 0xf000 },
+       { 0x307a, 0x0000 },
+       { 0x307b, 0xf000 },
+       { 0x307c, 0x0000 },
+       { 0x307d, 0xf000 },
+       { 0x307e, 0x0000 },
+       { 0x307f, 0xf000 },
+       { 0x3080, 0x2227 },
+       { 0x3081, 0x3a03 },
+       { 0x3082, 0x0227 },
+       { 0x3083, 0x0801 },
+       { 0x3084, 0x6255 },
+       { 0x3085, 0x0c04 },
+       { 0x3086, 0x0227 },
+       { 0x3087, 0x5901 },
+       { 0x3088, 0xe255 },
+       { 0x3089, 0x030d },
+       { 0x308a, 0x0255 },
+       { 0x308b, 0x2c01 },
+       { 0x308c, 0xe255 },
+       { 0x308d, 0x4342 },
+       { 0x308e, 0xe255 },
+       { 0x308f, 0x73c0 },
+       { 0x3090, 0x4255 },
+       { 0x3091, 0x0c00 },
+       { 0x3092, 0x0227 },
+       { 0x3093, 0x1f01 },
+       { 0x3094, 0x0227 },
+       { 0x3095, 0x1e01 },
+       { 0x3096, 0x0227 },
+       { 0x3097, 0xfa00 },
+       { 0x3098, 0x0000 },
+       { 0x3099, 0xf000 },
+       { 0x309a, 0x0000 },
+       { 0x309b, 0xf000 },
+       { 0x309c, 0x0000 },
+       { 0x309d, 0xf000 },
+       { 0x309e, 0x0000 },
+       { 0x309f, 0xf000 },
+       { 0x30a0, 0x0000 },
+       { 0x30a1, 0xf000 },
+       { 0x30a2, 0x0000 },
+       { 0x30a3, 0xf000 },
+       { 0x30a4, 0x0000 },
+       { 0x30a5, 0xf000 },
+       { 0x30a6, 0x0000 },
+       { 0x30a7, 0xf000 },
+       { 0x30a8, 0x0000 },
+       { 0x30a9, 0xf000 },
+       { 0x30aa, 0x0000 },
+       { 0x30ab, 0xf000 },
+       { 0x30ac, 0x0000 },
+       { 0x30ad, 0xf000 },
+       { 0x30ae, 0x0000 },
+       { 0x30af, 0xf000 },
+       { 0x30b0, 0x0227 },
+       { 0x30b1, 0x1a01 },
+       { 0x30b2, 0x0227 },
+       { 0x30b3, 0x1e00 },
+       { 0x30b4, 0x0227 },
+       { 0x30b5, 0x1f00 },
+       { 0x30b6, 0x6227 },
+       { 0x30b7, 0xf800 },
+       { 0x30b8, 0x0000 },
+       { 0x30b9, 0xf000 },
+       { 0x30ba, 0x0000 },
+       { 0x30bb, 0xf000 },
+       { 0x30bc, 0x0000 },
+       { 0x30bd, 0xf000 },
+       { 0x30be, 0x0000 },
+       { 0x30bf, 0xf000 },
+       { 0x30c0, 0x2228 },
+       { 0x30c1, 0x3a03 },
+       { 0x30c2, 0x0228 },
+       { 0x30c3, 0x0801 },
+       { 0x30c4, 0x6255 },
+       { 0x30c5, 0x0c06 },
+       { 0x30c6, 0x0228 },
+       { 0x30c7, 0x5901 },
+       { 0x30c8, 0xe255 },
+       { 0x30c9, 0x030d },
+       { 0x30ca, 0x0255 },
+       { 0x30cb, 0x2c01 },
+       { 0x30cc, 0xe255 },
+       { 0x30cd, 0x4342 },
+       { 0x30ce, 0xe255 },
+       { 0x30cf, 0x73c0 },
+       { 0x30d0, 0x4255 },
+       { 0x30d1, 0x0c00 },
+       { 0x30d2, 0x0228 },
+       { 0x30d3, 0x1f01 },
+       { 0x30d4, 0x0228 },
+       { 0x30d5, 0x1e01 },
+       { 0x30d6, 0x0228 },
+       { 0x30d7, 0xfa00 },
+       { 0x30d8, 0x0000 },
+       { 0x30d9, 0xf000 },
+       { 0x30da, 0x0000 },
+       { 0x30db, 0xf000 },
+       { 0x30dc, 0x0000 },
+       { 0x30dd, 0xf000 },
+       { 0x30de, 0x0000 },
+       { 0x30df, 0xf000 },
+       { 0x30e0, 0x0000 },
+       { 0x30e1, 0xf000 },
+       { 0x30e2, 0x0000 },
+       { 0x30e3, 0xf000 },
+       { 0x30e4, 0x0000 },
+       { 0x30e5, 0xf000 },
+       { 0x30e6, 0x0000 },
+       { 0x30e7, 0xf000 },
+       { 0x30e8, 0x0000 },
+       { 0x30e9, 0xf000 },
+       { 0x30ea, 0x0000 },
+       { 0x30eb, 0xf000 },
+       { 0x30ec, 0x0000 },
+       { 0x30ed, 0xf000 },
+       { 0x30ee, 0x0000 },
+       { 0x30ef, 0xf000 },
+       { 0x30f0, 0x0228 },
+       { 0x30f1, 0x1a01 },
+       { 0x30f2, 0x0228 },
+       { 0x30f3, 0x1e00 },
+       { 0x30f4, 0x0228 },
+       { 0x30f5, 0x1f00 },
+       { 0x30f6, 0x6228 },
+       { 0x30f7, 0xf800 },
+       { 0x30f8, 0x0000 },
+       { 0x30f9, 0xf000 },
+       { 0x30fa, 0x0000 },
+       { 0x30fb, 0xf000 },
+       { 0x30fc, 0x0000 },
+       { 0x30fd, 0xf000 },
+       { 0x30fe, 0x0000 },
+       { 0x30ff, 0xf000 },
+       { 0x3100, 0x222b },
+       { 0x3101, 0x3a03 },
+       { 0x3102, 0x222b },
+       { 0x3103, 0x5803 },
+       { 0x3104, 0xe26f },
+       { 0x3105, 0x030d },
+       { 0x3106, 0x626f },
+       { 0x3107, 0x2c01 },
+       { 0x3108, 0xe26f },
+       { 0x3109, 0x4342 },
+       { 0x310a, 0xe26f },
+       { 0x310b, 0x73c0 },
+       { 0x310c, 0x026f },
+       { 0x310d, 0x0c00 },
+       { 0x310e, 0x022b },
+       { 0x310f, 0x1f01 },
+       { 0x3110, 0x022b },
+       { 0x3111, 0x1e01 },
+       { 0x3112, 0x022b },
+       { 0x3113, 0xfa00 },
+       { 0x3114, 0x0000 },
+       { 0x3115, 0xf000 },
+       { 0x3116, 0x0000 },
+       { 0x3117, 0xf000 },
+       { 0x3118, 0x0000 },
+       { 0x3119, 0xf000 },
+       { 0x311a, 0x0000 },
+       { 0x311b, 0xf000 },
+       { 0x311c, 0x0000 },
+       { 0x311d, 0xf000 },
+       { 0x311e, 0x0000 },
+       { 0x311f, 0xf000 },
+       { 0x3120, 0x022b },
+       { 0x3121, 0x0a01 },
+       { 0x3122, 0x022b },
+       { 0x3123, 0x1e00 },
+       { 0x3124, 0x022b },
+       { 0x3125, 0x1f00 },
+       { 0x3126, 0x622b },
+       { 0x3127, 0xf800 },
+       { 0x3128, 0x0000 },
+       { 0x3129, 0xf000 },
+       { 0x312a, 0x0000 },
+       { 0x312b, 0xf000 },
+       { 0x312c, 0x0000 },
+       { 0x312d, 0xf000 },
+       { 0x312e, 0x0000 },
+       { 0x312f, 0xf000 },
+       { 0x3130, 0x0000 },
+       { 0x3131, 0xf000 },
+       { 0x3132, 0x0000 },
+       { 0x3133, 0xf000 },
+       { 0x3134, 0x0000 },
+       { 0x3135, 0xf000 },
+       { 0x3136, 0x0000 },
+       { 0x3137, 0xf000 },
+       { 0x3138, 0x0000 },
+       { 0x3139, 0xf000 },
+       { 0x313a, 0x0000 },
+       { 0x313b, 0xf000 },
+       { 0x313c, 0x0000 },
+       { 0x313d, 0xf000 },
+       { 0x313e, 0x0000 },
+       { 0x313f, 0xf000 },
+       { 0x3140, 0x0000 },
+       { 0x3141, 0xf000 },
+       { 0x3142, 0x0000 },
+       { 0x3143, 0xf000 },
+       { 0x3144, 0x0000 },
+       { 0x3145, 0xf000 },
+       { 0x3146, 0x0000 },
+       { 0x3147, 0xf000 },
+       { 0x3148, 0x0000 },
+       { 0x3149, 0xf000 },
+       { 0x314a, 0x0000 },
+       { 0x314b, 0xf000 },
+       { 0x314c, 0x0000 },
+       { 0x314d, 0xf000 },
+       { 0x314e, 0x0000 },
+       { 0x314f, 0xf000 },
+       { 0x3150, 0x0000 },
+       { 0x3151, 0xf000 },
+       { 0x3152, 0x0000 },
+       { 0x3153, 0xf000 },
+       { 0x3154, 0x0000 },
+       { 0x3155, 0xf000 },
+       { 0x3156, 0x0000 },
+       { 0x3157, 0xf000 },
+       { 0x3158, 0x0000 },
+       { 0x3159, 0xf000 },
+       { 0x315a, 0x0000 },
+       { 0x315b, 0xf000 },
+       { 0x315c, 0x0000 },
+       { 0x315d, 0xf000 },
+       { 0x315e, 0x0000 },
+       { 0x315f, 0xf000 },
+       { 0x3160, 0x0000 },
+       { 0x3161, 0xf000 },
+       { 0x3162, 0x0000 },
+       { 0x3163, 0xf000 },
+       { 0x3164, 0x0000 },
+       { 0x3165, 0xf000 },
+       { 0x3166, 0x0000 },
+       { 0x3167, 0xf000 },
+       { 0x3168, 0x0000 },
+       { 0x3169, 0xf000 },
+       { 0x316a, 0x0000 },
+       { 0x316b, 0xf000 },
+       { 0x316c, 0x0000 },
+       { 0x316d, 0xf000 },
+       { 0x316e, 0x0000 },
+       { 0x316f, 0xf000 },
+       { 0x3170, 0x0000 },
+       { 0x3171, 0xf000 },
+       { 0x3172, 0x0000 },
+       { 0x3173, 0xf000 },
+       { 0x3174, 0x0000 },
+       { 0x3175, 0xf000 },
+       { 0x3176, 0x0000 },
+       { 0x3177, 0xf000 },
+       { 0x3178, 0x0000 },
+       { 0x3179, 0xf000 },
+       { 0x317a, 0x0000 },
+       { 0x317b, 0xf000 },
+       { 0x317c, 0x0000 },
+       { 0x317d, 0xf000 },
+       { 0x317e, 0x0000 },
+       { 0x317f, 0xf000 },
+       { 0x3180, 0x2001 },
+       { 0x3181, 0xf101 },
+       { 0x3182, 0x0000 },
+       { 0x3183, 0xf000 },
+       { 0x3184, 0x0000 },
+       { 0x3185, 0xf000 },
+       { 0x3186, 0x0000 },
+       { 0x3187, 0xf000 },
+       { 0x3188, 0x0000 },
+       { 0x3189, 0xf000 },
+       { 0x318a, 0x0000 },
+       { 0x318b, 0xf000 },
+       { 0x318c, 0x0000 },
+       { 0x318d, 0xf000 },
+       { 0x318e, 0x0000 },
+       { 0x318f, 0xf000 },
+       { 0x3190, 0x0000 },
+       { 0x3191, 0xf000 },
+       { 0x3192, 0x0000 },
+       { 0x3193, 0xf000 },
+       { 0x3194, 0x0000 },
+       { 0x3195, 0xf000 },
+       { 0x3196, 0x0000 },
+       { 0x3197, 0xf000 },
+       { 0x3198, 0x0000 },
+       { 0x3199, 0xf000 },
+       { 0x319a, 0x0000 },
+       { 0x319b, 0xf000 },
+       { 0x319c, 0x0000 },
+       { 0x319d, 0xf000 },
+       { 0x319e, 0x0000 },
+       { 0x319f, 0xf000 },
+       { 0x31a0, 0x0000 },
+       { 0x31a1, 0xf000 },
+       { 0x31a2, 0x0000 },
+       { 0x31a3, 0xf000 },
+       { 0x31a4, 0x0000 },
+       { 0x31a5, 0xf000 },
+       { 0x31a6, 0x0000 },
+       { 0x31a7, 0xf000 },
+       { 0x31a8, 0x0000 },
+       { 0x31a9, 0xf000 },
+       { 0x31aa, 0x0000 },
+       { 0x31ab, 0xf000 },
+       { 0x31ac, 0x0000 },
+       { 0x31ad, 0xf000 },
+       { 0x31ae, 0x0000 },
+       { 0x31af, 0xf000 },
+       { 0x31b0, 0x0000 },
+       { 0x31b1, 0xf000 },
+       { 0x31b2, 0x0000 },
+       { 0x31b3, 0xf000 },
+       { 0x31b4, 0x0000 },
+       { 0x31b5, 0xf000 },
+       { 0x31b6, 0x0000 },
+       { 0x31b7, 0xf000 },
+       { 0x31b8, 0x0000 },
+       { 0x31b9, 0xf000 },
+       { 0x31ba, 0x0000 },
+       { 0x31bb, 0xf000 },
+       { 0x31bc, 0x0000 },
+       { 0x31bd, 0xf000 },
+       { 0x31be, 0x0000 },
+       { 0x31bf, 0xf000 },
+       { 0x31c0, 0x0000 },
+       { 0x31c1, 0xf000 },
+       { 0x31c2, 0x0000 },
+       { 0x31c3, 0xf000 },
+       { 0x31c4, 0x0000 },
+       { 0x31c5, 0xf000 },
+       { 0x31c6, 0x0000 },
+       { 0x31c7, 0xf000 },
+       { 0x31c8, 0x0000 },
+       { 0x31c9, 0xf000 },
+       { 0x31ca, 0x0000 },
+       { 0x31cb, 0xf000 },
+       { 0x31cc, 0x0000 },
+       { 0x31cd, 0xf000 },
+       { 0x31ce, 0x0000 },
+       { 0x31cf, 0xf000 },
+       { 0x31d0, 0x0000 },
+       { 0x31d1, 0xf000 },
+       { 0x31d2, 0x0000 },
+       { 0x31d3, 0xf000 },
+       { 0x31d4, 0x0000 },
+       { 0x31d5, 0xf000 },
+       { 0x31d6, 0x0000 },
+       { 0x31d7, 0xf000 },
+       { 0x31d8, 0x0000 },
+       { 0x31d9, 0xf000 },
+       { 0x31da, 0x0000 },
+       { 0x31db, 0xf000 },
+       { 0x31dc, 0x0000 },
+       { 0x31dd, 0xf000 },
+       { 0x31de, 0x0000 },
+       { 0x31df, 0xf000 },
+       { 0x31e0, 0x0000 },
+       { 0x31e1, 0xf000 },
+       { 0x31e2, 0x0000 },
+       { 0x31e3, 0xf000 },
+       { 0x31e4, 0x0000 },
+       { 0x31e5, 0xf000 },
+       { 0x31e6, 0x0000 },
+       { 0x31e7, 0xf000 },
+       { 0x31e8, 0x0000 },
+       { 0x31e9, 0xf000 },
+       { 0x31ea, 0x0000 },
+       { 0x31eb, 0xf000 },
+       { 0x31ec, 0x0000 },
+       { 0x31ed, 0xf000 },
+       { 0x31ee, 0x0000 },
+       { 0x31ef, 0xf000 },
+       { 0x31f0, 0x0000 },
+       { 0x31f1, 0xf000 },
+       { 0x31f2, 0x0000 },
+       { 0x31f3, 0xf000 },
+       { 0x31f4, 0x0000 },
+       { 0x31f5, 0xf000 },
+       { 0x31f6, 0x0000 },
+       { 0x31f7, 0xf000 },
+       { 0x31f8, 0x0000 },
+       { 0x31f9, 0xf000 },
+       { 0x31fa, 0x0000 },
+       { 0x31fb, 0xf000 },
+       { 0x31fc, 0x0000 },
+       { 0x31fd, 0xf000 },
+       { 0x31fe, 0x0000 },
+       { 0x31ff, 0xf000 },
+       { 0x024d, 0xff50 },
+       { 0x0252, 0xff50 },
+       { 0x0259, 0x0112 },
+       { 0x025e, 0x0112 },
+       { 0x101, 0x0304 },
+       { 0x80, 0x0000 },
+};
+
+/* We use a function so we can use ARRAY_SIZE() */
+int wm5102_patch(struct arizona *arizona)
+{
+       switch (arizona->rev) {
+       case 0:
+               return regmap_register_patch(arizona->regmap,
+                                            wm5102_reva_patch,
+                                            ARRAY_SIZE(wm5102_reva_patch));
+       default:
+               return 0;
+       }
+}
+
+static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ] = {
+       [ARIZONA_IRQ_GP5_FALL] = { .mask = ARIZONA_GP5_FALL_EINT1 },
+       [ARIZONA_IRQ_GP5_RISE] = { .mask = ARIZONA_GP5_RISE_EINT1 },
+       [ARIZONA_IRQ_JD_FALL] = { .mask = ARIZONA_JD1_FALL_EINT1 },
+       [ARIZONA_IRQ_JD_RISE] = { .mask = ARIZONA_JD1_RISE_EINT1 },
+};
+
+const struct regmap_irq_chip wm5102_aod = {
+       .name = "wm5102 AOD",
+       .status_base = ARIZONA_AOD_IRQ1,
+       .mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1,
+       .ack_base = ARIZONA_AOD_IRQ1,
+       .wake_base = ARIZONA_WAKE_CONTROL,
+       .num_regs = 1,
+       .irqs = wm5102_aod_irqs,
+       .num_irqs = ARRAY_SIZE(wm5102_aod_irqs),
+};
+
+static const struct regmap_irq wm5102_irqs[ARIZONA_NUM_IRQ] = {
+       [ARIZONA_IRQ_GP4] = { .reg_offset = 0, .mask = ARIZONA_GP4_EINT1 },
+       [ARIZONA_IRQ_GP3] = { .reg_offset = 0, .mask = ARIZONA_GP3_EINT1 },
+       [ARIZONA_IRQ_GP2] = { .reg_offset = 0, .mask = ARIZONA_GP2_EINT1 },
+       [ARIZONA_IRQ_GP1] = { .reg_offset = 0, .mask = ARIZONA_GP1_EINT1 },
+
+       [ARIZONA_IRQ_DSP1_RAM_RDY] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP1_RAM_RDY_EINT1
+       },
+       [ARIZONA_IRQ_DSP_IRQ2] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP_IRQ2_EINT1
+       },
+       [ARIZONA_IRQ_DSP_IRQ1] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP_IRQ1_EINT1
+       },
+
+       [ARIZONA_IRQ_SPK_SHUTDOWN_WARN] = {
+               .reg_offset = 2, .mask = ARIZONA_SPK_SHUTDOWN_WARN_EINT1
+       },
+       [ARIZONA_IRQ_SPK_SHUTDOWN] = {
+               .reg_offset = 2, .mask = ARIZONA_SPK_SHUTDOWN_EINT1
+       },
+       [ARIZONA_IRQ_HPDET] = {
+               .reg_offset = 2, .mask = ARIZONA_HPDET_EINT1
+       },
+       [ARIZONA_IRQ_MICDET] = {
+               .reg_offset = 2, .mask = ARIZONA_MICDET_EINT1
+       },
+       [ARIZONA_IRQ_WSEQ_DONE] = {
+               .reg_offset = 2, .mask = ARIZONA_WSEQ_DONE_EINT1
+       },
+       [ARIZONA_IRQ_DRC2_SIG_DET] = {
+               .reg_offset = 2, .mask = ARIZONA_DRC2_SIG_DET_EINT1
+       },
+       [ARIZONA_IRQ_DRC1_SIG_DET] = {
+               .reg_offset = 2, .mask = ARIZONA_DRC1_SIG_DET_EINT1
+       },
+       [ARIZONA_IRQ_ASRC2_LOCK] = {
+               .reg_offset = 2, .mask = ARIZONA_ASRC2_LOCK_EINT1
+       },
+       [ARIZONA_IRQ_ASRC1_LOCK] = {
+               .reg_offset = 2, .mask = ARIZONA_ASRC1_LOCK_EINT1
+       },
+       [ARIZONA_IRQ_UNDERCLOCKED] = {
+               .reg_offset = 2, .mask = ARIZONA_UNDERCLOCKED_EINT1
+       },
+       [ARIZONA_IRQ_OVERCLOCKED] = {
+               .reg_offset = 2, .mask = ARIZONA_OVERCLOCKED_EINT1
+       },
+       [ARIZONA_IRQ_FLL2_LOCK] = {
+               .reg_offset = 2, .mask = ARIZONA_FLL2_LOCK_EINT1
+       },
+       [ARIZONA_IRQ_FLL1_LOCK] = {
+               .reg_offset = 2, .mask = ARIZONA_FLL1_LOCK_EINT1
+       },
+       [ARIZONA_IRQ_CLKGEN_ERR] = {
+               .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_EINT1
+       },
+       [ARIZONA_IRQ_CLKGEN_ERR_ASYNC] = {
+               .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_ASYNC_EINT1
+       },
+
+       [ARIZONA_IRQ_ASRC_CFG_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_ASRC_CFG_ERR_EINT1
+       },
+       [ARIZONA_IRQ_AIF3_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_AIF3_ERR_EINT1
+       },
+       [ARIZONA_IRQ_AIF2_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_AIF2_ERR_EINT1
+       },
+       [ARIZONA_IRQ_AIF1_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_AIF1_ERR_EINT1
+       },
+       [ARIZONA_IRQ_CTRLIF_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_CTRLIF_ERR_EINT1
+       },
+       [ARIZONA_IRQ_MIXER_DROPPED_SAMPLES] = {
+               .reg_offset = 3, .mask = ARIZONA_MIXER_DROPPED_SAMPLE_EINT1
+       },
+       [ARIZONA_IRQ_ASYNC_CLK_ENA_LOW] = {
+               .reg_offset = 3, .mask = ARIZONA_ASYNC_CLK_ENA_LOW_EINT1
+       },
+       [ARIZONA_IRQ_SYSCLK_ENA_LOW] = {
+               .reg_offset = 3, .mask = ARIZONA_SYSCLK_ENA_LOW_EINT1
+       },
+       [ARIZONA_IRQ_ISRC1_CFG_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_ISRC1_CFG_ERR_EINT1
+       },
+       [ARIZONA_IRQ_ISRC2_CFG_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_ISRC2_CFG_ERR_EINT1
+       },
+
+       [ARIZONA_IRQ_BOOT_DONE] = {
+               .reg_offset = 4, .mask = ARIZONA_BOOT_DONE_EINT1
+       },
+       [ARIZONA_IRQ_DCS_DAC_DONE] = {
+               .reg_offset = 4, .mask = ARIZONA_DCS_DAC_DONE_EINT1
+       },
+       [ARIZONA_IRQ_DCS_HP_DONE] = {
+               .reg_offset = 4, .mask = ARIZONA_DCS_HP_DONE_EINT1
+       },
+       [ARIZONA_IRQ_FLL2_CLOCK_OK] = {
+               .reg_offset = 4, .mask = ARIZONA_FLL2_CLOCK_OK_EINT1
+       },
+       [ARIZONA_IRQ_FLL1_CLOCK_OK] = {
+               .reg_offset = 4, .mask = ARIZONA_FLL1_CLOCK_OK_EINT1
+       },
+};
+
+const struct regmap_irq_chip wm5102_irq = {
+       .name = "wm5102 IRQ",
+       .status_base = ARIZONA_INTERRUPT_STATUS_1,
+       .mask_base = ARIZONA_INTERRUPT_STATUS_1_MASK,
+       .ack_base = ARIZONA_INTERRUPT_STATUS_1,
+       .num_regs = 5,
+       .irqs = wm5102_irqs,
+       .num_irqs = ARRAY_SIZE(wm5102_irqs),
+};
+
+static const struct reg_default wm5102_reg_default[] = {
+       { 0x00000008, 0x0019 },   /* R8     - Ctrl IF SPI CFG 1 */ 
+       { 0x00000009, 0x0001 },   /* R9     - Ctrl IF I2C1 CFG 1 */ 
+       { 0x0000000D, 0x0000 },   /* R13    - Ctrl IF Status 1 */ 
+       { 0x00000016, 0x0000 },   /* R22    - Write Sequencer Ctrl 0 */ 
+       { 0x00000017, 0x0000 },   /* R23    - Write Sequencer Ctrl 1 */ 
+       { 0x00000018, 0x0000 },   /* R24    - Write Sequencer Ctrl 2 */ 
+       { 0x0000001A, 0x0000 },   /* R26    - Write Sequencer PROM */ 
+       { 0x00000020, 0x0000 },   /* R32    - Tone Generator 1 */ 
+       { 0x00000021, 0x1000 },   /* R33    - Tone Generator 2 */ 
+       { 0x00000022, 0x0000 },   /* R34    - Tone Generator 3 */ 
+       { 0x00000023, 0x1000 },   /* R35    - Tone Generator 4 */ 
+       { 0x00000024, 0x0000 },   /* R36    - Tone Generator 5 */ 
+       { 0x00000030, 0x0000 },   /* R48    - PWM Drive 1 */ 
+       { 0x00000031, 0x0100 },   /* R49    - PWM Drive 2 */ 
+       { 0x00000032, 0x0100 },   /* R50    - PWM Drive 3 */ 
+       { 0x00000040, 0x0000 },   /* R64    - Wake control */ 
+       { 0x00000041, 0x0000 },   /* R65    - Sequence control */ 
+       { 0x00000061, 0x01FF },   /* R97    - Sample Rate Sequence Select 1 */ 
+       { 0x00000062, 0x01FF },   /* R98    - Sample Rate Sequence Select 2 */ 
+       { 0x00000063, 0x01FF },   /* R99    - Sample Rate Sequence Select 3 */ 
+       { 0x00000064, 0x01FF },   /* R100   - Sample Rate Sequence Select 4 */ 
+       { 0x00000068, 0x01FF },   /* R104   - Always On Triggers Sequence Select 1 */ 
+       { 0x00000069, 0x01FF },   /* R105   - Always On Triggers Sequence Select 2 */ 
+       { 0x0000006A, 0x01FF },   /* R106   - Always On Triggers Sequence Select 3 */ 
+       { 0x0000006B, 0x01FF },   /* R107   - Always On Triggers Sequence Select 4 */ 
+       { 0x0000006C, 0x01FF },   /* R108   - Always On Triggers Sequence Select 5 */ 
+       { 0x0000006D, 0x01FF },   /* R109   - Always On Triggers Sequence Select 6 */ 
+       { 0x00000070, 0x0000 },   /* R112   - Comfort Noise Generator */ 
+       { 0x00000090, 0x0000 },   /* R144   - Haptics Control 1 */ 
+       { 0x00000091, 0x7FFF },   /* R145   - Haptics Control 2 */ 
+       { 0x00000092, 0x0000 },   /* R146   - Haptics phase 1 intensity */ 
+       { 0x00000093, 0x0000 },   /* R147   - Haptics phase 1 duration */ 
+       { 0x00000094, 0x0000 },   /* R148   - Haptics phase 2 intensity */ 
+       { 0x00000095, 0x0000 },   /* R149   - Haptics phase 2 duration */ 
+       { 0x00000096, 0x0000 },   /* R150   - Haptics phase 3 intensity */ 
+       { 0x00000097, 0x0000 },   /* R151   - Haptics phase 3 duration */ 
+       { 0x00000100, 0x0001 },   /* R256   - Clock 32k 1 */ 
+       { 0x00000101, 0x0304 },   /* R257   - System Clock 1 */ 
+       { 0x00000102, 0x0011 },   /* R258   - Sample rate 1 */ 
+       { 0x00000103, 0x0011 },   /* R259   - Sample rate 2 */ 
+       { 0x00000104, 0x0011 },   /* R260   - Sample rate 3 */ 
+       { 0x00000112, 0x0305 },   /* R274   - Async clock 1 */ 
+       { 0x00000113, 0x0011 },   /* R275   - Async sample rate 1 */ 
+       { 0x00000149, 0x0000 },   /* R329   - Output system clock */ 
+       { 0x0000014A, 0x0000 },   /* R330   - Output async clock */ 
+       { 0x00000152, 0x0000 },   /* R338   - Rate Estimator 1 */ 
+       { 0x00000153, 0x0000 },   /* R339   - Rate Estimator 2 */ 
+       { 0x00000154, 0x0000 },   /* R340   - Rate Estimator 3 */ 
+       { 0x00000155, 0x0000 },   /* R341   - Rate Estimator 4 */ 
+       { 0x00000156, 0x0000 },   /* R342   - Rate Estimator 5 */ 
+       { 0x00000171, 0x0000 },   /* R369   - FLL1 Control 1 */ 
+       { 0x00000172, 0x0008 },   /* R370   - FLL1 Control 2 */ 
+       { 0x00000173, 0x0018 },   /* R371   - FLL1 Control 3 */ 
+       { 0x00000174, 0x007D },   /* R372   - FLL1 Control 4 */ 
+       { 0x00000175, 0x0004 },   /* R373   - FLL1 Control 5 */ 
+       { 0x00000176, 0x0000 },   /* R374   - FLL1 Control 6 */ 
+       { 0x00000177, 0x0181 },   /* R375   - FLL1 Loop Filter Test 1 */ 
+       { 0x00000181, 0x0000 },   /* R385   - FLL1 Synchroniser 1 */ 
+       { 0x00000182, 0x0000 },   /* R386   - FLL1 Synchroniser 2 */ 
+       { 0x00000183, 0x0000 },   /* R387   - FLL1 Synchroniser 3 */ 
+       { 0x00000184, 0x0000 },   /* R388   - FLL1 Synchroniser 4 */ 
+       { 0x00000185, 0x0000 },   /* R389   - FLL1 Synchroniser 5 */ 
+       { 0x00000186, 0x0000 },   /* R390   - FLL1 Synchroniser 6 */ 
+       { 0x00000189, 0x0000 },   /* R393   - FLL1 Spread Spectrum */ 
+       { 0x0000018A, 0x0004 },   /* R394   - FLL1 GPIO Clock */ 
+       { 0x00000191, 0x0000 },   /* R401   - FLL2 Control 1 */ 
+       { 0x00000192, 0x0008 },   /* R402   - FLL2 Control 2 */ 
+       { 0x00000193, 0x0018 },   /* R403   - FLL2 Control 3 */ 
+       { 0x00000194, 0x007D },   /* R404   - FLL2 Control 4 */ 
+       { 0x00000195, 0x0004 },   /* R405   - FLL2 Control 5 */ 
+       { 0x00000196, 0x0000 },   /* R406   - FLL2 Control 6 */ 
+       { 0x00000197, 0x0000 },   /* R407   - FLL2 Loop Filter Test 1 */ 
+       { 0x000001A1, 0x0000 },   /* R417   - FLL2 Synchroniser 1 */ 
+       { 0x000001A2, 0x0000 },   /* R418   - FLL2 Synchroniser 2 */ 
+       { 0x000001A3, 0x0000 },   /* R419   - FLL2 Synchroniser 3 */ 
+       { 0x000001A4, 0x0000 },   /* R420   - FLL2 Synchroniser 4 */ 
+       { 0x000001A5, 0x0000 },   /* R421   - FLL2 Synchroniser 5 */ 
+       { 0x000001A6, 0x0000 },   /* R422   - FLL2 Synchroniser 6 */ 
+       { 0x000001A9, 0x0000 },   /* R425   - FLL2 Spread Spectrum */ 
+       { 0x000001AA, 0x0004 },   /* R426   - FLL2 GPIO Clock */ 
+       { 0x00000200, 0x0006 },   /* R512   - Mic Charge Pump 1 */ 
+       { 0x00000210, 0x00D4 },   /* R528   - LDO1 Control 1 */ 
+       { 0x00000213, 0x0344 },   /* R531   - LDO2 Control 1 */ 
+       { 0x00000218, 0x01A6 },   /* R536   - Mic Bias Ctrl 1 */ 
+       { 0x00000219, 0x01A6 },   /* R537   - Mic Bias Ctrl 2 */ 
+       { 0x0000021A, 0x01A6 },   /* R538   - Mic Bias Ctrl 3 */ 
+       { 0x00000293, 0x0000 },   /* R659   - Accessory Detect Mode 1 */ 
+       { 0x0000029B, 0x0020 },   /* R667   - Headphone Detect 1 */ 
+       { 0x000002A3, 0x1102 },   /* R675   - Mic Detect 1 */ 
+       { 0x000002A4, 0x009F },   /* R676   - Mic Detect 2 */ 
+       { 0x000002A5, 0x0000 },   /* R677   - Mic Detect 3 */ 
+       { 0x000002C3, 0x0000 },   /* R707   - Mic noise mix control 1 */ 
+       { 0x000002CB, 0x0000 },   /* R715   - Isolation control */ 
+       { 0x000002D3, 0x0000 },   /* R723   - Jack detect analogue */ 
+       { 0x00000300, 0x0000 },   /* R768   - Input Enables */ 
+       { 0x00000308, 0x0000 },   /* R776   - Input Rate */ 
+       { 0x00000309, 0x0022 },   /* R777   - Input Volume Ramp */ 
+       { 0x00000310, 0x2080 },   /* R784   - IN1L Control */ 
+       { 0x00000311, 0x0180 },   /* R785   - ADC Digital Volume 1L */ 
+       { 0x00000312, 0x0000 },   /* R786   - DMIC1L Control */ 
+       { 0x00000314, 0x0080 },   /* R788   - IN1R Control */ 
+       { 0x00000315, 0x0180 },   /* R789   - ADC Digital Volume 1R */ 
+       { 0x00000316, 0x0000 },   /* R790   - DMIC1R Control */ 
+       { 0x00000318, 0x2080 },   /* R792   - IN2L Control */ 
+       { 0x00000319, 0x0180 },   /* R793   - ADC Digital Volume 2L */ 
+       { 0x0000031A, 0x0000 },   /* R794   - DMIC2L Control */ 
+       { 0x0000031C, 0x0080 },   /* R796   - IN2R Control */ 
+       { 0x0000031D, 0x0180 },   /* R797   - ADC Digital Volume 2R */ 
+       { 0x0000031E, 0x0000 },   /* R798   - DMIC2R Control */ 
+       { 0x00000320, 0x2080 },   /* R800   - IN3L Control */ 
+       { 0x00000321, 0x0180 },   /* R801   - ADC Digital Volume 3L */ 
+       { 0x00000322, 0x0000 },   /* R802   - DMIC3L Control */ 
+       { 0x00000324, 0x0080 },   /* R804   - IN3R Control */ 
+       { 0x00000325, 0x0180 },   /* R805   - ADC Digital Volume 3R */ 
+       { 0x00000326, 0x0000 },   /* R806   - DMIC3R Control */ 
+       { 0x00000400, 0x0000 },   /* R1024  - Output Enables 1 */ 
+       { 0x00000408, 0x0000 },   /* R1032  - Output Rate 1 */ 
+       { 0x00000409, 0x0022 },   /* R1033  - Output Volume Ramp */ 
+       { 0x00000410, 0x0080 },   /* R1040  - Output Path Config 1L */ 
+       { 0x00000411, 0x0180 },   /* R1041  - DAC Digital Volume 1L */ 
+       { 0x00000412, 0x0080 },   /* R1042  - DAC Volume Limit 1L */ 
+       { 0x00000413, 0x0001 },   /* R1043  - Noise Gate Select 1L */ 
+       { 0x00000414, 0x0080 },   /* R1044  - Output Path Config 1R */ 
+       { 0x00000415, 0x0180 },   /* R1045  - DAC Digital Volume 1R */ 
+       { 0x00000416, 0x0080 },   /* R1046  - DAC Volume Limit 1R */ 
+       { 0x00000417, 0x0002 },   /* R1047  - Noise Gate Select 1R */ 
+       { 0x00000418, 0x0080 },   /* R1048  - Output Path Config 2L */ 
+       { 0x00000419, 0x0180 },   /* R1049  - DAC Digital Volume 2L */ 
+       { 0x0000041A, 0x0080 },   /* R1050  - DAC Volume Limit 2L */ 
+       { 0x0000041B, 0x0004 },   /* R1051  - Noise Gate Select 2L */ 
+       { 0x0000041C, 0x0080 },   /* R1052  - Output Path Config 2R */ 
+       { 0x0000041D, 0x0180 },   /* R1053  - DAC Digital Volume 2R */ 
+       { 0x0000041E, 0x0080 },   /* R1054  - DAC Volume Limit 2R */ 
+       { 0x0000041F, 0x0008 },   /* R1055  - Noise Gate Select 2R */ 
+       { 0x00000420, 0x0080 },   /* R1056  - Output Path Config 3L */ 
+       { 0x00000421, 0x0180 },   /* R1057  - DAC Digital Volume 3L */ 
+       { 0x00000422, 0x0080 },   /* R1058  - DAC Volume Limit 3L */ 
+       { 0x00000423, 0x0010 },   /* R1059  - Noise Gate Select 3L */ 
+       { 0x00000424, 0x0080 },   /* R1060  - Output Path Config 3R */ 
+       { 0x00000425, 0x0180 },   /* R1061  - DAC Digital Volume 3R */ 
+       { 0x00000426, 0x0080 },   /* R1062  - DAC Volume Limit 3R */ 
+       { 0x00000428, 0x0000 },   /* R1064  - Output Path Config 4L */ 
+       { 0x00000429, 0x0180 },   /* R1065  - DAC Digital Volume 4L */ 
+       { 0x0000042A, 0x0080 },   /* R1066  - Out Volume 4L */ 
+       { 0x0000042B, 0x0040 },   /* R1067  - Noise Gate Select 4L */ 
+       { 0x0000042C, 0x0000 },   /* R1068  - Output Path Config 4R */ 
+       { 0x0000042D, 0x0180 },   /* R1069  - DAC Digital Volume 4R */ 
+       { 0x0000042E, 0x0080 },   /* R1070  - Out Volume 4R */ 
+       { 0x0000042F, 0x0080 },   /* R1071  - Noise Gate Select 4R */ 
+       { 0x00000430, 0x0000 },   /* R1072  - Output Path Config 5L */ 
+       { 0x00000431, 0x0180 },   /* R1073  - DAC Digital Volume 5L */ 
+       { 0x00000432, 0x0080 },   /* R1074  - DAC Volume Limit 5L */ 
+       { 0x00000433, 0x0100 },   /* R1075  - Noise Gate Select 5L */ 
+       { 0x00000434, 0x0000 },   /* R1076  - Output Path Config 5R */ 
+       { 0x00000435, 0x0180 },   /* R1077  - DAC Digital Volume 5R */ 
+       { 0x00000436, 0x0080 },   /* R1078  - DAC Volume Limit 5R */ 
+       { 0x00000437, 0x0200 },   /* R1079  - Noise Gate Select 5R */ 
+       { 0x00000450, 0x0000 },   /* R1104  - DAC AEC Control 1 */ 
+       { 0x00000458, 0x0001 },   /* R1112  - Noise Gate Control */ 
+       { 0x00000490, 0x0069 },   /* R1168  - PDM SPK1 CTRL 1 */ 
+       { 0x00000491, 0x0000 },   /* R1169  - PDM SPK1 CTRL 2 */ 
+       { 0x000004DC, 0x0000 },   /* R1244  - DAC comp 1 */ 
+       { 0x000004DD, 0x0000 },   /* R1245  - DAC comp 2 */ 
+       { 0x000004DE, 0x0000 },   /* R1246  - DAC comp 3 */ 
+       { 0x000004DF, 0x0000 },   /* R1247  - DAC comp 4 */ 
+       { 0x00000500, 0x000C },   /* R1280  - AIF1 BCLK Ctrl */ 
+       { 0x00000501, 0x0008 },   /* R1281  - AIF1 Tx Pin Ctrl */ 
+       { 0x00000502, 0x0000 },   /* R1282  - AIF1 Rx Pin Ctrl */ 
+       { 0x00000503, 0x0000 },   /* R1283  - AIF1 Rate Ctrl */ 
+       { 0x00000504, 0x0000 },   /* R1284  - AIF1 Format */ 
+       { 0x00000505, 0x0040 },   /* R1285  - AIF1 Tx BCLK Rate */ 
+       { 0x00000506, 0x0040 },   /* R1286  - AIF1 Rx BCLK Rate */ 
+       { 0x00000507, 0x1818 },   /* R1287  - AIF1 Frame Ctrl 1 */ 
+       { 0x00000508, 0x1818 },   /* R1288  - AIF1 Frame Ctrl 2 */ 
+       { 0x00000509, 0x0000 },   /* R1289  - AIF1 Frame Ctrl 3 */ 
+       { 0x0000050A, 0x0001 },   /* R1290  - AIF1 Frame Ctrl 4 */ 
+       { 0x0000050B, 0x0002 },   /* R1291  - AIF1 Frame Ctrl 5 */ 
+       { 0x0000050C, 0x0003 },   /* R1292  - AIF1 Frame Ctrl 6 */ 
+       { 0x0000050D, 0x0004 },   /* R1293  - AIF1 Frame Ctrl 7 */ 
+       { 0x0000050E, 0x0005 },   /* R1294  - AIF1 Frame Ctrl 8 */ 
+       { 0x0000050F, 0x0006 },   /* R1295  - AIF1 Frame Ctrl 9 */ 
+       { 0x00000510, 0x0007 },   /* R1296  - AIF1 Frame Ctrl 10 */ 
+       { 0x00000511, 0x0000 },   /* R1297  - AIF1 Frame Ctrl 11 */ 
+       { 0x00000512, 0x0001 },   /* R1298  - AIF1 Frame Ctrl 12 */ 
+       { 0x00000513, 0x0002 },   /* R1299  - AIF1 Frame Ctrl 13 */ 
+       { 0x00000514, 0x0003 },   /* R1300  - AIF1 Frame Ctrl 14 */ 
+       { 0x00000515, 0x0004 },   /* R1301  - AIF1 Frame Ctrl 15 */ 
+       { 0x00000516, 0x0005 },   /* R1302  - AIF1 Frame Ctrl 16 */ 
+       { 0x00000517, 0x0006 },   /* R1303  - AIF1 Frame Ctrl 17 */ 
+       { 0x00000518, 0x0007 },   /* R1304  - AIF1 Frame Ctrl 18 */ 
+       { 0x00000519, 0x0000 },   /* R1305  - AIF1 Tx Enables */ 
+       { 0x0000051A, 0x0000 },   /* R1306  - AIF1 Rx Enables */ 
+       { 0x0000051B, 0x0000 },   /* R1307  - AIF1 Force Write */ 
+       { 0x00000540, 0x000C },   /* R1344  - AIF2 BCLK Ctrl */ 
+       { 0x00000541, 0x0008 },   /* R1345  - AIF2 Tx Pin Ctrl */ 
+       { 0x00000542, 0x0000 },   /* R1346  - AIF2 Rx Pin Ctrl */ 
+       { 0x00000543, 0x0000 },   /* R1347  - AIF2 Rate Ctrl */ 
+       { 0x00000544, 0x0000 },   /* R1348  - AIF2 Format */ 
+       { 0x00000545, 0x0040 },   /* R1349  - AIF2 Tx BCLK Rate */ 
+       { 0x00000546, 0x0040 },   /* R1350  - AIF2 Rx BCLK Rate */ 
+       { 0x00000547, 0x1818 },   /* R1351  - AIF2 Frame Ctrl 1 */ 
+       { 0x00000548, 0x1818 },   /* R1352  - AIF2 Frame Ctrl 2 */ 
+       { 0x00000549, 0x0000 },   /* R1353  - AIF2 Frame Ctrl 3 */ 
+       { 0x0000054A, 0x0001 },   /* R1354  - AIF2 Frame Ctrl 4 */ 
+       { 0x00000551, 0x0000 },   /* R1361  - AIF2 Frame Ctrl 11 */ 
+       { 0x00000552, 0x0001 },   /* R1362  - AIF2 Frame Ctrl 12 */ 
+       { 0x00000559, 0x0000 },   /* R1369  - AIF2 Tx Enables */ 
+       { 0x0000055A, 0x0000 },   /* R1370  - AIF2 Rx Enables */ 
+       { 0x0000055B, 0x0000 },   /* R1371  - AIF2 Force Write */ 
+       { 0x00000580, 0x000C },   /* R1408  - AIF3 BCLK Ctrl */ 
+       { 0x00000581, 0x0008 },   /* R1409  - AIF3 Tx Pin Ctrl */ 
+       { 0x00000582, 0x0000 },   /* R1410  - AIF3 Rx Pin Ctrl */ 
+       { 0x00000583, 0x0000 },   /* R1411  - AIF3 Rate Ctrl */ 
+       { 0x00000584, 0x0000 },   /* R1412  - AIF3 Format */ 
+       { 0x00000585, 0x0040 },   /* R1413  - AIF3 Tx BCLK Rate */ 
+       { 0x00000586, 0x0040 },   /* R1414  - AIF3 Rx BCLK Rate */ 
+       { 0x00000587, 0x1818 },   /* R1415  - AIF3 Frame Ctrl 1 */ 
+       { 0x00000588, 0x1818 },   /* R1416  - AIF3 Frame Ctrl 2 */ 
+       { 0x00000589, 0x0000 },   /* R1417  - AIF3 Frame Ctrl 3 */ 
+       { 0x0000058A, 0x0001 },   /* R1418  - AIF3 Frame Ctrl 4 */ 
+       { 0x00000591, 0x0000 },   /* R1425  - AIF3 Frame Ctrl 11 */ 
+       { 0x00000592, 0x0001 },   /* R1426  - AIF3 Frame Ctrl 12 */ 
+       { 0x00000599, 0x0000 },   /* R1433  - AIF3 Tx Enables */ 
+       { 0x0000059A, 0x0000 },   /* R1434  - AIF3 Rx Enables */ 
+       { 0x0000059B, 0x0000 },   /* R1435  - AIF3 Force Write */ 
+       { 0x000005E3, 0x0004 },   /* R1507  - SLIMbus Framer Ref Gear */ 
+       { 0x000005E5, 0x0000 },   /* R1509  - SLIMbus Rates 1 */ 
+       { 0x000005E6, 0x0000 },   /* R1510  - SLIMbus Rates 2 */ 
+       { 0x000005E7, 0x0000 },   /* R1511  - SLIMbus Rates 3 */ 
+       { 0x000005E8, 0x0000 },   /* R1512  - SLIMbus Rates 4 */ 
+       { 0x000005E9, 0x0000 },   /* R1513  - SLIMbus Rates 5 */ 
+       { 0x000005EA, 0x0000 },   /* R1514  - SLIMbus Rates 6 */ 
+       { 0x000005EB, 0x0000 },   /* R1515  - SLIMbus Rates 7 */ 
+       { 0x000005EC, 0x0000 },   /* R1516  - SLIMbus Rates 8 */ 
+       { 0x000005F5, 0x0000 },   /* R1525  - SLIMbus RX Channel Enable */ 
+       { 0x000005F6, 0x0000 },   /* R1526  - SLIMbus TX Channel Enable */ 
+       { 0x00000640, 0x0000 },   /* R1600  - PWM1MIX Input 1 Source */ 
+       { 0x00000641, 0x0080 },   /* R1601  - PWM1MIX Input 1 Volume */ 
+       { 0x00000642, 0x0000 },   /* R1602  - PWM1MIX Input 2 Source */ 
+       { 0x00000643, 0x0080 },   /* R1603  - PWM1MIX Input 2 Volume */ 
+       { 0x00000644, 0x0000 },   /* R1604  - PWM1MIX Input 3 Source */ 
+       { 0x00000645, 0x0080 },   /* R1605  - PWM1MIX Input 3 Volume */ 
+       { 0x00000646, 0x0000 },   /* R1606  - PWM1MIX Input 4 Source */ 
+       { 0x00000647, 0x0080 },   /* R1607  - PWM1MIX Input 4 Volume */ 
+       { 0x00000648, 0x0000 },   /* R1608  - PWM2MIX Input 1 Source */ 
+       { 0x00000649, 0x0080 },   /* R1609  - PWM2MIX Input 1 Volume */ 
+       { 0x0000064A, 0x0000 },   /* R1610  - PWM2MIX Input 2 Source */ 
+       { 0x0000064B, 0x0080 },   /* R1611  - PWM2MIX Input 2 Volume */ 
+       { 0x0000064C, 0x0000 },   /* R1612  - PWM2MIX Input 3 Source */ 
+       { 0x0000064D, 0x0080 },   /* R1613  - PWM2MIX Input 3 Volume */ 
+       { 0x0000064E, 0x0000 },   /* R1614  - PWM2MIX Input 4 Source */ 
+       { 0x0000064F, 0x0080 },   /* R1615  - PWM2MIX Input 4 Volume */ 
+       { 0x00000660, 0x0000 },   /* R1632  - MICMIX Input 1 Source */ 
+       { 0x00000661, 0x0080 },   /* R1633  - MICMIX Input 1 Volume */ 
+       { 0x00000662, 0x0000 },   /* R1634  - MICMIX Input 2 Source */ 
+       { 0x00000663, 0x0080 },   /* R1635  - MICMIX Input 2 Volume */ 
+       { 0x00000664, 0x0000 },   /* R1636  - MICMIX Input 3 Source */ 
+       { 0x00000665, 0x0080 },   /* R1637  - MICMIX Input 3 Volume */ 
+       { 0x00000666, 0x0000 },   /* R1638  - MICMIX Input 4 Source */ 
+       { 0x00000667, 0x0080 },   /* R1639  - MICMIX Input 4 Volume */ 
+       { 0x00000668, 0x0000 },   /* R1640  - NOISEMIX Input 1 Source */ 
+       { 0x00000669, 0x0080 },   /* R1641  - NOISEMIX Input 1 Volume */ 
+       { 0x0000066A, 0x0000 },   /* R1642  - NOISEMIX Input 2 Source */ 
+       { 0x0000066B, 0x0080 },   /* R1643  - NOISEMIX Input 2 Volume */ 
+       { 0x0000066C, 0x0000 },   /* R1644  - NOISEMIX Input 3 Source */ 
+       { 0x0000066D, 0x0080 },   /* R1645  - NOISEMIX Input 3 Volume */ 
+       { 0x0000066E, 0x0000 },   /* R1646  - NOISEMIX Input 4 Source */ 
+       { 0x0000066F, 0x0080 },   /* R1647  - NOISEMIX Input 4 Volume */ 
+       { 0x00000680, 0x0000 },   /* R1664  - OUT1LMIX Input 1 Source */ 
+       { 0x00000681, 0x0080 },   /* R1665  - OUT1LMIX Input 1 Volume */ 
+       { 0x00000682, 0x0000 },   /* R1666  - OUT1LMIX Input 2 Source */ 
+       { 0x00000683, 0x0080 },   /* R1667  - OUT1LMIX Input 2 Volume */ 
+       { 0x00000684, 0x0000 },   /* R1668  - OUT1LMIX Input 3 Source */ 
+       { 0x00000685, 0x0080 },   /* R1669  - OUT1LMIX Input 3 Volume */ 
+       { 0x00000686, 0x0000 },   /* R1670  - OUT1LMIX Input 4 Source */ 
+       { 0x00000687, 0x0080 },   /* R1671  - OUT1LMIX Input 4 Volume */ 
+       { 0x00000688, 0x0000 },   /* R1672  - OUT1RMIX Input 1 Source */ 
+       { 0x00000689, 0x0080 },   /* R1673  - OUT1RMIX Input 1 Volume */ 
+       { 0x0000068A, 0x0000 },   /* R1674  - OUT1RMIX Input 2 Source */ 
+       { 0x0000068B, 0x0080 },   /* R1675  - OUT1RMIX Input 2 Volume */ 
+       { 0x0000068C, 0x0000 },   /* R1676  - OUT1RMIX Input 3 Source */ 
+       { 0x0000068D, 0x0080 },   /* R1677  - OUT1RMIX Input 3 Volume */ 
+       { 0x0000068E, 0x0000 },   /* R1678  - OUT1RMIX Input 4 Source */ 
+       { 0x0000068F, 0x0080 },   /* R1679  - OUT1RMIX Input 4 Volume */ 
+       { 0x00000690, 0x0000 },   /* R1680  - OUT2LMIX Input 1 Source */ 
+       { 0x00000691, 0x0080 },   /* R1681  - OUT2LMIX Input 1 Volume */ 
+       { 0x00000692, 0x0000 },   /* R1682  - OUT2LMIX Input 2 Source */ 
+       { 0x00000693, 0x0080 },   /* R1683  - OUT2LMIX Input 2 Volume */ 
+       { 0x00000694, 0x0000 },   /* R1684  - OUT2LMIX Input 3 Source */ 
+       { 0x00000695, 0x0080 },   /* R1685  - OUT2LMIX Input 3 Volume */ 
+       { 0x00000696, 0x0000 },   /* R1686  - OUT2LMIX Input 4 Source */ 
+       { 0x00000697, 0x0080 },   /* R1687  - OUT2LMIX Input 4 Volume */ 
+       { 0x00000698, 0x0000 },   /* R1688  - OUT2RMIX Input 1 Source */ 
+       { 0x00000699, 0x0080 },   /* R1689  - OUT2RMIX Input 1 Volume */ 
+       { 0x0000069A, 0x0000 },   /* R1690  - OUT2RMIX Input 2 Source */ 
+       { 0x0000069B, 0x0080 },   /* R1691  - OUT2RMIX Input 2 Volume */ 
+       { 0x0000069C, 0x0000 },   /* R1692  - OUT2RMIX Input 3 Source */ 
+       { 0x0000069D, 0x0080 },   /* R1693  - OUT2RMIX Input 3 Volume */ 
+       { 0x0000069E, 0x0000 },   /* R1694  - OUT2RMIX Input 4 Source */ 
+       { 0x0000069F, 0x0080 },   /* R1695  - OUT2RMIX Input 4 Volume */ 
+       { 0x000006A0, 0x0000 },   /* R1696  - OUT3LMIX Input 1 Source */ 
+       { 0x000006A1, 0x0080 },   /* R1697  - OUT3LMIX Input 1 Volume */ 
+       { 0x000006A2, 0x0000 },   /* R1698  - OUT3LMIX Input 2 Source */ 
+       { 0x000006A3, 0x0080 },   /* R1699  - OUT3LMIX Input 2 Volume */ 
+       { 0x000006A4, 0x0000 },   /* R1700  - OUT3LMIX Input 3 Source */ 
+       { 0x000006A5, 0x0080 },   /* R1701  - OUT3LMIX Input 3 Volume */ 
+       { 0x000006A6, 0x0000 },   /* R1702  - OUT3LMIX Input 4 Source */ 
+       { 0x000006A7, 0x0080 },   /* R1703  - OUT3LMIX Input 4 Volume */ 
+       { 0x000006B0, 0x0000 },   /* R1712  - OUT4LMIX Input 1 Source */ 
+       { 0x000006B1, 0x0080 },   /* R1713  - OUT4LMIX Input 1 Volume */ 
+       { 0x000006B2, 0x0000 },   /* R1714  - OUT4LMIX Input 2 Source */ 
+       { 0x000006B3, 0x0080 },   /* R1715  - OUT4LMIX Input 2 Volume */ 
+       { 0x000006B4, 0x0000 },   /* R1716  - OUT4LMIX Input 3 Source */ 
+       { 0x000006B5, 0x0080 },   /* R1717  - OUT4LMIX Input 3 Volume */ 
+       { 0x000006B6, 0x0000 },   /* R1718  - OUT4LMIX Input 4 Source */ 
+       { 0x000006B7, 0x0080 },   /* R1719  - OUT4LMIX Input 4 Volume */ 
+       { 0x000006B8, 0x0000 },   /* R1720  - OUT4RMIX Input 1 Source */ 
+       { 0x000006B9, 0x0080 },   /* R1721  - OUT4RMIX Input 1 Volume */ 
+       { 0x000006BA, 0x0000 },   /* R1722  - OUT4RMIX Input 2 Source */ 
+       { 0x000006BB, 0x0080 },   /* R1723  - OUT4RMIX Input 2 Volume */ 
+       { 0x000006BC, 0x0000 },   /* R1724  - OUT4RMIX Input 3 Source */ 
+       { 0x000006BD, 0x0080 },   /* R1725  - OUT4RMIX Input 3 Volume */ 
+       { 0x000006BE, 0x0000 },   /* R1726  - OUT4RMIX Input 4 Source */ 
+       { 0x000006BF, 0x0080 },   /* R1727  - OUT4RMIX Input 4 Volume */ 
+       { 0x000006C0, 0x0000 },   /* R1728  - OUT5LMIX Input 1 Source */ 
+       { 0x000006C1, 0x0080 },   /* R1729  - OUT5LMIX Input 1 Volume */ 
+       { 0x000006C2, 0x0000 },   /* R1730  - OUT5LMIX Input 2 Source */ 
+       { 0x000006C3, 0x0080 },   /* R1731  - OUT5LMIX Input 2 Volume */ 
+       { 0x000006C4, 0x0000 },   /* R1732  - OUT5LMIX Input 3 Source */ 
+       { 0x000006C5, 0x0080 },   /* R1733  - OUT5LMIX Input 3 Volume */ 
+       { 0x000006C6, 0x0000 },   /* R1734  - OUT5LMIX Input 4 Source */ 
+       { 0x000006C7, 0x0080 },   /* R1735  - OUT5LMIX Input 4 Volume */ 
+       { 0x000006C8, 0x0000 },   /* R1736  - OUT5RMIX Input 1 Source */ 
+       { 0x000006C9, 0x0080 },   /* R1737  - OUT5RMIX Input 1 Volume */ 
+       { 0x000006CA, 0x0000 },   /* R1738  - OUT5RMIX Input 2 Source */ 
+       { 0x000006CB, 0x0080 },   /* R1739  - OUT5RMIX Input 2 Volume */ 
+       { 0x000006CC, 0x0000 },   /* R1740  - OUT5RMIX Input 3 Source */ 
+       { 0x000006CD, 0x0080 },   /* R1741  - OUT5RMIX Input 3 Volume */ 
+       { 0x000006CE, 0x0000 },   /* R1742  - OUT5RMIX Input 4 Source */ 
+       { 0x000006CF, 0x0080 },   /* R1743  - OUT5RMIX Input 4 Volume */ 
+       { 0x00000700, 0x0000 },   /* R1792  - AIF1TX1MIX Input 1 Source */ 
+       { 0x00000701, 0x0080 },   /* R1793  - AIF1TX1MIX Input 1 Volume */ 
+       { 0x00000702, 0x0000 },   /* R1794  - AIF1TX1MIX Input 2 Source */ 
+       { 0x00000703, 0x0080 },   /* R1795  - AIF1TX1MIX Input 2 Volume */ 
+       { 0x00000704, 0x0000 },   /* R1796  - AIF1TX1MIX Input 3 Source */ 
+       { 0x00000705, 0x0080 },   /* R1797  - AIF1TX1MIX Input 3 Volume */ 
+       { 0x00000706, 0x0000 },   /* R1798  - AIF1TX1MIX Input 4 Source */ 
+       { 0x00000707, 0x0080 },   /* R1799  - AIF1TX1MIX Input 4 Volume */ 
+       { 0x00000708, 0x0000 },   /* R1800  - AIF1TX2MIX Input 1 Source */ 
+       { 0x00000709, 0x0080 },   /* R1801  - AIF1TX2MIX Input 1 Volume */ 
+       { 0x0000070A, 0x0000 },   /* R1802  - AIF1TX2MIX Input 2 Source */ 
+       { 0x0000070B, 0x0080 },   /* R1803  - AIF1TX2MIX Input 2 Volume */ 
+       { 0x0000070C, 0x0000 },   /* R1804  - AIF1TX2MIX Input 3 Source */ 
+       { 0x0000070D, 0x0080 },   /* R1805  - AIF1TX2MIX Input 3 Volume */ 
+       { 0x0000070E, 0x0000 },   /* R1806  - AIF1TX2MIX Input 4 Source */ 
+       { 0x0000070F, 0x0080 },   /* R1807  - AIF1TX2MIX Input 4 Volume */ 
+       { 0x00000710, 0x0000 },   /* R1808  - AIF1TX3MIX Input 1 Source */ 
+       { 0x00000711, 0x0080 },   /* R1809  - AIF1TX3MIX Input 1 Volume */ 
+       { 0x00000712, 0x0000 },   /* R1810  - AIF1TX3MIX Input 2 Source */ 
+       { 0x00000713, 0x0080 },   /* R1811  - AIF1TX3MIX Input 2 Volume */ 
+       { 0x00000714, 0x0000 },   /* R1812  - AIF1TX3MIX Input 3 Source */ 
+       { 0x00000715, 0x0080 },   /* R1813  - AIF1TX3MIX Input 3 Volume */ 
+       { 0x00000716, 0x0000 },   /* R1814  - AIF1TX3MIX Input 4 Source */ 
+       { 0x00000717, 0x0080 },   /* R1815  - AIF1TX3MIX Input 4 Volume */ 
+       { 0x00000718, 0x0000 },   /* R1816  - AIF1TX4MIX Input 1 Source */ 
+       { 0x00000719, 0x0080 },   /* R1817  - AIF1TX4MIX Input 1 Volume */ 
+       { 0x0000071A, 0x0000 },   /* R1818  - AIF1TX4MIX Input 2 Source */ 
+       { 0x0000071B, 0x0080 },   /* R1819  - AIF1TX4MIX Input 2 Volume */ 
+       { 0x0000071C, 0x0000 },   /* R1820  - AIF1TX4MIX Input 3 Source */ 
+       { 0x0000071D, 0x0080 },   /* R1821  - AIF1TX4MIX Input 3 Volume */ 
+       { 0x0000071E, 0x0000 },   /* R1822  - AIF1TX4MIX Input 4 Source */ 
+       { 0x0000071F, 0x0080 },   /* R1823  - AIF1TX4MIX Input 4 Volume */ 
+       { 0x00000720, 0x0000 },   /* R1824  - AIF1TX5MIX Input 1 Source */ 
+       { 0x00000721, 0x0080 },   /* R1825  - AIF1TX5MIX Input 1 Volume */ 
+       { 0x00000722, 0x0000 },   /* R1826  - AIF1TX5MIX Input 2 Source */ 
+       { 0x00000723, 0x0080 },   /* R1827  - AIF1TX5MIX Input 2 Volume */ 
+       { 0x00000724, 0x0000 },   /* R1828  - AIF1TX5MIX Input 3 Source */ 
+       { 0x00000725, 0x0080 },   /* R1829  - AIF1TX5MIX Input 3 Volume */ 
+       { 0x00000726, 0x0000 },   /* R1830  - AIF1TX5MIX Input 4 Source */ 
+       { 0x00000727, 0x0080 },   /* R1831  - AIF1TX5MIX Input 4 Volume */ 
+       { 0x00000728, 0x0000 },   /* R1832  - AIF1TX6MIX Input 1 Source */ 
+       { 0x00000729, 0x0080 },   /* R1833  - AIF1TX6MIX Input 1 Volume */ 
+       { 0x0000072A, 0x0000 },   /* R1834  - AIF1TX6MIX Input 2 Source */ 
+       { 0x0000072B, 0x0080 },   /* R1835  - AIF1TX6MIX Input 2 Volume */ 
+       { 0x0000072C, 0x0000 },   /* R1836  - AIF1TX6MIX Input 3 Source */ 
+       { 0x0000072D, 0x0080 },   /* R1837  - AIF1TX6MIX Input 3 Volume */ 
+       { 0x0000072E, 0x0000 },   /* R1838  - AIF1TX6MIX Input 4 Source */ 
+       { 0x0000072F, 0x0080 },   /* R1839  - AIF1TX6MIX Input 4 Volume */ 
+       { 0x00000730, 0x0000 },   /* R1840  - AIF1TX7MIX Input 1 Source */ 
+       { 0x00000731, 0x0080 },   /* R1841  - AIF1TX7MIX Input 1 Volume */ 
+       { 0x00000732, 0x0000 },   /* R1842  - AIF1TX7MIX Input 2 Source */ 
+       { 0x00000733, 0x0080 },   /* R1843  - AIF1TX7MIX Input 2 Volume */ 
+       { 0x00000734, 0x0000 },   /* R1844  - AIF1TX7MIX Input 3 Source */ 
+       { 0x00000735, 0x0080 },   /* R1845  - AIF1TX7MIX Input 3 Volume */ 
+       { 0x00000736, 0x0000 },   /* R1846  - AIF1TX7MIX Input 4 Source */ 
+       { 0x00000737, 0x0080 },   /* R1847  - AIF1TX7MIX Input 4 Volume */ 
+       { 0x00000738, 0x0000 },   /* R1848  - AIF1TX8MIX Input 1 Source */ 
+       { 0x00000739, 0x0080 },   /* R1849  - AIF1TX8MIX Input 1 Volume */ 
+       { 0x0000073A, 0x0000 },   /* R1850  - AIF1TX8MIX Input 2 Source */ 
+       { 0x0000073B, 0x0080 },   /* R1851  - AIF1TX8MIX Input 2 Volume */ 
+       { 0x0000073C, 0x0000 },   /* R1852  - AIF1TX8MIX Input 3 Source */ 
+       { 0x0000073D, 0x0080 },   /* R1853  - AIF1TX8MIX Input 3 Volume */ 
+       { 0x0000073E, 0x0000 },   /* R1854  - AIF1TX8MIX Input 4 Source */ 
+       { 0x0000073F, 0x0080 },   /* R1855  - AIF1TX8MIX Input 4 Volume */ 
+       { 0x00000740, 0x0000 },   /* R1856  - AIF2TX1MIX Input 1 Source */ 
+       { 0x00000741, 0x0080 },   /* R1857  - AIF2TX1MIX Input 1 Volume */ 
+       { 0x00000742, 0x0000 },   /* R1858  - AIF2TX1MIX Input 2 Source */ 
+       { 0x00000743, 0x0080 },   /* R1859  - AIF2TX1MIX Input 2 Volume */ 
+       { 0x00000744, 0x0000 },   /* R1860  - AIF2TX1MIX Input 3 Source */ 
+       { 0x00000745, 0x0080 },   /* R1861  - AIF2TX1MIX Input 3 Volume */ 
+       { 0x00000746, 0x0000 },   /* R1862  - AIF2TX1MIX Input 4 Source */ 
+       { 0x00000747, 0x0080 },   /* R1863  - AIF2TX1MIX Input 4 Volume */ 
+       { 0x00000748, 0x0000 },   /* R1864  - AIF2TX2MIX Input 1 Source */ 
+       { 0x00000749, 0x0080 },   /* R1865  - AIF2TX2MIX Input 1 Volume */ 
+       { 0x0000074A, 0x0000 },   /* R1866  - AIF2TX2MIX Input 2 Source */ 
+       { 0x0000074B, 0x0080 },   /* R1867  - AIF2TX2MIX Input 2 Volume */ 
+       { 0x0000074C, 0x0000 },   /* R1868  - AIF2TX2MIX Input 3 Source */ 
+       { 0x0000074D, 0x0080 },   /* R1869  - AIF2TX2MIX Input 3 Volume */ 
+       { 0x0000074E, 0x0000 },   /* R1870  - AIF2TX2MIX Input 4 Source */ 
+       { 0x0000074F, 0x0080 },   /* R1871  - AIF2TX2MIX Input 4 Volume */ 
+       { 0x00000780, 0x0000 },   /* R1920  - AIF3TX1MIX Input 1 Source */ 
+       { 0x00000781, 0x0080 },   /* R1921  - AIF3TX1MIX Input 1 Volume */ 
+       { 0x00000782, 0x0000 },   /* R1922  - AIF3TX1MIX Input 2 Source */ 
+       { 0x00000783, 0x0080 },   /* R1923  - AIF3TX1MIX Input 2 Volume */ 
+       { 0x00000784, 0x0000 },   /* R1924  - AIF3TX1MIX Input 3 Source */ 
+       { 0x00000785, 0x0080 },   /* R1925  - AIF3TX1MIX Input 3 Volume */ 
+       { 0x00000786, 0x0000 },   /* R1926  - AIF3TX1MIX Input 4 Source */ 
+       { 0x00000787, 0x0080 },   /* R1927  - AIF3TX1MIX Input 4 Volume */ 
+       { 0x00000788, 0x0000 },   /* R1928  - AIF3TX2MIX Input 1 Source */ 
+       { 0x00000789, 0x0080 },   /* R1929  - AIF3TX2MIX Input 1 Volume */ 
+       { 0x0000078A, 0x0000 },   /* R1930  - AIF3TX2MIX Input 2 Source */ 
+       { 0x0000078B, 0x0080 },   /* R1931  - AIF3TX2MIX Input 2 Volume */ 
+       { 0x0000078C, 0x0000 },   /* R1932  - AIF3TX2MIX Input 3 Source */ 
+       { 0x0000078D, 0x0080 },   /* R1933  - AIF3TX2MIX Input 3 Volume */ 
+       { 0x0000078E, 0x0000 },   /* R1934  - AIF3TX2MIX Input 4 Source */ 
+       { 0x0000078F, 0x0080 },   /* R1935  - AIF3TX2MIX Input 4 Volume */ 
+       { 0x000007C0, 0x0000 },   /* R1984  - SLIMTX1MIX Input 1 Source */ 
+       { 0x000007C1, 0x0080 },   /* R1985  - SLIMTX1MIX Input 1 Volume */ 
+       { 0x000007C2, 0x0000 },   /* R1986  - SLIMTX1MIX Input 2 Source */ 
+       { 0x000007C3, 0x0080 },   /* R1987  - SLIMTX1MIX Input 2 Volume */ 
+       { 0x000007C4, 0x0000 },   /* R1988  - SLIMTX1MIX Input 3 Source */ 
+       { 0x000007C5, 0x0080 },   /* R1989  - SLIMTX1MIX Input 3 Volume */ 
+       { 0x000007C6, 0x0000 },   /* R1990  - SLIMTX1MIX Input 4 Source */ 
+       { 0x000007C7, 0x0080 },   /* R1991  - SLIMTX1MIX Input 4 Volume */ 
+       { 0x000007C8, 0x0000 },   /* R1992  - SLIMTX2MIX Input 1 Source */ 
+       { 0x000007C9, 0x0080 },   /* R1993  - SLIMTX2MIX Input 1 Volume */ 
+       { 0x000007CA, 0x0000 },   /* R1994  - SLIMTX2MIX Input 2 Source */ 
+       { 0x000007CB, 0x0080 },   /* R1995  - SLIMTX2MIX Input 2 Volume */ 
+       { 0x000007CC, 0x0000 },   /* R1996  - SLIMTX2MIX Input 3 Source */ 
+       { 0x000007CD, 0x0080 },   /* R1997  - SLIMTX2MIX Input 3 Volume */ 
+       { 0x000007CE, 0x0000 },   /* R1998  - SLIMTX2MIX Input 4 Source */ 
+       { 0x000007CF, 0x0080 },   /* R1999  - SLIMTX2MIX Input 4 Volume */ 
+       { 0x000007D0, 0x0000 },   /* R2000  - SLIMTX3MIX Input 1 Source */ 
+       { 0x000007D1, 0x0080 },   /* R2001  - SLIMTX3MIX Input 1 Volume */ 
+       { 0x000007D2, 0x0000 },   /* R2002  - SLIMTX3MIX Input 2 Source */ 
+       { 0x000007D3, 0x0080 },   /* R2003  - SLIMTX3MIX Input 2 Volume */ 
+       { 0x000007D4, 0x0000 },   /* R2004  - SLIMTX3MIX Input 3 Source */ 
+       { 0x000007D5, 0x0080 },   /* R2005  - SLIMTX3MIX Input 3 Volume */ 
+       { 0x000007D6, 0x0000 },   /* R2006  - SLIMTX3MIX Input 4 Source */ 
+       { 0x000007D7, 0x0080 },   /* R2007  - SLIMTX3MIX Input 4 Volume */ 
+       { 0x000007D8, 0x0000 },   /* R2008  - SLIMTX4MIX Input 1 Source */ 
+       { 0x000007D9, 0x0080 },   /* R2009  - SLIMTX4MIX Input 1 Volume */ 
+       { 0x000007DA, 0x0000 },   /* R2010  - SLIMTX4MIX Input 2 Source */ 
+       { 0x000007DB, 0x0080 },   /* R2011  - SLIMTX4MIX Input 2 Volume */ 
+       { 0x000007DC, 0x0000 },   /* R2012  - SLIMTX4MIX Input 3 Source */ 
+       { 0x000007DD, 0x0080 },   /* R2013  - SLIMTX4MIX Input 3 Volume */ 
+       { 0x000007DE, 0x0000 },   /* R2014  - SLIMTX4MIX Input 4 Source */ 
+       { 0x000007DF, 0x0080 },   /* R2015  - SLIMTX4MIX Input 4 Volume */ 
+       { 0x000007E0, 0x0000 },   /* R2016  - SLIMTX5MIX Input 1 Source */ 
+       { 0x000007E1, 0x0080 },   /* R2017  - SLIMTX5MIX Input 1 Volume */ 
+       { 0x000007E2, 0x0000 },   /* R2018  - SLIMTX5MIX Input 2 Source */ 
+       { 0x000007E3, 0x0080 },   /* R2019  - SLIMTX5MIX Input 2 Volume */ 
+       { 0x000007E4, 0x0000 },   /* R2020  - SLIMTX5MIX Input 3 Source */ 
+       { 0x000007E5, 0x0080 },   /* R2021  - SLIMTX5MIX Input 3 Volume */ 
+       { 0x000007E6, 0x0000 },   /* R2022  - SLIMTX5MIX Input 4 Source */ 
+       { 0x000007E7, 0x0080 },   /* R2023  - SLIMTX5MIX Input 4 Volume */ 
+       { 0x000007E8, 0x0000 },   /* R2024  - SLIMTX6MIX Input 1 Source */ 
+       { 0x000007E9, 0x0080 },   /* R2025  - SLIMTX6MIX Input 1 Volume */ 
+       { 0x000007EA, 0x0000 },   /* R2026  - SLIMTX6MIX Input 2 Source */ 
+       { 0x000007EB, 0x0080 },   /* R2027  - SLIMTX6MIX Input 2 Volume */ 
+       { 0x000007EC, 0x0000 },   /* R2028  - SLIMTX6MIX Input 3 Source */ 
+       { 0x000007ED, 0x0080 },   /* R2029  - SLIMTX6MIX Input 3 Volume */ 
+       { 0x000007EE, 0x0000 },   /* R2030  - SLIMTX6MIX Input 4 Source */ 
+       { 0x000007EF, 0x0080 },   /* R2031  - SLIMTX6MIX Input 4 Volume */ 
+       { 0x000007F0, 0x0000 },   /* R2032  - SLIMTX7MIX Input 1 Source */ 
+       { 0x000007F1, 0x0080 },   /* R2033  - SLIMTX7MIX Input 1 Volume */ 
+       { 0x000007F2, 0x0000 },   /* R2034  - SLIMTX7MIX Input 2 Source */ 
+       { 0x000007F3, 0x0080 },   /* R2035  - SLIMTX7MIX Input 2 Volume */ 
+       { 0x000007F4, 0x0000 },   /* R2036  - SLIMTX7MIX Input 3 Source */ 
+       { 0x000007F5, 0x0080 },   /* R2037  - SLIMTX7MIX Input 3 Volume */ 
+       { 0x000007F6, 0x0000 },   /* R2038  - SLIMTX7MIX Input 4 Source */ 
+       { 0x000007F7, 0x0080 },   /* R2039  - SLIMTX7MIX Input 4 Volume */ 
+       { 0x000007F8, 0x0000 },   /* R2040  - SLIMTX8MIX Input 1 Source */ 
+       { 0x000007F9, 0x0080 },   /* R2041  - SLIMTX8MIX Input 1 Volume */ 
+       { 0x000007FA, 0x0000 },   /* R2042  - SLIMTX8MIX Input 2 Source */ 
+       { 0x000007FB, 0x0080 },   /* R2043  - SLIMTX8MIX Input 2 Volume */ 
+       { 0x000007FC, 0x0000 },   /* R2044  - SLIMTX8MIX Input 3 Source */ 
+       { 0x000007FD, 0x0080 },   /* R2045  - SLIMTX8MIX Input 3 Volume */ 
+       { 0x000007FE, 0x0000 },   /* R2046  - SLIMTX8MIX Input 4 Source */ 
+       { 0x000007FF, 0x0080 },   /* R2047  - SLIMTX8MIX Input 4 Volume */ 
+       { 0x00000880, 0x0000 },   /* R2176  - EQ1MIX Input 1 Source */ 
+       { 0x00000881, 0x0080 },   /* R2177  - EQ1MIX Input 1 Volume */ 
+       { 0x00000882, 0x0000 },   /* R2178  - EQ1MIX Input 2 Source */ 
+       { 0x00000883, 0x0080 },   /* R2179  - EQ1MIX Input 2 Volume */ 
+       { 0x00000884, 0x0000 },   /* R2180  - EQ1MIX Input 3 Source */ 
+       { 0x00000885, 0x0080 },   /* R2181  - EQ1MIX Input 3 Volume */ 
+       { 0x00000886, 0x0000 },   /* R2182  - EQ1MIX Input 4 Source */ 
+       { 0x00000887, 0x0080 },   /* R2183  - EQ1MIX Input 4 Volume */ 
+       { 0x00000888, 0x0000 },   /* R2184  - EQ2MIX Input 1 Source */ 
+       { 0x00000889, 0x0080 },   /* R2185  - EQ2MIX Input 1 Volume */ 
+       { 0x0000088A, 0x0000 },   /* R2186  - EQ2MIX Input 2 Source */ 
+       { 0x0000088B, 0x0080 },   /* R2187  - EQ2MIX Input 2 Volume */ 
+       { 0x0000088C, 0x0000 },   /* R2188  - EQ2MIX Input 3 Source */ 
+       { 0x0000088D, 0x0080 },   /* R2189  - EQ2MIX Input 3 Volume */ 
+       { 0x0000088E, 0x0000 },   /* R2190  - EQ2MIX Input 4 Source */ 
+       { 0x0000088F, 0x0080 },   /* R2191  - EQ2MIX Input 4 Volume */ 
+       { 0x00000890, 0x0000 },   /* R2192  - EQ3MIX Input 1 Source */ 
+       { 0x00000891, 0x0080 },   /* R2193  - EQ3MIX Input 1 Volume */ 
+       { 0x00000892, 0x0000 },   /* R2194  - EQ3MIX Input 2 Source */ 
+       { 0x00000893, 0x0080 },   /* R2195  - EQ3MIX Input 2 Volume */ 
+       { 0x00000894, 0x0000 },   /* R2196  - EQ3MIX Input 3 Source */ 
+       { 0x00000895, 0x0080 },   /* R2197  - EQ3MIX Input 3 Volume */ 
+       { 0x00000896, 0x0000 },   /* R2198  - EQ3MIX Input 4 Source */ 
+       { 0x00000897, 0x0080 },   /* R2199  - EQ3MIX Input 4 Volume */ 
+       { 0x00000898, 0x0000 },   /* R2200  - EQ4MIX Input 1 Source */ 
+       { 0x00000899, 0x0080 },   /* R2201  - EQ4MIX Input 1 Volume */ 
+       { 0x0000089A, 0x0000 },   /* R2202  - EQ4MIX Input 2 Source */ 
+       { 0x0000089B, 0x0080 },   /* R2203  - EQ4MIX Input 2 Volume */ 
+       { 0x0000089C, 0x0000 },   /* R2204  - EQ4MIX Input 3 Source */ 
+       { 0x0000089D, 0x0080 },   /* R2205  - EQ4MIX Input 3 Volume */ 
+       { 0x0000089E, 0x0000 },   /* R2206  - EQ4MIX Input 4 Source */ 
+       { 0x0000089F, 0x0080 },   /* R2207  - EQ4MIX Input 4 Volume */ 
+       { 0x000008C0, 0x0000 },   /* R2240  - DRC1LMIX Input 1 Source */ 
+       { 0x000008C1, 0x0080 },   /* R2241  - DRC1LMIX Input 1 Volume */ 
+       { 0x000008C2, 0x0000 },   /* R2242  - DRC1LMIX Input 2 Source */ 
+       { 0x000008C3, 0x0080 },   /* R2243  - DRC1LMIX Input 2 Volume */ 
+       { 0x000008C4, 0x0000 },   /* R2244  - DRC1LMIX Input 3 Source */ 
+       { 0x000008C5, 0x0080 },   /* R2245  - DRC1LMIX Input 3 Volume */ 
+       { 0x000008C6, 0x0000 },   /* R2246  - DRC1LMIX Input 4 Source */ 
+       { 0x000008C7, 0x0080 },   /* R2247  - DRC1LMIX Input 4 Volume */ 
+       { 0x000008C8, 0x0000 },   /* R2248  - DRC1RMIX Input 1 Source */ 
+       { 0x000008C9, 0x0080 },   /* R2249  - DRC1RMIX Input 1 Volume */ 
+       { 0x000008CA, 0x0000 },   /* R2250  - DRC1RMIX Input 2 Source */ 
+       { 0x000008CB, 0x0080 },   /* R2251  - DRC1RMIX Input 2 Volume */ 
+       { 0x000008CC, 0x0000 },   /* R2252  - DRC1RMIX Input 3 Source */ 
+       { 0x000008CD, 0x0080 },   /* R2253  - DRC1RMIX Input 3 Volume */ 
+       { 0x000008CE, 0x0000 },   /* R2254  - DRC1RMIX Input 4 Source */ 
+       { 0x000008CF, 0x0080 },   /* R2255  - DRC1RMIX Input 4 Volume */ 
+       { 0x000008D0, 0x0000 },   /* R2256  - DRC2LMIX Input 1 Source */ 
+       { 0x000008D1, 0x0080 },   /* R2257  - DRC2LMIX Input 1 Volume */ 
+       { 0x000008D2, 0x0000 },   /* R2258  - DRC2LMIX Input 2 Source */ 
+       { 0x000008D3, 0x0080 },   /* R2259  - DRC2LMIX Input 2 Volume */ 
+       { 0x000008D4, 0x0000 },   /* R2260  - DRC2LMIX Input 3 Source */ 
+       { 0x000008D5, 0x0080 },   /* R2261  - DRC2LMIX Input 3 Volume */ 
+       { 0x000008D6, 0x0000 },   /* R2262  - DRC2LMIX Input 4 Source */ 
+       { 0x000008D7, 0x0080 },   /* R2263  - DRC2LMIX Input 4 Volume */ 
+       { 0x000008D8, 0x0000 },   /* R2264  - DRC2RMIX Input 1 Source */ 
+       { 0x000008D9, 0x0080 },   /* R2265  - DRC2RMIX Input 1 Volume */ 
+       { 0x000008DA, 0x0000 },   /* R2266  - DRC2RMIX Input 2 Source */ 
+       { 0x000008DB, 0x0080 },   /* R2267  - DRC2RMIX Input 2 Volume */ 
+       { 0x000008DC, 0x0000 },   /* R2268  - DRC2RMIX Input 3 Source */ 
+       { 0x000008DD, 0x0080 },   /* R2269  - DRC2RMIX Input 3 Volume */ 
+       { 0x000008DE, 0x0000 },   /* R2270  - DRC2RMIX Input 4 Source */ 
+       { 0x000008DF, 0x0080 },   /* R2271  - DRC2RMIX Input 4 Volume */ 
+       { 0x00000900, 0x0000 },   /* R2304  - HPLP1MIX Input 1 Source */ 
+       { 0x00000901, 0x0080 },   /* R2305  - HPLP1MIX Input 1 Volume */ 
+       { 0x00000902, 0x0000 },   /* R2306  - HPLP1MIX Input 2 Source */ 
+       { 0x00000903, 0x0080 },   /* R2307  - HPLP1MIX Input 2 Volume */ 
+       { 0x00000904, 0x0000 },   /* R2308  - HPLP1MIX Input 3 Source */ 
+       { 0x00000905, 0x0080 },   /* R2309  - HPLP1MIX Input 3 Volume */ 
+       { 0x00000906, 0x0000 },   /* R2310  - HPLP1MIX Input 4 Source */ 
+       { 0x00000907, 0x0080 },   /* R2311  - HPLP1MIX Input 4 Volume */ 
+       { 0x00000908, 0x0000 },   /* R2312  - HPLP2MIX Input 1 Source */ 
+       { 0x00000909, 0x0080 },   /* R2313  - HPLP2MIX Input 1 Volume */ 
+       { 0x0000090A, 0x0000 },   /* R2314  - HPLP2MIX Input 2 Source */ 
+       { 0x0000090B, 0x0080 },   /* R2315  - HPLP2MIX Input 2 Volume */ 
+       { 0x0000090C, 0x0000 },   /* R2316  - HPLP2MIX Input 3 Source */ 
+       { 0x0000090D, 0x0080 },   /* R2317  - HPLP2MIX Input 3 Volume */ 
+       { 0x0000090E, 0x0000 },   /* R2318  - HPLP2MIX Input 4 Source */ 
+       { 0x0000090F, 0x0080 },   /* R2319  - HPLP2MIX Input 4 Volume */ 
+       { 0x00000910, 0x0000 },   /* R2320  - HPLP3MIX Input 1 Source */ 
+       { 0x00000911, 0x0080 },   /* R2321  - HPLP3MIX Input 1 Volume */ 
+       { 0x00000912, 0x0000 },   /* R2322  - HPLP3MIX Input 2 Source */ 
+       { 0x00000913, 0x0080 },   /* R2323  - HPLP3MIX Input 2 Volume */ 
+       { 0x00000914, 0x0000 },   /* R2324  - HPLP3MIX Input 3 Source */ 
+       { 0x00000915, 0x0080 },   /* R2325  - HPLP3MIX Input 3 Volume */ 
+       { 0x00000916, 0x0000 },   /* R2326  - HPLP3MIX Input 4 Source */ 
+       { 0x00000917, 0x0080 },   /* R2327  - HPLP3MIX Input 4 Volume */ 
+       { 0x00000918, 0x0000 },   /* R2328  - HPLP4MIX Input 1 Source */ 
+       { 0x00000919, 0x0080 },   /* R2329  - HPLP4MIX Input 1 Volume */ 
+       { 0x0000091A, 0x0000 },   /* R2330  - HPLP4MIX Input 2 Source */ 
+       { 0x0000091B, 0x0080 },   /* R2331  - HPLP4MIX Input 2 Volume */ 
+       { 0x0000091C, 0x0000 },   /* R2332  - HPLP4MIX Input 3 Source */ 
+       { 0x0000091D, 0x0080 },   /* R2333  - HPLP4MIX Input 3 Volume */ 
+       { 0x0000091E, 0x0000 },   /* R2334  - HPLP4MIX Input 4 Source */ 
+       { 0x0000091F, 0x0080 },   /* R2335  - HPLP4MIX Input 4 Volume */ 
+       { 0x00000940, 0x0000 },   /* R2368  - DSP1LMIX Input 1 Source */ 
+       { 0x00000941, 0x0080 },   /* R2369  - DSP1LMIX Input 1 Volume */ 
+       { 0x00000942, 0x0000 },   /* R2370  - DSP1LMIX Input 2 Source */ 
+       { 0x00000943, 0x0080 },   /* R2371  - DSP1LMIX Input 2 Volume */ 
+       { 0x00000944, 0x0000 },   /* R2372  - DSP1LMIX Input 3 Source */ 
+       { 0x00000945, 0x0080 },   /* R2373  - DSP1LMIX Input 3 Volume */ 
+       { 0x00000946, 0x0000 },   /* R2374  - DSP1LMIX Input 4 Source */ 
+       { 0x00000947, 0x0080 },   /* R2375  - DSP1LMIX Input 4 Volume */ 
+       { 0x00000948, 0x0000 },   /* R2376  - DSP1RMIX Input 1 Source */ 
+       { 0x00000949, 0x0080 },   /* R2377  - DSP1RMIX Input 1 Volume */ 
+       { 0x0000094A, 0x0000 },   /* R2378  - DSP1RMIX Input 2 Source */ 
+       { 0x0000094B, 0x0080 },   /* R2379  - DSP1RMIX Input 2 Volume */ 
+       { 0x0000094C, 0x0000 },   /* R2380  - DSP1RMIX Input 3 Source */ 
+       { 0x0000094D, 0x0080 },   /* R2381  - DSP1RMIX Input 3 Volume */ 
+       { 0x0000094E, 0x0000 },   /* R2382  - DSP1RMIX Input 4 Source */ 
+       { 0x0000094F, 0x0080 },   /* R2383  - DSP1RMIX Input 4 Volume */ 
+       { 0x00000950, 0x0000 },   /* R2384  - DSP1AUX1MIX Input 1 Source */ 
+       { 0x00000958, 0x0000 },   /* R2392  - DSP1AUX2MIX Input 1 Source */ 
+       { 0x00000960, 0x0000 },   /* R2400  - DSP1AUX3MIX Input 1 Source */ 
+       { 0x00000968, 0x0000 },   /* R2408  - DSP1AUX4MIX Input 1 Source */ 
+       { 0x00000970, 0x0000 },   /* R2416  - DSP1AUX5MIX Input 1 Source */ 
+       { 0x00000978, 0x0000 },   /* R2424  - DSP1AUX6MIX Input 1 Source */ 
+       { 0x00000A80, 0x0000 },   /* R2688  - ASRC1LMIX Input 1 Source */ 
+       { 0x00000A88, 0x0000 },   /* R2696  - ASRC1RMIX Input 1 Source */ 
+       { 0x00000A90, 0x0000 },   /* R2704  - ASRC2LMIX Input 1 Source */ 
+       { 0x00000A98, 0x0000 },   /* R2712  - ASRC2RMIX Input 1 Source */ 
+       { 0x00000B00, 0x0000 },   /* R2816  - ISRC1DEC1MIX Input 1 Source */ 
+       { 0x00000B08, 0x0000 },   /* R2824  - ISRC1DEC2MIX Input 1 Source */ 
+       { 0x00000B20, 0x0000 },   /* R2848  - ISRC1INT1MIX Input 1 Source */ 
+       { 0x00000B28, 0x0000 },   /* R2856  - ISRC1INT2MIX Input 1 Source */ 
+       { 0x00000B40, 0x0000 },   /* R2880  - ISRC2DEC1MIX Input 1 Source */ 
+       { 0x00000B48, 0x0000 },   /* R2888  - ISRC2DEC2MIX Input 1 Source */ 
+       { 0x00000B60, 0x0000 },   /* R2912  - ISRC2INT1MIX Input 1 Source */ 
+       { 0x00000B68, 0x0000 },   /* R2920  - ISRC2INT2MIX Input 1 Source */ 
+       { 0x00000C00, 0xA101 },   /* R3072  - GPIO1 CTRL */ 
+       { 0x00000C01, 0xA101 },   /* R3073  - GPIO2 CTRL */ 
+       { 0x00000C02, 0xA101 },   /* R3074  - GPIO3 CTRL */ 
+       { 0x00000C03, 0xA101 },   /* R3075  - GPIO4 CTRL */ 
+       { 0x00000C04, 0xA101 },   /* R3076  - GPIO5 CTRL */ 
+       { 0x00000C0F, 0x0400 },   /* R3087  - IRQ CTRL 1 */ 
+       { 0x00000C10, 0x1000 },   /* R3088  - GPIO Debounce Config */ 
+       { 0x00000C20, 0x8002 },   /* R3104  - Misc Pad Ctrl 1 */ 
+       { 0x00000C21, 0x8001 },   /* R3105  - Misc Pad Ctrl 2 */ 
+       { 0x00000C22, 0x0000 },   /* R3106  - Misc Pad Ctrl 3 */ 
+       { 0x00000C23, 0x0000 },   /* R3107  - Misc Pad Ctrl 4 */ 
+       { 0x00000C24, 0x0000 },   /* R3108  - Misc Pad Ctrl 5 */ 
+       { 0x00000C25, 0x0000 },   /* R3109  - Misc Pad Ctrl 6 */ 
+       { 0x00000D08, 0xFFFF },   /* R3336  - Interrupt Status 1 Mask */ 
+       { 0x00000D09, 0xFFFF },   /* R3337  - Interrupt Status 2 Mask */ 
+       { 0x00000D0A, 0xFFFF },   /* R3338  - Interrupt Status 3 Mask */ 
+       { 0x00000D0B, 0xFFFF },   /* R3339  - Interrupt Status 4 Mask */ 
+       { 0x00000D0C, 0xFEFF },   /* R3340  - Interrupt Status 5 Mask */ 
+       { 0x00000D0F, 0x0000 },   /* R3343  - Interrupt Control */ 
+       { 0x00000D18, 0xFFFF },   /* R3352  - IRQ2 Status 1 Mask */ 
+       { 0x00000D19, 0xFFFF },   /* R3353  - IRQ2 Status 2 Mask */ 
+       { 0x00000D1A, 0xFFFF },   /* R3354  - IRQ2 Status 3 Mask */ 
+       { 0x00000D1B, 0xFFFF },   /* R3355  - IRQ2 Status 4 Mask */ 
+       { 0x00000D1C, 0xFFFF },   /* R3356  - IRQ2 Status 5 Mask */ 
+       { 0x00000D1F, 0x0000 },   /* R3359  - IRQ2 Control */ 
+       { 0x00000D41, 0x0000 },   /* R3393  - ADSP2 IRQ0 */ 
+       { 0x00000D53, 0xFFFF },   /* R3411  - AOD IRQ Mask IRQ1 */ 
+       { 0x00000D54, 0xFFFF },   /* R3412  - AOD IRQ Mask IRQ2 */ 
+       { 0x00000D56, 0x0000 },   /* R3414  - Jack detect debounce */ 
+       { 0x00000E00, 0x0000 },   /* R3584  - FX_Ctrl1 */ 
+       { 0x00000E01, 0x0000 },   /* R3585  - FX_Ctrl2 */ 
+       { 0x00000E10, 0x6318 },   /* R3600  - EQ1_1 */ 
+       { 0x00000E11, 0x6300 },   /* R3601  - EQ1_2 */ 
+       { 0x00000E12, 0x0FC8 },   /* R3602  - EQ1_3 */ 
+       { 0x00000E13, 0x03FE },   /* R3603  - EQ1_4 */ 
+       { 0x00000E14, 0x00E0 },   /* R3604  - EQ1_5 */ 
+       { 0x00000E15, 0x1EC4 },   /* R3605  - EQ1_6 */ 
+       { 0x00000E16, 0xF136 },   /* R3606  - EQ1_7 */ 
+       { 0x00000E17, 0x0409 },   /* R3607  - EQ1_8 */ 
+       { 0x00000E18, 0x04CC },   /* R3608  - EQ1_9 */ 
+       { 0x00000E19, 0x1C9B },   /* R3609  - EQ1_10 */ 
+       { 0x00000E1A, 0xF337 },   /* R3610  - EQ1_11 */ 
+       { 0x00000E1B, 0x040B },   /* R3611  - EQ1_12 */ 
+       { 0x00000E1C, 0x0CBB },   /* R3612  - EQ1_13 */ 
+       { 0x00000E1D, 0x16F8 },   /* R3613  - EQ1_14 */ 
+       { 0x00000E1E, 0xF7D9 },   /* R3614  - EQ1_15 */ 
+       { 0x00000E1F, 0x040A },   /* R3615  - EQ1_16 */ 
+       { 0x00000E20, 0x1F14 },   /* R3616  - EQ1_17 */ 
+       { 0x00000E21, 0x058C },   /* R3617  - EQ1_18 */ 
+       { 0x00000E22, 0x0563 },   /* R3618  - EQ1_19 */ 
+       { 0x00000E23, 0x4000 },   /* R3619  - EQ1_20 */ 
+       { 0x00000E24, 0x0B75 },   /* R3620  - EQ1_21 */ 
+       { 0x00000E26, 0x6318 },   /* R3622  - EQ2_1 */ 
+       { 0x00000E27, 0x6300 },   /* R3623  - EQ2_2 */ 
+       { 0x00000E28, 0x0FC8 },   /* R3624  - EQ2_3 */ 
+       { 0x00000E29, 0x03FE },   /* R3625  - EQ2_4 */ 
+       { 0x00000E2A, 0x00E0 },   /* R3626  - EQ2_5 */ 
+       { 0x00000E2B, 0x1EC4 },   /* R3627  - EQ2_6 */ 
+       { 0x00000E2C, 0xF136 },   /* R3628  - EQ2_7 */ 
+       { 0x00000E2D, 0x0409 },   /* R3629  - EQ2_8 */ 
+       { 0x00000E2E, 0x04CC },   /* R3630  - EQ2_9 */ 
+       { 0x00000E2F, 0x1C9B },   /* R3631  - EQ2_10 */ 
+       { 0x00000E30, 0xF337 },   /* R3632  - EQ2_11 */ 
+       { 0x00000E31, 0x040B },   /* R3633  - EQ2_12 */ 
+       { 0x00000E32, 0x0CBB },   /* R3634  - EQ2_13 */ 
+       { 0x00000E33, 0x16F8 },   /* R3635  - EQ2_14 */ 
+       { 0x00000E34, 0xF7D9 },   /* R3636  - EQ2_15 */ 
+       { 0x00000E35, 0x040A },   /* R3637  - EQ2_16 */ 
+       { 0x00000E36, 0x1F14 },   /* R3638  - EQ2_17 */ 
+       { 0x00000E37, 0x058C },   /* R3639  - EQ2_18 */ 
+       { 0x00000E38, 0x0563 },   /* R3640  - EQ2_19 */ 
+       { 0x00000E39, 0x4000 },   /* R3641  - EQ2_20 */ 
+       { 0x00000E3A, 0x0B75 },   /* R3642  - EQ2_21 */ 
+       { 0x00000E3C, 0x6318 },   /* R3644  - EQ3_1 */ 
+       { 0x00000E3D, 0x6300 },   /* R3645  - EQ3_2 */ 
+       { 0x00000E3E, 0x0FC8 },   /* R3646  - EQ3_3 */ 
+       { 0x00000E3F, 0x03FE },   /* R3647  - EQ3_4 */ 
+       { 0x00000E40, 0x00E0 },   /* R3648  - EQ3_5 */ 
+       { 0x00000E41, 0x1EC4 },   /* R3649  - EQ3_6 */ 
+       { 0x00000E42, 0xF136 },   /* R3650  - EQ3_7 */ 
+       { 0x00000E43, 0x0409 },   /* R3651  - EQ3_8 */ 
+       { 0x00000E44, 0x04CC },   /* R3652  - EQ3_9 */ 
+       { 0x00000E45, 0x1C9B },   /* R3653  - EQ3_10 */ 
+       { 0x00000E46, 0xF337 },   /* R3654  - EQ3_11 */ 
+       { 0x00000E47, 0x040B },   /* R3655  - EQ3_12 */ 
+       { 0x00000E48, 0x0CBB },   /* R3656  - EQ3_13 */ 
+       { 0x00000E49, 0x16F8 },   /* R3657  - EQ3_14 */ 
+       { 0x00000E4A, 0xF7D9 },   /* R3658  - EQ3_15 */ 
+       { 0x00000E4B, 0x040A },   /* R3659  - EQ3_16 */ 
+       { 0x00000E4C, 0x1F14 },   /* R3660  - EQ3_17 */ 
+       { 0x00000E4D, 0x058C },   /* R3661  - EQ3_18 */ 
+       { 0x00000E4E, 0x0563 },   /* R3662  - EQ3_19 */ 
+       { 0x00000E4F, 0x4000 },   /* R3663  - EQ3_20 */ 
+       { 0x00000E50, 0x0B75 },   /* R3664  - EQ3_21 */ 
+       { 0x00000E52, 0x6318 },   /* R3666  - EQ4_1 */ 
+       { 0x00000E53, 0x6300 },   /* R3667  - EQ4_2 */ 
+       { 0x00000E54, 0x0FC8 },   /* R3668  - EQ4_3 */ 
+       { 0x00000E55, 0x03FE },   /* R3669  - EQ4_4 */ 
+       { 0x00000E56, 0x00E0 },   /* R3670  - EQ4_5 */ 
+       { 0x00000E57, 0x1EC4 },   /* R3671  - EQ4_6 */ 
+       { 0x00000E58, 0xF136 },   /* R3672  - EQ4_7 */ 
+       { 0x00000E59, 0x0409 },   /* R3673  - EQ4_8 */ 
+       { 0x00000E5A, 0x04CC },   /* R3674  - EQ4_9 */ 
+       { 0x00000E5B, 0x1C9B },   /* R3675  - EQ4_10 */ 
+       { 0x00000E5C, 0xF337 },   /* R3676  - EQ4_11 */ 
+       { 0x00000E5D, 0x040B },   /* R3677  - EQ4_12 */ 
+       { 0x00000E5E, 0x0CBB },   /* R3678  - EQ4_13 */ 
+       { 0x00000E5F, 0x16F8 },   /* R3679  - EQ4_14 */ 
+       { 0x00000E60, 0xF7D9 },   /* R3680  - EQ4_15 */ 
+       { 0x00000E61, 0x040A },   /* R3681  - EQ4_16 */ 
+       { 0x00000E62, 0x1F14 },   /* R3682  - EQ4_17 */ 
+       { 0x00000E63, 0x058C },   /* R3683  - EQ4_18 */ 
+       { 0x00000E64, 0x0563 },   /* R3684  - EQ4_19 */ 
+       { 0x00000E65, 0x4000 },   /* R3685  - EQ4_20 */ 
+       { 0x00000E66, 0x0B75 },   /* R3686  - EQ4_21 */ 
+       { 0x00000E80, 0x0018 },   /* R3712  - DRC1 ctrl1 */ 
+       { 0x00000E81, 0x0933 },   /* R3713  - DRC1 ctrl2 */ 
+       { 0x00000E82, 0x0018 },   /* R3714  - DRC1 ctrl3 */ 
+       { 0x00000E83, 0x0000 },   /* R3715  - DRC1 ctrl4 */ 
+       { 0x00000E84, 0x0000 },   /* R3716  - DRC1 ctrl5 */ 
+       { 0x00000E89, 0x0018 },   /* R3721  - DRC2 ctrl1 */ 
+       { 0x00000E8A, 0x0933 },   /* R3722  - DRC2 ctrl2 */ 
+       { 0x00000E8B, 0x0018 },   /* R3723  - DRC2 ctrl3 */ 
+       { 0x00000E8C, 0x0000 },   /* R3724  - DRC2 ctrl4 */ 
+       { 0x00000E8D, 0x0000 },   /* R3725  - DRC2 ctrl5 */ 
+       { 0x00000EC0, 0x0000 },   /* R3776  - HPLPF1_1 */ 
+       { 0x00000EC1, 0x0000 },   /* R3777  - HPLPF1_2 */ 
+       { 0x00000EC4, 0x0000 },   /* R3780  - HPLPF2_1 */ 
+       { 0x00000EC5, 0x0000 },   /* R3781  - HPLPF2_2 */ 
+       { 0x00000EC8, 0x0000 },   /* R3784  - HPLPF3_1 */ 
+       { 0x00000EC9, 0x0000 },   /* R3785  - HPLPF3_2 */ 
+       { 0x00000ECC, 0x0000 },   /* R3788  - HPLPF4_1 */ 
+       { 0x00000ECD, 0x0000 },   /* R3789  - HPLPF4_2 */ 
+       { 0x00000EE0, 0x0000 },   /* R3808  - ASRC_ENABLE */ 
+       { 0x00000EE2, 0x0000 },   /* R3810  - ASRC_RATE1 */ 
+       { 0x00000EE3, 0x4000 },   /* R3811  - ASRC_RATE2 */ 
+       { 0x00000EF0, 0x0000 },   /* R3824  - ISRC 1 CTRL 1 */ 
+       { 0x00000EF1, 0x0000 },   /* R3825  - ISRC 1 CTRL 2 */ 
+       { 0x00000EF2, 0x0000 },   /* R3826  - ISRC 1 CTRL 3 */ 
+       { 0x00000EF3, 0x0000 },   /* R3827  - ISRC 2 CTRL 1 */ 
+       { 0x00000EF4, 0x0000 },   /* R3828  - ISRC 2 CTRL 2 */ 
+       { 0x00000EF5, 0x0000 },   /* R3829  - ISRC 2 CTRL 3 */ 
+       { 0x00000EF6, 0x0000 },   /* R3830  - ISRC 3 CTRL 1 */ 
+       { 0x00000EF7, 0x0000 },   /* R3831  - ISRC 3 CTRL 2 */ 
+       { 0x00000EF8, 0x0000 },   /* R3832  - ISRC 3 CTRL 3 */ 
+       { 0x00001100, 0x0010 },   /* R4352  - DSP1 Control 1 */ 
+       { 0x00001101, 0x0000 },   /* R4353  - DSP1 Clocking 1 */ 
+};
+
+static bool wm5102_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case ARIZONA_SOFTWARE_RESET:
+       case ARIZONA_DEVICE_REVISION:
+       case ARIZONA_CTRL_IF_SPI_CFG_1:
+       case ARIZONA_CTRL_IF_I2C1_CFG_1:
+       case ARIZONA_CTRL_IF_STATUS_1:
+       case ARIZONA_WRITE_SEQUENCER_CTRL_0:
+       case ARIZONA_WRITE_SEQUENCER_CTRL_1:
+       case ARIZONA_WRITE_SEQUENCER_CTRL_2:
+       case ARIZONA_WRITE_SEQUENCER_PROM:
+       case ARIZONA_TONE_GENERATOR_1:
+       case ARIZONA_TONE_GENERATOR_2:
+       case ARIZONA_TONE_GENERATOR_3:
+       case ARIZONA_TONE_GENERATOR_4:
+       case ARIZONA_TONE_GENERATOR_5:
+       case ARIZONA_PWM_DRIVE_1:
+       case ARIZONA_PWM_DRIVE_2:
+       case ARIZONA_PWM_DRIVE_3:
+       case ARIZONA_WAKE_CONTROL:
+       case ARIZONA_SEQUENCE_CONTROL:
+       case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1:
+       case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2:
+       case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3:
+       case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6:
+       case ARIZONA_COMFORT_NOISE_GENERATOR:
+       case ARIZONA_HAPTICS_CONTROL_1:
+       case ARIZONA_HAPTICS_CONTROL_2:
+       case ARIZONA_HAPTICS_PHASE_1_INTENSITY:
+       case ARIZONA_HAPTICS_PHASE_1_DURATION:
+       case ARIZONA_HAPTICS_PHASE_2_INTENSITY:
+       case ARIZONA_HAPTICS_PHASE_2_DURATION:
+       case ARIZONA_HAPTICS_PHASE_3_INTENSITY:
+       case ARIZONA_HAPTICS_PHASE_3_DURATION:
+       case ARIZONA_HAPTICS_STATUS:
+       case ARIZONA_CLOCK_32K_1:
+       case ARIZONA_SYSTEM_CLOCK_1:
+       case ARIZONA_SAMPLE_RATE_1:
+       case ARIZONA_SAMPLE_RATE_2:
+       case ARIZONA_SAMPLE_RATE_3:
+       case ARIZONA_SAMPLE_RATE_1_STATUS:
+       case ARIZONA_SAMPLE_RATE_2_STATUS:
+       case ARIZONA_SAMPLE_RATE_3_STATUS:
+       case ARIZONA_ASYNC_CLOCK_1:
+       case ARIZONA_ASYNC_SAMPLE_RATE_1:
+       case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
+       case ARIZONA_OUTPUT_SYSTEM_CLOCK:
+       case ARIZONA_OUTPUT_ASYNC_CLOCK:
+       case ARIZONA_RATE_ESTIMATOR_1:
+       case ARIZONA_RATE_ESTIMATOR_2:
+       case ARIZONA_RATE_ESTIMATOR_3:
+       case ARIZONA_RATE_ESTIMATOR_4:
+       case ARIZONA_RATE_ESTIMATOR_5:
+       case ARIZONA_FLL1_CONTROL_1:
+       case ARIZONA_FLL1_CONTROL_2:
+       case ARIZONA_FLL1_CONTROL_3:
+       case ARIZONA_FLL1_CONTROL_4:
+       case ARIZONA_FLL1_CONTROL_5:
+       case ARIZONA_FLL1_CONTROL_6:
+       case ARIZONA_FLL1_LOOP_FILTER_TEST_1:
+       case ARIZONA_FLL1_SYNCHRONISER_1:
+       case ARIZONA_FLL1_SYNCHRONISER_2:
+       case ARIZONA_FLL1_SYNCHRONISER_3:
+       case ARIZONA_FLL1_SYNCHRONISER_4:
+       case ARIZONA_FLL1_SYNCHRONISER_5:
+       case ARIZONA_FLL1_SYNCHRONISER_6:
+       case ARIZONA_FLL1_SPREAD_SPECTRUM:
+       case ARIZONA_FLL1_GPIO_CLOCK:
+       case ARIZONA_FLL2_CONTROL_1:
+       case ARIZONA_FLL2_CONTROL_2:
+       case ARIZONA_FLL2_CONTROL_3:
+       case ARIZONA_FLL2_CONTROL_4:
+       case ARIZONA_FLL2_CONTROL_5:
+       case ARIZONA_FLL2_CONTROL_6:
+       case ARIZONA_FLL2_LOOP_FILTER_TEST_1:
+       case ARIZONA_FLL2_SYNCHRONISER_1:
+       case ARIZONA_FLL2_SYNCHRONISER_2:
+       case ARIZONA_FLL2_SYNCHRONISER_3:
+       case ARIZONA_FLL2_SYNCHRONISER_4:
+       case ARIZONA_FLL2_SYNCHRONISER_5:
+       case ARIZONA_FLL2_SYNCHRONISER_6:
+       case ARIZONA_FLL2_SPREAD_SPECTRUM:
+       case ARIZONA_FLL2_GPIO_CLOCK:
+       case ARIZONA_MIC_CHARGE_PUMP_1:
+       case ARIZONA_LDO1_CONTROL_1:
+       case ARIZONA_LDO2_CONTROL_1:
+       case ARIZONA_MIC_BIAS_CTRL_1:
+       case ARIZONA_MIC_BIAS_CTRL_2:
+       case ARIZONA_MIC_BIAS_CTRL_3:
+       case ARIZONA_ACCESSORY_DETECT_MODE_1:
+       case ARIZONA_HEADPHONE_DETECT_1:
+       case ARIZONA_HEADPHONE_DETECT_2:
+       case ARIZONA_MIC_DETECT_1:
+       case ARIZONA_MIC_DETECT_2:
+       case ARIZONA_MIC_DETECT_3:
+       case ARIZONA_MIC_NOISE_MIX_CONTROL_1:
+       case ARIZONA_ISOLATION_CONTROL:
+       case ARIZONA_JACK_DETECT_ANALOGUE:
+       case ARIZONA_INPUT_ENABLES:
+       case ARIZONA_INPUT_RATE:
+       case ARIZONA_INPUT_VOLUME_RAMP:
+       case ARIZONA_IN1L_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_1L:
+       case ARIZONA_DMIC1L_CONTROL:
+       case ARIZONA_IN1R_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_1R:
+       case ARIZONA_DMIC1R_CONTROL:
+       case ARIZONA_IN2L_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_2L:
+       case ARIZONA_DMIC2L_CONTROL:
+       case ARIZONA_IN2R_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_2R:
+       case ARIZONA_DMIC2R_CONTROL:
+       case ARIZONA_IN3L_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_3L:
+       case ARIZONA_DMIC3L_CONTROL:
+       case ARIZONA_IN3R_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_3R:
+       case ARIZONA_DMIC3R_CONTROL:
+       case ARIZONA_OUTPUT_ENABLES_1:
+       case ARIZONA_OUTPUT_STATUS_1:
+       case ARIZONA_OUTPUT_RATE_1:
+       case ARIZONA_OUTPUT_VOLUME_RAMP:
+       case ARIZONA_OUTPUT_PATH_CONFIG_1L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_1L:
+       case ARIZONA_DAC_VOLUME_LIMIT_1L:
+       case ARIZONA_NOISE_GATE_SELECT_1L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_1R:
+       case ARIZONA_DAC_DIGITAL_VOLUME_1R:
+       case ARIZONA_DAC_VOLUME_LIMIT_1R:
+       case ARIZONA_NOISE_GATE_SELECT_1R:
+       case ARIZONA_OUTPUT_PATH_CONFIG_2L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_2L:
+       case ARIZONA_DAC_VOLUME_LIMIT_2L:
+       case ARIZONA_NOISE_GATE_SELECT_2L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_2R:
+       case ARIZONA_DAC_DIGITAL_VOLUME_2R:
+       case ARIZONA_DAC_VOLUME_LIMIT_2R:
+       case ARIZONA_NOISE_GATE_SELECT_2R:
+       case ARIZONA_OUTPUT_PATH_CONFIG_3L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_3L:
+       case ARIZONA_DAC_VOLUME_LIMIT_3L:
+       case ARIZONA_NOISE_GATE_SELECT_3L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_3R:
+       case ARIZONA_DAC_DIGITAL_VOLUME_3R:
+       case ARIZONA_DAC_VOLUME_LIMIT_3R:
+       case ARIZONA_OUTPUT_PATH_CONFIG_4L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_4L:
+       case ARIZONA_OUT_VOLUME_4L:
+       case ARIZONA_NOISE_GATE_SELECT_4L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_4R:
+       case ARIZONA_DAC_DIGITAL_VOLUME_4R:
+       case ARIZONA_OUT_VOLUME_4R:
+       case ARIZONA_NOISE_GATE_SELECT_4R:
+       case ARIZONA_OUTPUT_PATH_CONFIG_5L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_5L:
+       case ARIZONA_DAC_VOLUME_LIMIT_5L:
+       case ARIZONA_NOISE_GATE_SELECT_5L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_5R:
+       case ARIZONA_DAC_DIGITAL_VOLUME_5R:
+       case ARIZONA_DAC_VOLUME_LIMIT_5R:
+       case ARIZONA_NOISE_GATE_SELECT_5R:
+       case ARIZONA_DAC_AEC_CONTROL_1:
+       case ARIZONA_NOISE_GATE_CONTROL:
+       case ARIZONA_PDM_SPK1_CTRL_1:
+       case ARIZONA_PDM_SPK1_CTRL_2:
+       case ARIZONA_DAC_COMP_1:
+       case ARIZONA_DAC_COMP_2:
+       case ARIZONA_DAC_COMP_3:
+       case ARIZONA_DAC_COMP_4:
+       case ARIZONA_AIF1_BCLK_CTRL:
+       case ARIZONA_AIF1_TX_PIN_CTRL:
+       case ARIZONA_AIF1_RX_PIN_CTRL:
+       case ARIZONA_AIF1_RATE_CTRL:
+       case ARIZONA_AIF1_FORMAT:
+       case ARIZONA_AIF1_TX_BCLK_RATE:
+       case ARIZONA_AIF1_RX_BCLK_RATE:
+       case ARIZONA_AIF1_FRAME_CTRL_1:
+       case ARIZONA_AIF1_FRAME_CTRL_2:
+       case ARIZONA_AIF1_FRAME_CTRL_3:
+       case ARIZONA_AIF1_FRAME_CTRL_4:
+       case ARIZONA_AIF1_FRAME_CTRL_5:
+       case ARIZONA_AIF1_FRAME_CTRL_6:
+       case ARIZONA_AIF1_FRAME_CTRL_7:
+       case ARIZONA_AIF1_FRAME_CTRL_8:
+       case ARIZONA_AIF1_FRAME_CTRL_9:
+       case ARIZONA_AIF1_FRAME_CTRL_10:
+       case ARIZONA_AIF1_FRAME_CTRL_11:
+       case ARIZONA_AIF1_FRAME_CTRL_12:
+       case ARIZONA_AIF1_FRAME_CTRL_13:
+       case ARIZONA_AIF1_FRAME_CTRL_14:
+       case ARIZONA_AIF1_FRAME_CTRL_15:
+       case ARIZONA_AIF1_FRAME_CTRL_16:
+       case ARIZONA_AIF1_FRAME_CTRL_17:
+       case ARIZONA_AIF1_FRAME_CTRL_18:
+       case ARIZONA_AIF1_TX_ENABLES:
+       case ARIZONA_AIF1_RX_ENABLES:
+       case ARIZONA_AIF1_FORCE_WRITE:
+       case ARIZONA_AIF2_BCLK_CTRL:
+       case ARIZONA_AIF2_TX_PIN_CTRL:
+       case ARIZONA_AIF2_RX_PIN_CTRL:
+       case ARIZONA_AIF2_RATE_CTRL:
+       case ARIZONA_AIF2_FORMAT:
+       case ARIZONA_AIF2_TX_BCLK_RATE:
+       case ARIZONA_AIF2_RX_BCLK_RATE:
+       case ARIZONA_AIF2_FRAME_CTRL_1:
+       case ARIZONA_AIF2_FRAME_CTRL_2:
+       case ARIZONA_AIF2_FRAME_CTRL_3:
+       case ARIZONA_AIF2_FRAME_CTRL_4:
+       case ARIZONA_AIF2_FRAME_CTRL_11:
+       case ARIZONA_AIF2_FRAME_CTRL_12:
+       case ARIZONA_AIF2_TX_ENABLES:
+       case ARIZONA_AIF2_RX_ENABLES:
+       case ARIZONA_AIF2_FORCE_WRITE:
+       case ARIZONA_AIF3_BCLK_CTRL:
+       case ARIZONA_AIF3_TX_PIN_CTRL:
+       case ARIZONA_AIF3_RX_PIN_CTRL:
+       case ARIZONA_AIF3_RATE_CTRL:
+       case ARIZONA_AIF3_FORMAT:
+       case ARIZONA_AIF3_TX_BCLK_RATE:
+       case ARIZONA_AIF3_RX_BCLK_RATE:
+       case ARIZONA_AIF3_FRAME_CTRL_1:
+       case ARIZONA_AIF3_FRAME_CTRL_2:
+       case ARIZONA_AIF3_FRAME_CTRL_3:
+       case ARIZONA_AIF3_FRAME_CTRL_4:
+       case ARIZONA_AIF3_FRAME_CTRL_11:
+       case ARIZONA_AIF3_FRAME_CTRL_12:
+       case ARIZONA_AIF3_TX_ENABLES:
+       case ARIZONA_AIF3_RX_ENABLES:
+       case ARIZONA_AIF3_FORCE_WRITE:
+       case ARIZONA_SLIMBUS_FRAMER_REF_GEAR:
+       case ARIZONA_SLIMBUS_RATES_1:
+       case ARIZONA_SLIMBUS_RATES_2:
+       case ARIZONA_SLIMBUS_RATES_3:
+       case ARIZONA_SLIMBUS_RATES_4:
+       case ARIZONA_SLIMBUS_RATES_5:
+       case ARIZONA_SLIMBUS_RATES_6:
+       case ARIZONA_SLIMBUS_RATES_7:
+       case ARIZONA_SLIMBUS_RATES_8:
+       case ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE:
+       case ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE:
+       case ARIZONA_SLIMBUS_RX_PORT_STATUS:
+       case ARIZONA_SLIMBUS_TX_PORT_STATUS:
+       case ARIZONA_PWM1MIX_INPUT_1_SOURCE:
+       case ARIZONA_PWM1MIX_INPUT_1_VOLUME:
+       case ARIZONA_PWM1MIX_INPUT_2_SOURCE:
+       case ARIZONA_PWM1MIX_INPUT_2_VOLUME:
+       case ARIZONA_PWM1MIX_INPUT_3_SOURCE:
+       case ARIZONA_PWM1MIX_INPUT_3_VOLUME:
+       case ARIZONA_PWM1MIX_INPUT_4_SOURCE:
+       case ARIZONA_PWM1MIX_INPUT_4_VOLUME:
+       case ARIZONA_PWM2MIX_INPUT_1_SOURCE:
+       case ARIZONA_PWM2MIX_INPUT_1_VOLUME:
+       case ARIZONA_PWM2MIX_INPUT_2_SOURCE:
+       case ARIZONA_PWM2MIX_INPUT_2_VOLUME:
+       case ARIZONA_PWM2MIX_INPUT_3_SOURCE:
+       case ARIZONA_PWM2MIX_INPUT_3_VOLUME:
+       case ARIZONA_PWM2MIX_INPUT_4_SOURCE:
+       case ARIZONA_PWM2MIX_INPUT_4_VOLUME:
+       case ARIZONA_MICMIX_INPUT_1_SOURCE:
+       case ARIZONA_MICMIX_INPUT_1_VOLUME:
+       case ARIZONA_MICMIX_INPUT_2_SOURCE:
+       case ARIZONA_MICMIX_INPUT_2_VOLUME:
+       case ARIZONA_MICMIX_INPUT_3_SOURCE:
+       case ARIZONA_MICMIX_INPUT_3_VOLUME:
+       case ARIZONA_MICMIX_INPUT_4_SOURCE:
+       case ARIZONA_MICMIX_INPUT_4_VOLUME:
+       case ARIZONA_NOISEMIX_INPUT_1_SOURCE:
+       case ARIZONA_NOISEMIX_INPUT_1_VOLUME:
+       case ARIZONA_NOISEMIX_INPUT_2_SOURCE:
+       case ARIZONA_NOISEMIX_INPUT_2_VOLUME:
+       case ARIZONA_NOISEMIX_INPUT_3_SOURCE:
+       case ARIZONA_NOISEMIX_INPUT_3_VOLUME:
+       case ARIZONA_NOISEMIX_INPUT_4_SOURCE:
+       case ARIZONA_NOISEMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT1LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT1LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT1LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT1LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT1LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT1LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT1LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT1LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT1RMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT1RMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT1RMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT1RMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT1RMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT1RMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT1RMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT1RMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT2LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT2LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT2LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT2LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT2LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT2LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT2LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT2LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT2RMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT2RMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT2RMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT2RMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT2RMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT2RMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT2RMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT2RMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT3LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT3LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT3LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT3LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT3LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT3LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT3LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT3LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT4LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT4LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT4LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT4LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT4LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT4LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT4LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT4LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT4RMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT4RMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT4RMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT4RMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT4RMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT4RMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT4RMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT4RMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT5LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT5LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT5LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT5LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT5LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT5LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT5LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT5LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT5RMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT5RMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT5RMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT5RMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT5RMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT5RMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT5RMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT5RMIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX1MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX1MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX1MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX1MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX1MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX1MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX1MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX2MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX2MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX2MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX2MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX2MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX2MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX2MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX3MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX3MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX3MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX3MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX3MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX3MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX3MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX4MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX4MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX4MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX4MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX4MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX4MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX4MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX5MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX5MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX5MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX5MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX5MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX5MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX5MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX6MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX6MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX6MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX6MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX6MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX6MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX6MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX7MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX7MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX7MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX7MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX7MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX7MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX7MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX8MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX8MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX8MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX8MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX8MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX8MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX8MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF2TX1MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF2TX1MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF2TX1MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF2TX1MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF2TX1MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF2TX1MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF2TX1MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF2TX2MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF2TX2MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF2TX2MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF2TX2MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF3TX1MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF3TX1MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF3TX1MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF3TX1MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF3TX1MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF3TX2MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF3TX2MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF3TX2MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF3TX2MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF3TX2MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF3TX2MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF3TX2MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX1MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX1MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX1MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX1MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX1MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX1MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX1MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX2MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX2MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX2MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX2MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX2MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX2MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX2MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX3MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX3MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX3MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX3MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX3MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX3MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX3MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX4MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX4MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX4MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX4MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX4MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX4MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX4MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX5MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX5MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX5MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX5MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX5MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX5MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX5MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX6MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX6MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX6MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX6MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX6MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX6MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX6MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX7MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX7MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX7MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX7MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX7MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX7MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX7MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX8MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX8MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX8MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX8MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX8MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX8MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX8MIX_INPUT_4_VOLUME:
+       case ARIZONA_EQ1MIX_INPUT_1_SOURCE:
+       case ARIZONA_EQ1MIX_INPUT_1_VOLUME:
+       case ARIZONA_EQ1MIX_INPUT_2_SOURCE:
+       case ARIZONA_EQ1MIX_INPUT_2_VOLUME:
+       case ARIZONA_EQ1MIX_INPUT_3_SOURCE:
+       case ARIZONA_EQ1MIX_INPUT_3_VOLUME:
+       case ARIZONA_EQ1MIX_INPUT_4_SOURCE:
+       case ARIZONA_EQ1MIX_INPUT_4_VOLUME:
+       case ARIZONA_EQ2MIX_INPUT_1_SOURCE:
+       case ARIZONA_EQ2MIX_INPUT_1_VOLUME:
+       case ARIZONA_EQ2MIX_INPUT_2_SOURCE:
+       case ARIZONA_EQ2MIX_INPUT_2_VOLUME:
+       case ARIZONA_EQ2MIX_INPUT_3_SOURCE:
+       case ARIZONA_EQ2MIX_INPUT_3_VOLUME:
+       case ARIZONA_EQ2MIX_INPUT_4_SOURCE:
+       case ARIZONA_EQ2MIX_INPUT_4_VOLUME:
+       case ARIZONA_EQ3MIX_INPUT_1_SOURCE:
+       case ARIZONA_EQ3MIX_INPUT_1_VOLUME:
+       case ARIZONA_EQ3MIX_INPUT_2_SOURCE:
+       case ARIZONA_EQ3MIX_INPUT_2_VOLUME:
+       case ARIZONA_EQ3MIX_INPUT_3_SOURCE:
+       case ARIZONA_EQ3MIX_INPUT_3_VOLUME:
+       case ARIZONA_EQ3MIX_INPUT_4_SOURCE:
+       case ARIZONA_EQ3MIX_INPUT_4_VOLUME:
+       case ARIZONA_EQ4MIX_INPUT_1_SOURCE:
+       case ARIZONA_EQ4MIX_INPUT_1_VOLUME:
+       case ARIZONA_EQ4MIX_INPUT_2_SOURCE:
+       case ARIZONA_EQ4MIX_INPUT_2_VOLUME:
+       case ARIZONA_EQ4MIX_INPUT_3_SOURCE:
+       case ARIZONA_EQ4MIX_INPUT_3_VOLUME:
+       case ARIZONA_EQ4MIX_INPUT_4_SOURCE:
+       case ARIZONA_EQ4MIX_INPUT_4_VOLUME:
+       case ARIZONA_DRC1LMIX_INPUT_1_SOURCE:
+       case ARIZONA_DRC1LMIX_INPUT_1_VOLUME:
+       case ARIZONA_DRC1LMIX_INPUT_2_SOURCE:
+       case ARIZONA_DRC1LMIX_INPUT_2_VOLUME:
+       case ARIZONA_DRC1LMIX_INPUT_3_SOURCE:
+       case ARIZONA_DRC1LMIX_INPUT_3_VOLUME:
+       case ARIZONA_DRC1LMIX_INPUT_4_SOURCE:
+       case ARIZONA_DRC1LMIX_INPUT_4_VOLUME:
+       case ARIZONA_DRC1RMIX_INPUT_1_SOURCE:
+       case ARIZONA_DRC1RMIX_INPUT_1_VOLUME:
+       case ARIZONA_DRC1RMIX_INPUT_2_SOURCE:
+       case ARIZONA_DRC1RMIX_INPUT_2_VOLUME:
+       case ARIZONA_DRC1RMIX_INPUT_3_SOURCE:
+       case ARIZONA_DRC1RMIX_INPUT_3_VOLUME:
+       case ARIZONA_DRC1RMIX_INPUT_4_SOURCE:
+       case ARIZONA_DRC1RMIX_INPUT_4_VOLUME:
+       case ARIZONA_DRC2LMIX_INPUT_1_SOURCE:
+       case ARIZONA_DRC2LMIX_INPUT_1_VOLUME:
+       case ARIZONA_DRC2LMIX_INPUT_2_SOURCE:
+       case ARIZONA_DRC2LMIX_INPUT_2_VOLUME:
+       case ARIZONA_DRC2LMIX_INPUT_3_SOURCE:
+       case ARIZONA_DRC2LMIX_INPUT_3_VOLUME:
+       case ARIZONA_DRC2LMIX_INPUT_4_SOURCE:
+       case ARIZONA_DRC2LMIX_INPUT_4_VOLUME:
+       case ARIZONA_DRC2RMIX_INPUT_1_SOURCE:
+       case ARIZONA_DRC2RMIX_INPUT_1_VOLUME:
+       case ARIZONA_DRC2RMIX_INPUT_2_SOURCE:
+       case ARIZONA_DRC2RMIX_INPUT_2_VOLUME:
+       case ARIZONA_DRC2RMIX_INPUT_3_SOURCE:
+       case ARIZONA_DRC2RMIX_INPUT_3_VOLUME:
+       case ARIZONA_DRC2RMIX_INPUT_4_SOURCE:
+       case ARIZONA_DRC2RMIX_INPUT_4_VOLUME:
+       case ARIZONA_HPLP1MIX_INPUT_1_SOURCE:
+       case ARIZONA_HPLP1MIX_INPUT_1_VOLUME:
+       case ARIZONA_HPLP1MIX_INPUT_2_SOURCE:
+       case ARIZONA_HPLP1MIX_INPUT_2_VOLUME:
+       case ARIZONA_HPLP1MIX_INPUT_3_SOURCE:
+       case ARIZONA_HPLP1MIX_INPUT_3_VOLUME:
+       case ARIZONA_HPLP1MIX_INPUT_4_SOURCE:
+       case ARIZONA_HPLP1MIX_INPUT_4_VOLUME:
+       case ARIZONA_HPLP2MIX_INPUT_1_SOURCE:
+       case ARIZONA_HPLP2MIX_INPUT_1_VOLUME:
+       case ARIZONA_HPLP2MIX_INPUT_2_SOURCE:
+       case ARIZONA_HPLP2MIX_INPUT_2_VOLUME:
+       case ARIZONA_HPLP2MIX_INPUT_3_SOURCE:
+       case ARIZONA_HPLP2MIX_INPUT_3_VOLUME:
+       case ARIZONA_HPLP2MIX_INPUT_4_SOURCE:
+       case ARIZONA_HPLP2MIX_INPUT_4_VOLUME:
+       case ARIZONA_HPLP3MIX_INPUT_1_SOURCE:
+       case ARIZONA_HPLP3MIX_INPUT_1_VOLUME:
+       case ARIZONA_HPLP3MIX_INPUT_2_SOURCE:
+       case ARIZONA_HPLP3MIX_INPUT_2_VOLUME:
+       case ARIZONA_HPLP3MIX_INPUT_3_SOURCE:
+       case ARIZONA_HPLP3MIX_INPUT_3_VOLUME:
+       case ARIZONA_HPLP3MIX_INPUT_4_SOURCE:
+       case ARIZONA_HPLP3MIX_INPUT_4_VOLUME:
+       case ARIZONA_HPLP4MIX_INPUT_1_SOURCE:
+       case ARIZONA_HPLP4MIX_INPUT_1_VOLUME:
+       case ARIZONA_HPLP4MIX_INPUT_2_SOURCE:
+       case ARIZONA_HPLP4MIX_INPUT_2_VOLUME:
+       case ARIZONA_HPLP4MIX_INPUT_3_SOURCE:
+       case ARIZONA_HPLP4MIX_INPUT_3_VOLUME:
+       case ARIZONA_HPLP4MIX_INPUT_4_SOURCE:
+       case ARIZONA_HPLP4MIX_INPUT_4_VOLUME:
+       case ARIZONA_DSP1LMIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1LMIX_INPUT_1_VOLUME:
+       case ARIZONA_DSP1LMIX_INPUT_2_SOURCE:
+       case ARIZONA_DSP1LMIX_INPUT_2_VOLUME:
+       case ARIZONA_DSP1LMIX_INPUT_3_SOURCE:
+       case ARIZONA_DSP1LMIX_INPUT_3_VOLUME:
+       case ARIZONA_DSP1LMIX_INPUT_4_SOURCE:
+       case ARIZONA_DSP1LMIX_INPUT_4_VOLUME:
+       case ARIZONA_DSP1RMIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1RMIX_INPUT_1_VOLUME:
+       case ARIZONA_DSP1RMIX_INPUT_2_SOURCE:
+       case ARIZONA_DSP1RMIX_INPUT_2_VOLUME:
+       case ARIZONA_DSP1RMIX_INPUT_3_SOURCE:
+       case ARIZONA_DSP1RMIX_INPUT_3_VOLUME:
+       case ARIZONA_DSP1RMIX_INPUT_4_SOURCE:
+       case ARIZONA_DSP1RMIX_INPUT_4_VOLUME:
+       case ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1AUX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1AUX3MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1AUX4MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1AUX5MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1AUX6MIX_INPUT_1_SOURCE:
+       case ARIZONA_ASRC1LMIX_INPUT_1_SOURCE:
+       case ARIZONA_ASRC1RMIX_INPUT_1_SOURCE:
+       case ARIZONA_ASRC2LMIX_INPUT_1_SOURCE:
+       case ARIZONA_ASRC2RMIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE:
+       case ARIZONA_GPIO1_CTRL:
+       case ARIZONA_GPIO2_CTRL:
+       case ARIZONA_GPIO3_CTRL:
+       case ARIZONA_GPIO4_CTRL:
+       case ARIZONA_GPIO5_CTRL:
+       case ARIZONA_IRQ_CTRL_1:
+       case ARIZONA_GPIO_DEBOUNCE_CONFIG:
+       case ARIZONA_MISC_PAD_CTRL_1:
+       case ARIZONA_MISC_PAD_CTRL_2:
+       case ARIZONA_MISC_PAD_CTRL_3:
+       case ARIZONA_MISC_PAD_CTRL_4:
+       case ARIZONA_MISC_PAD_CTRL_5:
+       case ARIZONA_MISC_PAD_CTRL_6:
+       case ARIZONA_INTERRUPT_STATUS_1:
+       case ARIZONA_INTERRUPT_STATUS_2:
+       case ARIZONA_INTERRUPT_STATUS_3:
+       case ARIZONA_INTERRUPT_STATUS_4:
+       case ARIZONA_INTERRUPT_STATUS_5:
+       case ARIZONA_INTERRUPT_STATUS_1_MASK:
+       case ARIZONA_INTERRUPT_STATUS_2_MASK:
+       case ARIZONA_INTERRUPT_STATUS_3_MASK:
+       case ARIZONA_INTERRUPT_STATUS_4_MASK:
+       case ARIZONA_INTERRUPT_STATUS_5_MASK:
+       case ARIZONA_INTERRUPT_CONTROL:
+       case ARIZONA_IRQ2_STATUS_1:
+       case ARIZONA_IRQ2_STATUS_2:
+       case ARIZONA_IRQ2_STATUS_3:
+       case ARIZONA_IRQ2_STATUS_4:
+       case ARIZONA_IRQ2_STATUS_5:
+       case ARIZONA_IRQ2_STATUS_1_MASK:
+       case ARIZONA_IRQ2_STATUS_2_MASK:
+       case ARIZONA_IRQ2_STATUS_3_MASK:
+       case ARIZONA_IRQ2_STATUS_4_MASK:
+       case ARIZONA_IRQ2_STATUS_5_MASK:
+       case ARIZONA_IRQ2_CONTROL:
+       case ARIZONA_INTERRUPT_RAW_STATUS_2:
+       case ARIZONA_INTERRUPT_RAW_STATUS_3:
+       case ARIZONA_INTERRUPT_RAW_STATUS_4:
+       case ARIZONA_INTERRUPT_RAW_STATUS_5:
+       case ARIZONA_INTERRUPT_RAW_STATUS_6:
+       case ARIZONA_INTERRUPT_RAW_STATUS_7:
+       case ARIZONA_INTERRUPT_RAW_STATUS_8:
+       case ARIZONA_IRQ_PIN_STATUS:
+       case ARIZONA_ADSP2_IRQ0:
+       case ARIZONA_AOD_WKUP_AND_TRIG:
+       case ARIZONA_AOD_IRQ1:
+       case ARIZONA_AOD_IRQ2:
+       case ARIZONA_AOD_IRQ_MASK_IRQ1:
+       case ARIZONA_AOD_IRQ_MASK_IRQ2:
+       case ARIZONA_AOD_IRQ_RAW_STATUS:
+       case ARIZONA_JACK_DETECT_DEBOUNCE:
+       case ARIZONA_FX_CTRL1:
+       case ARIZONA_FX_CTRL2:
+       case ARIZONA_EQ1_1:
+       case ARIZONA_EQ1_2:
+       case ARIZONA_EQ1_3:
+       case ARIZONA_EQ1_4:
+       case ARIZONA_EQ1_5:
+       case ARIZONA_EQ1_6:
+       case ARIZONA_EQ1_7:
+       case ARIZONA_EQ1_8:
+       case ARIZONA_EQ1_9:
+       case ARIZONA_EQ1_10:
+       case ARIZONA_EQ1_11:
+       case ARIZONA_EQ1_12:
+       case ARIZONA_EQ1_13:
+       case ARIZONA_EQ1_14:
+       case ARIZONA_EQ1_15:
+       case ARIZONA_EQ1_16:
+       case ARIZONA_EQ1_17:
+       case ARIZONA_EQ1_18:
+       case ARIZONA_EQ1_19:
+       case ARIZONA_EQ1_20:
+       case ARIZONA_EQ1_21:
+       case ARIZONA_EQ2_1:
+       case ARIZONA_EQ2_2:
+       case ARIZONA_EQ2_3:
+       case ARIZONA_EQ2_4:
+       case ARIZONA_EQ2_5:
+       case ARIZONA_EQ2_6:
+       case ARIZONA_EQ2_7:
+       case ARIZONA_EQ2_8:
+       case ARIZONA_EQ2_9:
+       case ARIZONA_EQ2_10:
+       case ARIZONA_EQ2_11:
+       case ARIZONA_EQ2_12:
+       case ARIZONA_EQ2_13:
+       case ARIZONA_EQ2_14:
+       case ARIZONA_EQ2_15:
+       case ARIZONA_EQ2_16:
+       case ARIZONA_EQ2_17:
+       case ARIZONA_EQ2_18:
+       case ARIZONA_EQ2_19:
+       case ARIZONA_EQ2_20:
+       case ARIZONA_EQ2_21:
+       case ARIZONA_EQ3_1:
+       case ARIZONA_EQ3_2:
+       case ARIZONA_EQ3_3:
+       case ARIZONA_EQ3_4:
+       case ARIZONA_EQ3_5:
+       case ARIZONA_EQ3_6:
+       case ARIZONA_EQ3_7:
+       case ARIZONA_EQ3_8:
+       case ARIZONA_EQ3_9:
+       case ARIZONA_EQ3_10:
+       case ARIZONA_EQ3_11:
+       case ARIZONA_EQ3_12:
+       case ARIZONA_EQ3_13:
+       case ARIZONA_EQ3_14:
+       case ARIZONA_EQ3_15:
+       case ARIZONA_EQ3_16:
+       case ARIZONA_EQ3_17:
+       case ARIZONA_EQ3_18:
+       case ARIZONA_EQ3_19:
+       case ARIZONA_EQ3_20:
+       case ARIZONA_EQ3_21:
+       case ARIZONA_EQ4_1:
+       case ARIZONA_EQ4_2:
+       case ARIZONA_EQ4_3:
+       case ARIZONA_EQ4_4:
+       case ARIZONA_EQ4_5:
+       case ARIZONA_EQ4_6:
+       case ARIZONA_EQ4_7:
+       case ARIZONA_EQ4_8:
+       case ARIZONA_EQ4_9:
+       case ARIZONA_EQ4_10:
+       case ARIZONA_EQ4_11:
+       case ARIZONA_EQ4_12:
+       case ARIZONA_EQ4_13:
+       case ARIZONA_EQ4_14:
+       case ARIZONA_EQ4_15:
+       case ARIZONA_EQ4_16:
+       case ARIZONA_EQ4_17:
+       case ARIZONA_EQ4_18:
+       case ARIZONA_EQ4_19:
+       case ARIZONA_EQ4_20:
+       case ARIZONA_EQ4_21:
+       case ARIZONA_DRC1_CTRL1:
+       case ARIZONA_DRC1_CTRL2:
+       case ARIZONA_DRC1_CTRL3:
+       case ARIZONA_DRC1_CTRL4:
+       case ARIZONA_DRC1_CTRL5:
+       case ARIZONA_DRC2_CTRL1:
+       case ARIZONA_DRC2_CTRL2:
+       case ARIZONA_DRC2_CTRL3:
+       case ARIZONA_DRC2_CTRL4:
+       case ARIZONA_DRC2_CTRL5:
+       case ARIZONA_HPLPF1_1:
+       case ARIZONA_HPLPF1_2:
+       case ARIZONA_HPLPF2_1:
+       case ARIZONA_HPLPF2_2:
+       case ARIZONA_HPLPF3_1:
+       case ARIZONA_HPLPF3_2:
+       case ARIZONA_HPLPF4_1:
+       case ARIZONA_HPLPF4_2:
+       case ARIZONA_ASRC_ENABLE:
+       case ARIZONA_ASRC_RATE1:
+       case ARIZONA_ASRC_RATE2:
+       case ARIZONA_ISRC_1_CTRL_1:
+       case ARIZONA_ISRC_1_CTRL_2:
+       case ARIZONA_ISRC_1_CTRL_3:
+       case ARIZONA_ISRC_2_CTRL_1:
+       case ARIZONA_ISRC_2_CTRL_2:
+       case ARIZONA_ISRC_2_CTRL_3:
+       case ARIZONA_ISRC_3_CTRL_1:
+       case ARIZONA_ISRC_3_CTRL_2:
+       case ARIZONA_ISRC_3_CTRL_3:
+       case ARIZONA_DSP1_CONTROL_1:
+       case ARIZONA_DSP1_CLOCKING_1:
+       case ARIZONA_DSP1_STATUS_1:
+       case ARIZONA_DSP1_STATUS_2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case ARIZONA_SOFTWARE_RESET:
+       case ARIZONA_DEVICE_REVISION:
+       case ARIZONA_OUTPUT_STATUS_1:
+       case ARIZONA_SAMPLE_RATE_1_STATUS:
+       case ARIZONA_SAMPLE_RATE_2_STATUS:
+       case ARIZONA_SAMPLE_RATE_3_STATUS:
+       case ARIZONA_HAPTICS_STATUS:
+       case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
+       case ARIZONA_FX_CTRL2:
+       case ARIZONA_INTERRUPT_STATUS_1:
+       case ARIZONA_INTERRUPT_STATUS_2:
+       case ARIZONA_INTERRUPT_STATUS_3:
+       case ARIZONA_INTERRUPT_STATUS_4:
+       case ARIZONA_INTERRUPT_STATUS_5:
+       case ARIZONA_IRQ2_STATUS_1:
+       case ARIZONA_IRQ2_STATUS_2:
+       case ARIZONA_IRQ2_STATUS_3:
+       case ARIZONA_IRQ2_STATUS_4:
+       case ARIZONA_IRQ2_STATUS_5:
+       case ARIZONA_INTERRUPT_RAW_STATUS_2:
+       case ARIZONA_INTERRUPT_RAW_STATUS_3:
+       case ARIZONA_INTERRUPT_RAW_STATUS_4:
+       case ARIZONA_INTERRUPT_RAW_STATUS_5:
+       case ARIZONA_INTERRUPT_RAW_STATUS_6:
+       case ARIZONA_INTERRUPT_RAW_STATUS_7:
+       case ARIZONA_INTERRUPT_RAW_STATUS_8:
+       case ARIZONA_IRQ_PIN_STATUS:
+       case ARIZONA_AOD_WKUP_AND_TRIG:
+       case ARIZONA_AOD_IRQ1:
+       case ARIZONA_AOD_IRQ2:
+       case ARIZONA_AOD_IRQ_RAW_STATUS:
+       case ARIZONA_DSP1_STATUS_1:
+       case ARIZONA_DSP1_STATUS_2:
+       case ARIZONA_HEADPHONE_DETECT_2:
+       case ARIZONA_MIC_DETECT_3:
+               return true;
+       default:
+               return false;
+       }
+}
+
+const struct regmap_config wm5102_spi_regmap = {
+       .reg_bits = 32,
+       .pad_bits = 16,
+       .val_bits = 16,
+
+       .max_register = ARIZONA_DSP1_STATUS_2,
+       .readable_reg = wm5102_readable_register,
+       .volatile_reg = wm5102_volatile_register,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = wm5102_reg_default,
+       .num_reg_defaults = ARRAY_SIZE(wm5102_reg_default),
+};
+EXPORT_SYMBOL_GPL(wm5102_spi_regmap);
+
+const struct regmap_config wm5102_i2c_regmap = {
+       .reg_bits = 32,
+       .val_bits = 16,
+
+       .max_register = ARIZONA_DSP1_STATUS_2,
+       .readable_reg = wm5102_readable_register,
+       .volatile_reg = wm5102_volatile_register,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = wm5102_reg_default,
+       .num_reg_defaults = ARRAY_SIZE(wm5102_reg_default),
+};
+EXPORT_SYMBOL_GPL(wm5102_i2c_regmap);
diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c
new file mode 100644 (file)
index 0000000..bd8782c
--- /dev/null
@@ -0,0 +1,2281 @@
+/*
+ * wm5110-tables.c  --  WM5110 data tables
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+
+#define WM5110_NUM_AOD_ISR 2
+#define WM5110_NUM_ISR 5
+
+static const struct reg_default wm5110_reva_patch[] = {
+       { 0x80, 0x3 },
+       { 0x44, 0x20 },
+       { 0x45, 0x40 },
+       { 0x46, 0x60 },
+       { 0x47, 0x80 },
+       { 0x48, 0xa0 },
+       { 0x51, 0x13 },
+       { 0x52, 0x33 },
+       { 0x53, 0x53 },
+       { 0x54, 0x73 },
+       { 0x55, 0x75 },
+       { 0x56, 0xb3 },
+       { 0x2ef, 0x124 },
+       { 0x2ef, 0x124 },
+       { 0x2f0, 0x124 },
+       { 0x2f0, 0x124 },
+       { 0x2f1, 0x124 },
+       { 0x2f1, 0x124 },
+       { 0x2f2, 0x124 },
+       { 0x2f2, 0x124 },
+       { 0x2f3, 0x124 },
+       { 0x2f3, 0x124 },
+       { 0x2f4, 0x124 },
+       { 0x2f4, 0x124 },
+       { 0x2eb, 0x60 },
+       { 0x2ec, 0x60 },
+       { 0x2ed, 0x60 },
+       { 0xc30, 0x3e3e },
+       { 0xc30, 0x3e3e },
+       { 0xc31, 0x3e },
+       { 0xc32, 0x3e3e },
+       { 0xc32, 0x3e3e },
+       { 0xc33, 0x3e3e },
+       { 0xc33, 0x3e3e },
+       { 0xc34, 0x3e3e },
+       { 0xc34, 0x3e3e },
+       { 0xc35, 0x3e3e },
+       { 0xc35, 0x3e3e },
+       { 0xc36, 0x3e3e },
+       { 0xc36, 0x3e3e },
+       { 0xc37, 0x3e3e },
+       { 0xc37, 0x3e3e },
+       { 0xc38, 0x3e3e },
+       { 0xc38, 0x3e3e },
+       { 0xc30, 0x3e3e },
+       { 0xc30, 0x3e3e },
+       { 0xc39, 0x3e3e },
+       { 0xc39, 0x3e3e },
+       { 0xc3a, 0x3e3e },
+       { 0xc3a, 0x3e3e },
+       { 0xc3b, 0x3e3e },
+       { 0xc3b, 0x3e3e },
+       { 0xc3c, 0x3e },
+       { 0x201, 0x18a5 },
+       { 0x201, 0x18a5 },
+       { 0x201, 0x18a5 },
+       { 0x202, 0x4100 },
+       { 0x460, 0xc00 },
+       { 0x461, 0x8000 },
+       { 0x462, 0xc01 },
+       { 0x463, 0x50f0 },
+       { 0x464, 0xc01 },
+       { 0x465, 0x4820 },
+       { 0x466, 0xc01 },
+       { 0x466, 0xc01 },
+       { 0x467, 0x4040 },
+       { 0x468, 0xc01 },
+       { 0x468, 0xc01 },
+       { 0x469, 0x3940 },
+       { 0x46a, 0xc01 },
+       { 0x46a, 0xc01 },
+       { 0x46a, 0xc01 },
+       { 0x46b, 0x3310 },
+       { 0x46c, 0x801 },
+       { 0x46c, 0x801 },
+       { 0x46d, 0x2d80 },
+       { 0x46e, 0x801 },
+       { 0x46e, 0x801 },
+       { 0x46f, 0x2890 },
+       { 0x470, 0x801 },
+       { 0x470, 0x801 },
+       { 0x471, 0x1990 },
+       { 0x472, 0x801 },
+       { 0x472, 0x801 },
+       { 0x473, 0x1450 },
+       { 0x474, 0x801 },
+       { 0x474, 0x801 },
+       { 0x474, 0x801 },
+       { 0x475, 0x1020 },
+       { 0x476, 0x801 },
+       { 0x476, 0x801 },
+       { 0x476, 0x801 },
+       { 0x477, 0xcd0 },
+       { 0x478, 0x806 },
+       { 0x478, 0x806 },
+       { 0x479, 0xa30 },
+       { 0x47a, 0x806 },
+       { 0x47a, 0x806 },
+       { 0x47b, 0x810 },
+       { 0x47c, 0x80e },
+       { 0x47c, 0x80e },
+       { 0x47d, 0x510 },
+       { 0x47e, 0x81f },
+       { 0x47e, 0x81f },
+       { 0x2DB, 0x0A00 },
+       { 0x2DD, 0x0023 },
+       { 0x2DF, 0x0102 },
+       { 0x80, 0x0 },
+       { 0xC20, 0x0002 },
+       { 0x209, 0x002A },
+};
+
+/* We use a function so we can use ARRAY_SIZE() */
+int wm5110_patch(struct arizona *arizona)
+{
+       switch (arizona->rev) {
+       case 0:
+       case 1:
+               return regmap_register_patch(arizona->regmap,
+                                            wm5110_reva_patch,
+                                            ARRAY_SIZE(wm5110_reva_patch));
+       default:
+               return 0;
+       }
+}
+EXPORT_SYMBOL_GPL(wm5110_patch);
+
+static const struct regmap_irq wm5110_aod_irqs[ARIZONA_NUM_IRQ] = {
+       [ARIZONA_IRQ_GP5_FALL] = { .mask = ARIZONA_GP5_FALL_EINT1 },
+       [ARIZONA_IRQ_GP5_RISE] = { .mask = ARIZONA_GP5_RISE_EINT1 },
+       [ARIZONA_IRQ_JD_FALL] = { .mask = ARIZONA_JD1_FALL_EINT1 },
+       [ARIZONA_IRQ_JD_RISE] = { .mask = ARIZONA_JD1_RISE_EINT1 },
+};
+
+const struct regmap_irq_chip wm5110_aod = {
+       .name = "wm5110 AOD",
+       .status_base = ARIZONA_AOD_IRQ1,
+       .mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1,
+       .ack_base = ARIZONA_AOD_IRQ1,
+       .wake_base = ARIZONA_WAKE_CONTROL,
+       .num_regs = 1,
+       .irqs = wm5110_aod_irqs,
+       .num_irqs = ARRAY_SIZE(wm5110_aod_irqs),
+};
+EXPORT_SYMBOL_GPL(wm5110_aod);
+
+static const struct regmap_irq wm5110_irqs[ARIZONA_NUM_IRQ] = {
+       [ARIZONA_IRQ_GP4] = { .reg_offset = 0, .mask = ARIZONA_GP4_EINT1 },
+       [ARIZONA_IRQ_GP3] = { .reg_offset = 0, .mask = ARIZONA_GP3_EINT1 },
+       [ARIZONA_IRQ_GP2] = { .reg_offset = 0, .mask = ARIZONA_GP2_EINT1 },
+       [ARIZONA_IRQ_GP1] = { .reg_offset = 0, .mask = ARIZONA_GP1_EINT1 },
+
+       [ARIZONA_IRQ_DSP4_RAM_RDY] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP4_RAM_RDY_EINT1
+       },
+       [ARIZONA_IRQ_DSP3_RAM_RDY] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP3_RAM_RDY_EINT1
+       },
+       [ARIZONA_IRQ_DSP2_RAM_RDY] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP2_RAM_RDY_EINT1
+       },
+       [ARIZONA_IRQ_DSP1_RAM_RDY] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP1_RAM_RDY_EINT1
+       },
+       [ARIZONA_IRQ_DSP_IRQ8] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP_IRQ8_EINT1
+       },
+       [ARIZONA_IRQ_DSP_IRQ7] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP_IRQ7_EINT1
+       },
+       [ARIZONA_IRQ_DSP_IRQ6] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP_IRQ6_EINT1
+       },
+       [ARIZONA_IRQ_DSP_IRQ5] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP_IRQ5_EINT1
+       },
+       [ARIZONA_IRQ_DSP_IRQ4] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP_IRQ4_EINT1
+       },
+       [ARIZONA_IRQ_DSP_IRQ3] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP_IRQ3_EINT1
+       },
+       [ARIZONA_IRQ_DSP_IRQ2] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP_IRQ2_EINT1
+       },
+       [ARIZONA_IRQ_DSP_IRQ1] = {
+               .reg_offset = 1, .mask = ARIZONA_DSP_IRQ1_EINT1
+       },
+
+       [ARIZONA_IRQ_SPK_SHUTDOWN_WARN] = {
+               .reg_offset = 2, .mask = ARIZONA_SPK_SHUTDOWN_WARN_EINT1
+       },
+       [ARIZONA_IRQ_SPK_SHUTDOWN] = {
+               .reg_offset = 2, .mask = ARIZONA_SPK_SHUTDOWN_EINT1
+       },
+       [ARIZONA_IRQ_HPDET] = {
+               .reg_offset = 2, .mask = ARIZONA_HPDET_EINT1
+       },
+       [ARIZONA_IRQ_MICDET] = {
+               .reg_offset = 2, .mask = ARIZONA_MICDET_EINT1
+       },
+       [ARIZONA_IRQ_WSEQ_DONE] = {
+               .reg_offset = 2, .mask = ARIZONA_WSEQ_DONE_EINT1
+       },
+       [ARIZONA_IRQ_DRC2_SIG_DET] = {
+               .reg_offset = 2, .mask = ARIZONA_DRC2_SIG_DET_EINT1
+       },
+       [ARIZONA_IRQ_DRC1_SIG_DET] = {
+               .reg_offset = 2, .mask = ARIZONA_DRC1_SIG_DET_EINT1
+       },
+       [ARIZONA_IRQ_ASRC2_LOCK] = {
+               .reg_offset = 2, .mask = ARIZONA_ASRC2_LOCK_EINT1
+       },
+       [ARIZONA_IRQ_ASRC1_LOCK] = {
+               .reg_offset = 2, .mask = ARIZONA_ASRC1_LOCK_EINT1
+       },
+       [ARIZONA_IRQ_UNDERCLOCKED] = {
+               .reg_offset = 2, .mask = ARIZONA_UNDERCLOCKED_EINT1
+       },
+       [ARIZONA_IRQ_OVERCLOCKED] = {
+               .reg_offset = 2, .mask = ARIZONA_OVERCLOCKED_EINT1
+       },
+       [ARIZONA_IRQ_FLL2_LOCK] = {
+               .reg_offset = 2, .mask = ARIZONA_FLL2_LOCK_EINT1
+       },
+       [ARIZONA_IRQ_FLL1_LOCK] = {
+               .reg_offset = 2, .mask = ARIZONA_FLL1_LOCK_EINT1
+       },
+       [ARIZONA_IRQ_CLKGEN_ERR] = {
+               .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_EINT1
+       },
+       [ARIZONA_IRQ_CLKGEN_ERR_ASYNC] = {
+               .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_ASYNC_EINT1
+       },
+
+       [ARIZONA_IRQ_ASRC_CFG_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_ASRC_CFG_ERR_EINT1
+       },
+       [ARIZONA_IRQ_AIF3_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_AIF3_ERR_EINT1
+       },
+       [ARIZONA_IRQ_AIF2_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_AIF2_ERR_EINT1
+       },
+       [ARIZONA_IRQ_AIF1_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_AIF1_ERR_EINT1
+       },
+       [ARIZONA_IRQ_CTRLIF_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_CTRLIF_ERR_EINT1
+       },
+       [ARIZONA_IRQ_MIXER_DROPPED_SAMPLES] = {
+               .reg_offset = 3, .mask = ARIZONA_MIXER_DROPPED_SAMPLE_EINT1
+       },
+       [ARIZONA_IRQ_ASYNC_CLK_ENA_LOW] = {
+               .reg_offset = 3, .mask = ARIZONA_ASYNC_CLK_ENA_LOW_EINT1
+       },
+       [ARIZONA_IRQ_SYSCLK_ENA_LOW] = {
+               .reg_offset = 3, .mask = ARIZONA_SYSCLK_ENA_LOW_EINT1
+       },
+       [ARIZONA_IRQ_ISRC1_CFG_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_ISRC1_CFG_ERR_EINT1
+       },
+       [ARIZONA_IRQ_ISRC2_CFG_ERR] = {
+               .reg_offset = 3, .mask = ARIZONA_ISRC2_CFG_ERR_EINT1
+       },
+
+       [ARIZONA_IRQ_BOOT_DONE] = {
+               .reg_offset = 4, .mask = ARIZONA_BOOT_DONE_EINT1
+       },
+       [ARIZONA_IRQ_DCS_DAC_DONE] = {
+               .reg_offset = 4, .mask = ARIZONA_DCS_DAC_DONE_EINT1
+       },
+       [ARIZONA_IRQ_DCS_HP_DONE] = {
+               .reg_offset = 4, .mask = ARIZONA_DCS_HP_DONE_EINT1
+       },
+       [ARIZONA_IRQ_FLL2_CLOCK_OK] = {
+               .reg_offset = 4, .mask = ARIZONA_FLL2_CLOCK_OK_EINT1
+       },
+       [ARIZONA_IRQ_FLL1_CLOCK_OK] = {
+               .reg_offset = 4, .mask = ARIZONA_FLL1_CLOCK_OK_EINT1
+       },
+};
+
+const struct regmap_irq_chip wm5110_irq = {
+       .name = "wm5110 IRQ",
+       .status_base = ARIZONA_INTERRUPT_STATUS_1,
+       .mask_base = ARIZONA_INTERRUPT_STATUS_1_MASK,
+       .ack_base = ARIZONA_INTERRUPT_STATUS_1,
+       .num_regs = 5,
+       .irqs = wm5110_irqs,
+       .num_irqs = ARRAY_SIZE(wm5110_irqs),
+};
+EXPORT_SYMBOL_GPL(wm5110_irq);
+
+static const struct reg_default wm5110_reg_default[] = {
+       { 0x00000008, 0x0019 },    /* R8     - Ctrl IF SPI CFG 1 */
+       { 0x00000009, 0x0001 },    /* R9     - Ctrl IF I2C1 CFG 1 */
+       { 0x0000000A, 0x0001 },    /* R10    - Ctrl IF I2C2 CFG 1 */
+       { 0x0000000B, 0x0036 },    /* R11    - Ctrl IF I2C1 CFG 2 */
+       { 0x0000000C, 0x0036 },    /* R12    - Ctrl IF I2C2 CFG 2 */
+       { 0x00000016, 0x0000 },    /* R22    - Write Sequencer Ctrl 0 */
+       { 0x00000017, 0x0000 },    /* R23    - Write Sequencer Ctrl 1 */
+       { 0x00000018, 0x0000 },    /* R24    - Write Sequencer Ctrl 2 */
+       { 0x00000020, 0x0000 },    /* R32    - Tone Generator 1 */
+       { 0x00000021, 0x1000 },    /* R33    - Tone Generator 2 */
+       { 0x00000022, 0x0000 },    /* R34    - Tone Generator 3 */
+       { 0x00000023, 0x1000 },    /* R35    - Tone Generator 4 */
+       { 0x00000024, 0x0000 },    /* R36    - Tone Generator 5 */
+       { 0x00000030, 0x0000 },    /* R48    - PWM Drive 1 */
+       { 0x00000031, 0x0100 },    /* R49    - PWM Drive 2 */
+       { 0x00000032, 0x0100 },    /* R50    - PWM Drive 3 */
+       { 0x00000040, 0x0000 },    /* R64    - Wake control */
+       { 0x00000041, 0x0000 },    /* R65    - Sequence control */
+       { 0x00000061, 0x01FF },    /* R97    - Sample Rate Sequence Select 1 */
+       { 0x00000062, 0x01FF },    /* R98    - Sample Rate Sequence Select 2 */
+       { 0x00000063, 0x01FF },    /* R99    - Sample Rate Sequence Select 3 */
+       { 0x00000064, 0x01FF },    /* R100   - Sample Rate Sequence Select 4 */
+       { 0x00000068, 0x01FF },    /* R104   - Always On Triggers Sequence Select 1 */
+       { 0x00000069, 0x01FF },    /* R105   - Always On Triggers Sequence Select 2 */
+       { 0x0000006A, 0x01FF },    /* R106   - Always On Triggers Sequence Select 3 */
+       { 0x0000006B, 0x01FF },    /* R107   - Always On Triggers Sequence Select 4 */
+       { 0x00000070, 0x0000 },    /* R112   - Comfort Noise Generator */
+       { 0x00000090, 0x0000 },    /* R144   - Haptics Control 1 */
+       { 0x00000091, 0x7FFF },    /* R145   - Haptics Control 2 */
+       { 0x00000092, 0x0000 },    /* R146   - Haptics phase 1 intensity */
+       { 0x00000093, 0x0000 },    /* R147   - Haptics phase 1 duration */
+       { 0x00000094, 0x0000 },    /* R148   - Haptics phase 2 intensity */
+       { 0x00000095, 0x0000 },    /* R149   - Haptics phase 2 duration */
+       { 0x00000096, 0x0000 },    /* R150   - Haptics phase 3 intensity */
+       { 0x00000097, 0x0000 },    /* R151   - Haptics phase 3 duration */
+       { 0x00000100, 0x0001 },    /* R256   - Clock 32k 1 */
+       { 0x00000101, 0x0504 },    /* R257   - System Clock 1 */
+       { 0x00000102, 0x0011 },    /* R258   - Sample rate 1 */
+       { 0x00000103, 0x0011 },    /* R259   - Sample rate 2 */
+       { 0x00000104, 0x0011 },    /* R260   - Sample rate 3 */
+       { 0x00000112, 0x0305 },    /* R274   - Async clock 1 */
+       { 0x00000113, 0x0011 },    /* R275   - Async sample rate 1 */
+       { 0x00000149, 0x0000 },    /* R329   - Output system clock */
+       { 0x0000014A, 0x0000 },    /* R330   - Output async clock */
+       { 0x00000152, 0x0000 },    /* R338   - Rate Estimator 1 */
+       { 0x00000153, 0x0000 },    /* R339   - Rate Estimator 2 */
+       { 0x00000154, 0x0000 },    /* R340   - Rate Estimator 3 */
+       { 0x00000155, 0x0000 },    /* R341   - Rate Estimator 4 */
+       { 0x00000156, 0x0000 },    /* R342   - Rate Estimator 5 */
+       { 0x00000171, 0x0000 },    /* R369   - FLL1 Control 1 */
+       { 0x00000172, 0x0008 },    /* R370   - FLL1 Control 2 */
+       { 0x00000173, 0x0018 },    /* R371   - FLL1 Control 3 */
+       { 0x00000174, 0x007D },    /* R372   - FLL1 Control 4 */
+       { 0x00000175, 0x0006 },    /* R373   - FLL1 Control 5 */
+       { 0x00000176, 0x0000 },    /* R374   - FLL1 Control 6 */
+       { 0x00000177, 0x0281 },    /* R375   - FLL1 Loop Filter Test 1 */
+       { 0x00000178, 0x0000 },    /* R376   - FLL1 NCO Test 0 */
+       { 0x00000181, 0x0000 },    /* R385   - FLL1 Synchroniser 1 */
+       { 0x00000182, 0x0000 },    /* R386   - FLL1 Synchroniser 2 */
+       { 0x00000183, 0x0000 },    /* R387   - FLL1 Synchroniser 3 */
+       { 0x00000184, 0x0000 },    /* R388   - FLL1 Synchroniser 4 */
+       { 0x00000185, 0x0000 },    /* R389   - FLL1 Synchroniser 5 */
+       { 0x00000186, 0x0000 },    /* R390   - FLL1 Synchroniser 6 */
+       { 0x00000189, 0x0000 },    /* R393   - FLL1 Spread Spectrum */
+       { 0x0000018A, 0x0004 },    /* R394   - FLL1 GPIO Clock */
+       { 0x00000191, 0x0000 },    /* R401   - FLL2 Control 1 */
+       { 0x00000192, 0x0008 },    /* R402   - FLL2 Control 2 */
+       { 0x00000193, 0x0018 },    /* R403   - FLL2 Control 3 */
+       { 0x00000194, 0x007D },    /* R404   - FLL2 Control 4 */
+       { 0x00000195, 0x000C },    /* R405   - FLL2 Control 5 */
+       { 0x00000196, 0x0000 },    /* R406   - FLL2 Control 6 */
+       { 0x00000197, 0x0000 },    /* R407   - FLL2 Loop Filter Test 1 */
+       { 0x00000198, 0x0000 },    /* R408   - FLL2 NCO Test 0 */
+       { 0x000001A1, 0x0000 },    /* R417   - FLL2 Synchroniser 1 */
+       { 0x000001A2, 0x0000 },    /* R418   - FLL2 Synchroniser 2 */
+       { 0x000001A3, 0x0000 },    /* R419   - FLL2 Synchroniser 3 */
+       { 0x000001A4, 0x0000 },    /* R420   - FLL2 Synchroniser 4 */
+       { 0x000001A5, 0x0000 },    /* R421   - FLL2 Synchroniser 5 */
+       { 0x000001A6, 0x0000 },    /* R422   - FLL2 Synchroniser 6 */
+       { 0x000001A9, 0x0000 },    /* R425   - FLL2 Spread Spectrum */
+       { 0x000001AA, 0x0004 },    /* R426   - FLL2 GPIO Clock */
+       { 0x00000200, 0x0006 },    /* R512   - Mic Charge Pump 1 */
+       { 0x00000210, 0x0184 },    /* R528   - LDO1 Control 1 */
+       { 0x00000213, 0x0344 },    /* R531   - LDO2 Control 1 */
+       { 0x00000218, 0x01A6 },    /* R536   - Mic Bias Ctrl 1 */
+       { 0x00000219, 0x01A6 },    /* R537   - Mic Bias Ctrl 2 */
+       { 0x0000021A, 0x01A6 },    /* R538   - Mic Bias Ctrl 3 */
+       { 0x00000293, 0x0000 },    /* R659   - Accessory Detect Mode 1 */
+       { 0x0000029B, 0x0020 },    /* R667   - Headphone Detect 1 */
+       { 0x0000029C, 0x0000 },    /* R668   - Headphone Detect 2 */
+       { 0x000002A3, 0x1102 },    /* R675   - Mic Detect 1 */
+       { 0x000002A4, 0x009F },    /* R676   - Mic Detect 2 */
+       { 0x000002C3, 0x0000 },    /* R707   - Mic noise mix control 1 */
+       { 0x000002D3, 0x0000 },    /* R723   - Jack detect analogue */
+       { 0x00000300, 0x0000 },    /* R768   - Input Enables */
+       { 0x00000308, 0x0000 },    /* R776   - Input Rate */
+       { 0x00000309, 0x0022 },    /* R777   - Input Volume Ramp */
+       { 0x00000310, 0x2080 },    /* R784   - IN1L Control */
+       { 0x00000311, 0x0180 },    /* R785   - ADC Digital Volume 1L */
+       { 0x00000312, 0x0000 },    /* R786   - DMIC1L Control */
+       { 0x00000314, 0x0080 },    /* R788   - IN1R Control */
+       { 0x00000315, 0x0180 },    /* R789   - ADC Digital Volume 1R */
+       { 0x00000316, 0x0000 },    /* R790   - DMIC1R Control */
+       { 0x00000318, 0x2080 },    /* R792   - IN2L Control */
+       { 0x00000319, 0x0180 },    /* R793   - ADC Digital Volume 2L */
+       { 0x0000031A, 0x0000 },    /* R794   - DMIC2L Control */
+       { 0x0000031C, 0x0080 },    /* R796   - IN2R Control */
+       { 0x0000031D, 0x0180 },    /* R797   - ADC Digital Volume 2R */
+       { 0x0000031E, 0x0000 },    /* R798   - DMIC2R Control */
+       { 0x00000320, 0x2080 },    /* R800   - IN3L Control */
+       { 0x00000321, 0x0180 },    /* R801   - ADC Digital Volume 3L */
+       { 0x00000322, 0x0000 },    /* R802   - DMIC3L Control */
+       { 0x00000324, 0x0080 },    /* R804   - IN3R Control */
+       { 0x00000325, 0x0180 },    /* R805   - ADC Digital Volume 3R */
+       { 0x00000326, 0x0000 },    /* R806   - DMIC3R Control */
+       { 0x00000328, 0x2000 },    /* R808   - IN4L Control */
+       { 0x00000329, 0x0180 },    /* R809   - ADC Digital Volume 4L */
+       { 0x0000032A, 0x0000 },    /* R810   - DMIC4L Control */
+       { 0x0000032D, 0x0180 },    /* R813   - ADC Digital Volume 4R */
+       { 0x0000032E, 0x0000 },    /* R814   - DMIC4R Control */
+       { 0x00000400, 0x0000 },    /* R1024  - Output Enables 1 */
+       { 0x00000408, 0x0000 },    /* R1032  - Output Rate 1 */
+       { 0x00000409, 0x0022 },    /* R1033  - Output Volume Ramp */
+       { 0x00000410, 0x0080 },    /* R1040  - Output Path Config 1L */
+       { 0x00000411, 0x0180 },    /* R1041  - DAC Digital Volume 1L */
+       { 0x00000412, 0x0080 },    /* R1042  - DAC Volume Limit 1L */
+       { 0x00000413, 0x0001 },    /* R1043  - Noise Gate Select 1L */
+       { 0x00000414, 0x0080 },    /* R1044  - Output Path Config 1R */
+       { 0x00000415, 0x0180 },    /* R1045  - DAC Digital Volume 1R */
+       { 0x00000416, 0x0080 },    /* R1046  - DAC Volume Limit 1R */
+       { 0x00000417, 0x0002 },    /* R1047  - Noise Gate Select 1R */
+       { 0x00000418, 0x0080 },    /* R1048  - Output Path Config 2L */
+       { 0x00000419, 0x0180 },    /* R1049  - DAC Digital Volume 2L */
+       { 0x0000041A, 0x0080 },    /* R1050  - DAC Volume Limit 2L */
+       { 0x0000041B, 0x0004 },    /* R1051  - Noise Gate Select 2L */
+       { 0x0000041C, 0x0080 },    /* R1052  - Output Path Config 2R */
+       { 0x0000041D, 0x0180 },    /* R1053  - DAC Digital Volume 2R */
+       { 0x0000041E, 0x0080 },    /* R1054  - DAC Volume Limit 2R */
+       { 0x0000041F, 0x0008 },    /* R1055  - Noise Gate Select 2R */
+       { 0x00000420, 0x0080 },    /* R1056  - Output Path Config 3L */
+       { 0x00000421, 0x0180 },    /* R1057  - DAC Digital Volume 3L */
+       { 0x00000422, 0x0080 },    /* R1058  - DAC Volume Limit 3L */
+       { 0x00000423, 0x0010 },    /* R1059  - Noise Gate Select 3L */
+       { 0x00000424, 0x0080 },    /* R1060  - Output Path Config 3R */
+       { 0x00000425, 0x0180 },    /* R1061  - DAC Digital Volume 3R */
+       { 0x00000426, 0x0080 },    /* R1062  - DAC Volume Limit 3R */
+       { 0x00000427, 0x0020 },    /* R1063  - Noise Gate Select 3R */
+       { 0x00000428, 0x0000 },    /* R1064  - Output Path Config 4L */
+       { 0x00000429, 0x0180 },    /* R1065  - DAC Digital Volume 4L */
+       { 0x0000042A, 0x0080 },    /* R1066  - Out Volume 4L */
+       { 0x0000042B, 0x0040 },    /* R1067  - Noise Gate Select 4L */
+       { 0x0000042C, 0x0000 },    /* R1068  - Output Path Config 4R */
+       { 0x0000042D, 0x0180 },    /* R1069  - DAC Digital Volume 4R */
+       { 0x0000042E, 0x0080 },    /* R1070  - Out Volume 4R */
+       { 0x0000042F, 0x0080 },    /* R1071  - Noise Gate Select 4R */
+       { 0x00000430, 0x0000 },    /* R1072  - Output Path Config 5L */
+       { 0x00000431, 0x0180 },    /* R1073  - DAC Digital Volume 5L */
+       { 0x00000432, 0x0080 },    /* R1074  - DAC Volume Limit 5L */
+       { 0x00000433, 0x0100 },    /* R1075  - Noise Gate Select 5L */
+       { 0x00000434, 0x0000 },    /* R1076  - Output Path Config 5R */
+       { 0x00000435, 0x0180 },    /* R1077  - DAC Digital Volume 5R */
+       { 0x00000436, 0x0080 },    /* R1078  - DAC Volume Limit 5R */
+       { 0x00000437, 0x0200 },    /* R1079  - Noise Gate Select 5R */
+       { 0x00000438, 0x0000 },    /* R1080  - Output Path Config 6L */
+       { 0x00000439, 0x0180 },    /* R1081  - DAC Digital Volume 6L */
+       { 0x0000043A, 0x0080 },    /* R1082  - DAC Volume Limit 6L */
+       { 0x0000043B, 0x0400 },    /* R1083  - Noise Gate Select 6L */
+       { 0x0000043C, 0x0000 },    /* R1084  - Output Path Config 6R */
+       { 0x0000043D, 0x0180 },    /* R1085  - DAC Digital Volume 6R */
+       { 0x0000043E, 0x0080 },    /* R1086  - DAC Volume Limit 6R */
+       { 0x0000043F, 0x0800 },    /* R1087  - Noise Gate Select 6R */
+       { 0x00000450, 0x0000 },    /* R1104  - DAC AEC Control 1 */
+       { 0x00000458, 0x0001 },    /* R1112  - Noise Gate Control */
+       { 0x00000480, 0x0040 },    /* R1152  - Class W ANC Threshold 1 */
+       { 0x00000481, 0x0040 },    /* R1153  - Class W ANC Threshold 2 */
+       { 0x00000490, 0x0069 },    /* R1168  - PDM SPK1 CTRL 1 */
+       { 0x00000491, 0x0000 },    /* R1169  - PDM SPK1 CTRL 2 */
+       { 0x00000492, 0x0069 },    /* R1170  - PDM SPK2 CTRL 1 */
+       { 0x00000493, 0x0000 },    /* R1171  - PDM SPK2 CTRL 2 */
+       { 0x00000500, 0x000C },    /* R1280  - AIF1 BCLK Ctrl */
+       { 0x00000501, 0x0008 },    /* R1281  - AIF1 Tx Pin Ctrl */
+       { 0x00000502, 0x0000 },    /* R1282  - AIF1 Rx Pin Ctrl */
+       { 0x00000503, 0x0000 },    /* R1283  - AIF1 Rate Ctrl */
+       { 0x00000504, 0x0000 },    /* R1284  - AIF1 Format */
+       { 0x00000505, 0x0040 },    /* R1285  - AIF1 Tx BCLK Rate */
+       { 0x00000506, 0x0040 },    /* R1286  - AIF1 Rx BCLK Rate */
+       { 0x00000507, 0x1818 },    /* R1287  - AIF1 Frame Ctrl 1 */
+       { 0x00000508, 0x1818 },    /* R1288  - AIF1 Frame Ctrl 2 */
+       { 0x00000509, 0x0000 },    /* R1289  - AIF1 Frame Ctrl 3 */
+       { 0x0000050A, 0x0001 },    /* R1290  - AIF1 Frame Ctrl 4 */
+       { 0x0000050B, 0x0002 },    /* R1291  - AIF1 Frame Ctrl 5 */
+       { 0x0000050C, 0x0003 },    /* R1292  - AIF1 Frame Ctrl 6 */
+       { 0x0000050D, 0x0004 },    /* R1293  - AIF1 Frame Ctrl 7 */
+       { 0x0000050E, 0x0005 },    /* R1294  - AIF1 Frame Ctrl 8 */
+       { 0x0000050F, 0x0006 },    /* R1295  - AIF1 Frame Ctrl 9 */
+       { 0x00000510, 0x0007 },    /* R1296  - AIF1 Frame Ctrl 10 */
+       { 0x00000511, 0x0000 },    /* R1297  - AIF1 Frame Ctrl 11 */
+       { 0x00000512, 0x0001 },    /* R1298  - AIF1 Frame Ctrl 12 */
+       { 0x00000513, 0x0002 },    /* R1299  - AIF1 Frame Ctrl 13 */
+       { 0x00000514, 0x0003 },    /* R1300  - AIF1 Frame Ctrl 14 */
+       { 0x00000515, 0x0004 },    /* R1301  - AIF1 Frame Ctrl 15 */
+       { 0x00000516, 0x0005 },    /* R1302  - AIF1 Frame Ctrl 16 */
+       { 0x00000517, 0x0006 },    /* R1303  - AIF1 Frame Ctrl 17 */
+       { 0x00000518, 0x0007 },    /* R1304  - AIF1 Frame Ctrl 18 */
+       { 0x00000519, 0x0000 },    /* R1305  - AIF1 Tx Enables */
+       { 0x0000051A, 0x0000 },    /* R1306  - AIF1 Rx Enables */
+       { 0x00000540, 0x000C },    /* R1344  - AIF2 BCLK Ctrl */
+       { 0x00000541, 0x0008 },    /* R1345  - AIF2 Tx Pin Ctrl */
+       { 0x00000542, 0x0000 },    /* R1346  - AIF2 Rx Pin Ctrl */
+       { 0x00000543, 0x0000 },    /* R1347  - AIF2 Rate Ctrl */
+       { 0x00000544, 0x0000 },    /* R1348  - AIF2 Format */
+       { 0x00000545, 0x0040 },    /* R1349  - AIF2 Tx BCLK Rate */
+       { 0x00000546, 0x0040 },    /* R1350  - AIF2 Rx BCLK Rate */
+       { 0x00000547, 0x1818 },    /* R1351  - AIF2 Frame Ctrl 1 */
+       { 0x00000548, 0x1818 },    /* R1352  - AIF2 Frame Ctrl 2 */
+       { 0x00000549, 0x0000 },    /* R1353  - AIF2 Frame Ctrl 3 */
+       { 0x0000054A, 0x0001 },    /* R1354  - AIF2 Frame Ctrl 4 */
+       { 0x00000551, 0x0000 },    /* R1361  - AIF2 Frame Ctrl 11 */
+       { 0x00000552, 0x0001 },    /* R1362  - AIF2 Frame Ctrl 12 */
+       { 0x00000559, 0x0000 },    /* R1369  - AIF2 Tx Enables */
+       { 0x0000055A, 0x0000 },    /* R1370  - AIF2 Rx Enables */
+       { 0x00000580, 0x000C },    /* R1408  - AIF3 BCLK Ctrl */
+       { 0x00000581, 0x0008 },    /* R1409  - AIF3 Tx Pin Ctrl */
+       { 0x00000582, 0x0000 },    /* R1410  - AIF3 Rx Pin Ctrl */
+       { 0x00000583, 0x0000 },    /* R1411  - AIF3 Rate Ctrl */
+       { 0x00000584, 0x0000 },    /* R1412  - AIF3 Format */
+       { 0x00000585, 0x0040 },    /* R1413  - AIF3 Tx BCLK Rate */
+       { 0x00000586, 0x0040 },    /* R1414  - AIF3 Rx BCLK Rate */
+       { 0x00000587, 0x1818 },    /* R1415  - AIF3 Frame Ctrl 1 */
+       { 0x00000588, 0x1818 },    /* R1416  - AIF3 Frame Ctrl 2 */
+       { 0x00000589, 0x0000 },    /* R1417  - AIF3 Frame Ctrl 3 */
+       { 0x0000058A, 0x0001 },    /* R1418  - AIF3 Frame Ctrl 4 */
+       { 0x00000591, 0x0000 },    /* R1425  - AIF3 Frame Ctrl 11 */
+       { 0x00000592, 0x0001 },    /* R1426  - AIF3 Frame Ctrl 12 */
+       { 0x00000599, 0x0000 },    /* R1433  - AIF3 Tx Enables */
+       { 0x0000059A, 0x0000 },    /* R1434  - AIF3 Rx Enables */
+       { 0x000005E3, 0x0004 },    /* R1507  - SLIMbus Framer Ref Gear */
+       { 0x000005E5, 0x0000 },    /* R1509  - SLIMbus Rates 1 */
+       { 0x000005E6, 0x0000 },    /* R1510  - SLIMbus Rates 2 */
+       { 0x000005E7, 0x0000 },    /* R1511  - SLIMbus Rates 3 */
+       { 0x000005E8, 0x0000 },    /* R1512  - SLIMbus Rates 4 */
+       { 0x000005E9, 0x0000 },    /* R1513  - SLIMbus Rates 5 */
+       { 0x000005EA, 0x0000 },    /* R1514  - SLIMbus Rates 6 */
+       { 0x000005EB, 0x0000 },    /* R1515  - SLIMbus Rates 7 */
+       { 0x000005EC, 0x0000 },    /* R1516  - SLIMbus Rates 8 */
+       { 0x000005F5, 0x0000 },    /* R1525  - SLIMbus RX Channel Enable */
+       { 0x000005F6, 0x0000 },    /* R1526  - SLIMbus TX Channel Enable */
+       { 0x00000640, 0x0000 },    /* R1600  - PWM1MIX Input 1 Source */
+       { 0x00000641, 0x0080 },    /* R1601  - PWM1MIX Input 1 Volume */
+       { 0x00000642, 0x0000 },    /* R1602  - PWM1MIX Input 2 Source */
+       { 0x00000643, 0x0080 },    /* R1603  - PWM1MIX Input 2 Volume */
+       { 0x00000644, 0x0000 },    /* R1604  - PWM1MIX Input 3 Source */
+       { 0x00000645, 0x0080 },    /* R1605  - PWM1MIX Input 3 Volume */
+       { 0x00000646, 0x0000 },    /* R1606  - PWM1MIX Input 4 Source */
+       { 0x00000647, 0x0080 },    /* R1607  - PWM1MIX Input 4 Volume */
+       { 0x00000648, 0x0000 },    /* R1608  - PWM2MIX Input 1 Source */
+       { 0x00000649, 0x0080 },    /* R1609  - PWM2MIX Input 1 Volume */
+       { 0x0000064A, 0x0000 },    /* R1610  - PWM2MIX Input 2 Source */
+       { 0x0000064B, 0x0080 },    /* R1611  - PWM2MIX Input 2 Volume */
+       { 0x0000064C, 0x0000 },    /* R1612  - PWM2MIX Input 3 Source */
+       { 0x0000064D, 0x0080 },    /* R1613  - PWM2MIX Input 3 Volume */
+       { 0x0000064E, 0x0000 },    /* R1614  - PWM2MIX Input 4 Source */
+       { 0x0000064F, 0x0080 },    /* R1615  - PWM2MIX Input 4 Volume */
+       { 0x00000660, 0x0000 },    /* R1632  - MICMIX Input 1 Source */
+       { 0x00000661, 0x0080 },    /* R1633  - MICMIX Input 1 Volume */
+       { 0x00000662, 0x0000 },    /* R1634  - MICMIX Input 2 Source */
+       { 0x00000663, 0x0080 },    /* R1635  - MICMIX Input 2 Volume */
+       { 0x00000664, 0x0000 },    /* R1636  - MICMIX Input 3 Source */
+       { 0x00000665, 0x0080 },    /* R1637  - MICMIX Input 3 Volume */
+       { 0x00000666, 0x0000 },    /* R1638  - MICMIX Input 4 Source */
+       { 0x00000667, 0x0080 },    /* R1639  - MICMIX Input 4 Volume */
+       { 0x00000668, 0x0000 },    /* R1640  - NOISEMIX Input 1 Source */
+       { 0x00000669, 0x0080 },    /* R1641  - NOISEMIX Input 1 Volume */
+       { 0x0000066A, 0x0000 },    /* R1642  - NOISEMIX Input 2 Source */
+       { 0x0000066B, 0x0080 },    /* R1643  - NOISEMIX Input 2 Volume */
+       { 0x0000066C, 0x0000 },    /* R1644  - NOISEMIX Input 3 Source */
+       { 0x0000066D, 0x0080 },    /* R1645  - NOISEMIX Input 3 Volume */
+       { 0x0000066E, 0x0000 },    /* R1646  - NOISEMIX Input 4 Source */
+       { 0x0000066F, 0x0080 },    /* R1647  - NOISEMIX Input 4 Volume */
+       { 0x00000680, 0x0000 },    /* R1664  - OUT1LMIX Input 1 Source */
+       { 0x00000681, 0x0080 },    /* R1665  - OUT1LMIX Input 1 Volume */
+       { 0x00000682, 0x0000 },    /* R1666  - OUT1LMIX Input 2 Source */
+       { 0x00000683, 0x0080 },    /* R1667  - OUT1LMIX Input 2 Volume */
+       { 0x00000684, 0x0000 },    /* R1668  - OUT1LMIX Input 3 Source */
+       { 0x00000685, 0x0080 },    /* R1669  - OUT1LMIX Input 3 Volume */
+       { 0x00000686, 0x0000 },    /* R1670  - OUT1LMIX Input 4 Source */
+       { 0x00000687, 0x0080 },    /* R1671  - OUT1LMIX Input 4 Volume */
+       { 0x00000688, 0x0000 },    /* R1672  - OUT1RMIX Input 1 Source */
+       { 0x00000689, 0x0080 },    /* R1673  - OUT1RMIX Input 1 Volume */
+       { 0x0000068A, 0x0000 },    /* R1674  - OUT1RMIX Input 2 Source */
+       { 0x0000068B, 0x0080 },    /* R1675  - OUT1RMIX Input 2 Volume */
+       { 0x0000068C, 0x0000 },    /* R1676  - OUT1RMIX Input 3 Source */
+       { 0x0000068D, 0x0080 },    /* R1677  - OUT1RMIX Input 3 Volume */
+       { 0x0000068E, 0x0000 },    /* R1678  - OUT1RMIX Input 4 Source */
+       { 0x0000068F, 0x0080 },    /* R1679  - OUT1RMIX Input 4 Volume */
+       { 0x00000690, 0x0000 },    /* R1680  - OUT2LMIX Input 1 Source */
+       { 0x00000691, 0x0080 },    /* R1681  - OUT2LMIX Input 1 Volume */
+       { 0x00000692, 0x0000 },    /* R1682  - OUT2LMIX Input 2 Source */
+       { 0x00000693, 0x0080 },    /* R1683  - OUT2LMIX Input 2 Volume */
+       { 0x00000694, 0x0000 },    /* R1684  - OUT2LMIX Input 3 Source */
+       { 0x00000695, 0x0080 },    /* R1685  - OUT2LMIX Input 3 Volume */
+       { 0x00000696, 0x0000 },    /* R1686  - OUT2LMIX Input 4 Source */
+       { 0x00000697, 0x0080 },    /* R1687  - OUT2LMIX Input 4 Volume */
+       { 0x00000698, 0x0000 },    /* R1688  - OUT2RMIX Input 1 Source */
+       { 0x00000699, 0x0080 },    /* R1689  - OUT2RMIX Input 1 Volume */
+       { 0x0000069A, 0x0000 },    /* R1690  - OUT2RMIX Input 2 Source */
+       { 0x0000069B, 0x0080 },    /* R1691  - OUT2RMIX Input 2 Volume */
+       { 0x0000069C, 0x0000 },    /* R1692  - OUT2RMIX Input 3 Source */
+       { 0x0000069D, 0x0080 },    /* R1693  - OUT2RMIX Input 3 Volume */
+       { 0x0000069E, 0x0000 },    /* R1694  - OUT2RMIX Input 4 Source */
+       { 0x0000069F, 0x0080 },    /* R1695  - OUT2RMIX Input 4 Volume */
+       { 0x000006A0, 0x0000 },    /* R1696  - OUT3LMIX Input 1 Source */
+       { 0x000006A1, 0x0080 },    /* R1697  - OUT3LMIX Input 1 Volume */
+       { 0x000006A2, 0x0000 },    /* R1698  - OUT3LMIX Input 2 Source */
+       { 0x000006A3, 0x0080 },    /* R1699  - OUT3LMIX Input 2 Volume */
+       { 0x000006A4, 0x0000 },    /* R1700  - OUT3LMIX Input 3 Source */
+       { 0x000006A5, 0x0080 },    /* R1701  - OUT3LMIX Input 3 Volume */
+       { 0x000006A6, 0x0000 },    /* R1702  - OUT3LMIX Input 4 Source */
+       { 0x000006A7, 0x0080 },    /* R1703  - OUT3LMIX Input 4 Volume */
+       { 0x000006A8, 0x0000 },    /* R1704  - OUT3RMIX Input 1 Source */
+       { 0x000006A9, 0x0080 },    /* R1705  - OUT3RMIX Input 1 Volume */
+       { 0x000006AA, 0x0000 },    /* R1706  - OUT3RMIX Input 2 Source */
+       { 0x000006AB, 0x0080 },    /* R1707  - OUT3RMIX Input 2 Volume */
+       { 0x000006AC, 0x0000 },    /* R1708  - OUT3RMIX Input 3 Source */
+       { 0x000006AD, 0x0080 },    /* R1709  - OUT3RMIX Input 3 Volume */
+       { 0x000006AE, 0x0000 },    /* R1710  - OUT3RMIX Input 4 Source */
+       { 0x000006AF, 0x0080 },    /* R1711  - OUT3RMIX Input 4 Volume */
+       { 0x000006B0, 0x0000 },    /* R1712  - OUT4LMIX Input 1 Source */
+       { 0x000006B1, 0x0080 },    /* R1713  - OUT4LMIX Input 1 Volume */
+       { 0x000006B2, 0x0000 },    /* R1714  - OUT4LMIX Input 2 Source */
+       { 0x000006B3, 0x0080 },    /* R1715  - OUT4LMIX Input 2 Volume */
+       { 0x000006B4, 0x0000 },    /* R1716  - OUT4LMIX Input 3 Source */
+       { 0x000006B5, 0x0080 },    /* R1717  - OUT4LMIX Input 3 Volume */
+       { 0x000006B6, 0x0000 },    /* R1718  - OUT4LMIX Input 4 Source */
+       { 0x000006B7, 0x0080 },    /* R1719  - OUT4LMIX Input 4 Volume */
+       { 0x000006B8, 0x0000 },    /* R1720  - OUT4RMIX Input 1 Source */
+       { 0x000006B9, 0x0080 },    /* R1721  - OUT4RMIX Input 1 Volume */
+       { 0x000006BA, 0x0000 },    /* R1722  - OUT4RMIX Input 2 Source */
+       { 0x000006BB, 0x0080 },    /* R1723  - OUT4RMIX Input 2 Volume */
+       { 0x000006BC, 0x0000 },    /* R1724  - OUT4RMIX Input 3 Source */
+       { 0x000006BD, 0x0080 },    /* R1725  - OUT4RMIX Input 3 Volume */
+       { 0x000006BE, 0x0000 },    /* R1726  - OUT4RMIX Input 4 Source */
+       { 0x000006BF, 0x0080 },    /* R1727  - OUT4RMIX Input 4 Volume */
+       { 0x000006C0, 0x0000 },    /* R1728  - OUT5LMIX Input 1 Source */
+       { 0x000006C1, 0x0080 },    /* R1729  - OUT5LMIX Input 1 Volume */
+       { 0x000006C2, 0x0000 },    /* R1730  - OUT5LMIX Input 2 Source */
+       { 0x000006C3, 0x0080 },    /* R1731  - OUT5LMIX Input 2 Volume */
+       { 0x000006C4, 0x0000 },    /* R1732  - OUT5LMIX Input 3 Source */
+       { 0x000006C5, 0x0080 },    /* R1733  - OUT5LMIX Input 3 Volume */
+       { 0x000006C6, 0x0000 },    /* R1734  - OUT5LMIX Input 4 Source */
+       { 0x000006C7, 0x0080 },    /* R1735  - OUT5LMIX Input 4 Volume */
+       { 0x000006C8, 0x0000 },    /* R1736  - OUT5RMIX Input 1 Source */
+       { 0x000006C9, 0x0080 },    /* R1737  - OUT5RMIX Input 1 Volume */
+       { 0x000006CA, 0x0000 },    /* R1738  - OUT5RMIX Input 2 Source */
+       { 0x000006CB, 0x0080 },    /* R1739  - OUT5RMIX Input 2 Volume */
+       { 0x000006CC, 0x0000 },    /* R1740  - OUT5RMIX Input 3 Source */
+       { 0x000006CD, 0x0080 },    /* R1741  - OUT5RMIX Input 3 Volume */
+       { 0x000006CE, 0x0000 },    /* R1742  - OUT5RMIX Input 4 Source */
+       { 0x000006CF, 0x0080 },    /* R1743  - OUT5RMIX Input 4 Volume */
+       { 0x000006D0, 0x0000 },    /* R1744  - OUT6LMIX Input 1 Source */
+       { 0x000006D1, 0x0080 },    /* R1745  - OUT6LMIX Input 1 Volume */
+       { 0x000006D2, 0x0000 },    /* R1746  - OUT6LMIX Input 2 Source */
+       { 0x000006D3, 0x0080 },    /* R1747  - OUT6LMIX Input 2 Volume */
+       { 0x000006D4, 0x0000 },    /* R1748  - OUT6LMIX Input 3 Source */
+       { 0x000006D5, 0x0080 },    /* R1749  - OUT6LMIX Input 3 Volume */
+       { 0x000006D6, 0x0000 },    /* R1750  - OUT6LMIX Input 4 Source */
+       { 0x000006D7, 0x0080 },    /* R1751  - OUT6LMIX Input 4 Volume */
+       { 0x000006D8, 0x0000 },    /* R1752  - OUT6RMIX Input 1 Source */
+       { 0x000006D9, 0x0080 },    /* R1753  - OUT6RMIX Input 1 Volume */
+       { 0x000006DA, 0x0000 },    /* R1754  - OUT6RMIX Input 2 Source */
+       { 0x000006DB, 0x0080 },    /* R1755  - OUT6RMIX Input 2 Volume */
+       { 0x000006DC, 0x0000 },    /* R1756  - OUT6RMIX Input 3 Source */
+       { 0x000006DD, 0x0080 },    /* R1757  - OUT6RMIX Input 3 Volume */
+       { 0x000006DE, 0x0000 },    /* R1758  - OUT6RMIX Input 4 Source */
+       { 0x000006DF, 0x0080 },    /* R1759  - OUT6RMIX Input 4 Volume */
+       { 0x00000700, 0x0000 },    /* R1792  - AIF1TX1MIX Input 1 Source */
+       { 0x00000701, 0x0080 },    /* R1793  - AIF1TX1MIX Input 1 Volume */
+       { 0x00000702, 0x0000 },    /* R1794  - AIF1TX1MIX Input 2 Source */
+       { 0x00000703, 0x0080 },    /* R1795  - AIF1TX1MIX Input 2 Volume */
+       { 0x00000704, 0x0000 },    /* R1796  - AIF1TX1MIX Input 3 Source */
+       { 0x00000705, 0x0080 },    /* R1797  - AIF1TX1MIX Input 3 Volume */
+       { 0x00000706, 0x0000 },    /* R1798  - AIF1TX1MIX Input 4 Source */
+       { 0x00000707, 0x0080 },    /* R1799  - AIF1TX1MIX Input 4 Volume */
+       { 0x00000708, 0x0000 },    /* R1800  - AIF1TX2MIX Input 1 Source */
+       { 0x00000709, 0x0080 },    /* R1801  - AIF1TX2MIX Input 1 Volume */
+       { 0x0000070A, 0x0000 },    /* R1802  - AIF1TX2MIX Input 2 Source */
+       { 0x0000070B, 0x0080 },    /* R1803  - AIF1TX2MIX Input 2 Volume */
+       { 0x0000070C, 0x0000 },    /* R1804  - AIF1TX2MIX Input 3 Source */
+       { 0x0000070D, 0x0080 },    /* R1805  - AIF1TX2MIX Input 3 Volume */
+       { 0x0000070E, 0x0000 },    /* R1806  - AIF1TX2MIX Input 4 Source */
+       { 0x0000070F, 0x0080 },    /* R1807  - AIF1TX2MIX Input 4 Volume */
+       { 0x00000710, 0x0000 },    /* R1808  - AIF1TX3MIX Input 1 Source */
+       { 0x00000711, 0x0080 },    /* R1809  - AIF1TX3MIX Input 1 Volume */
+       { 0x00000712, 0x0000 },    /* R1810  - AIF1TX3MIX Input 2 Source */
+       { 0x00000713, 0x0080 },    /* R1811  - AIF1TX3MIX Input 2 Volume */
+       { 0x00000714, 0x0000 },    /* R1812  - AIF1TX3MIX Input 3 Source */
+       { 0x00000715, 0x0080 },    /* R1813  - AIF1TX3MIX Input 3 Volume */
+       { 0x00000716, 0x0000 },    /* R1814  - AIF1TX3MIX Input 4 Source */
+       { 0x00000717, 0x0080 },    /* R1815  - AIF1TX3MIX Input 4 Volume */
+       { 0x00000718, 0x0000 },    /* R1816  - AIF1TX4MIX Input 1 Source */
+       { 0x00000719, 0x0080 },    /* R1817  - AIF1TX4MIX Input 1 Volume */
+       { 0x0000071A, 0x0000 },    /* R1818  - AIF1TX4MIX Input 2 Source */
+       { 0x0000071B, 0x0080 },    /* R1819  - AIF1TX4MIX Input 2 Volume */
+       { 0x0000071C, 0x0000 },    /* R1820  - AIF1TX4MIX Input 3 Source */
+       { 0x0000071D, 0x0080 },    /* R1821  - AIF1TX4MIX Input 3 Volume */
+       { 0x0000071E, 0x0000 },    /* R1822  - AIF1TX4MIX Input 4 Source */
+       { 0x0000071F, 0x0080 },    /* R1823  - AIF1TX4MIX Input 4 Volume */
+       { 0x00000720, 0x0000 },    /* R1824  - AIF1TX5MIX Input 1 Source */
+       { 0x00000721, 0x0080 },    /* R1825  - AIF1TX5MIX Input 1 Volume */
+       { 0x00000722, 0x0000 },    /* R1826  - AIF1TX5MIX Input 2 Source */
+       { 0x00000723, 0x0080 },    /* R1827  - AIF1TX5MIX Input 2 Volume */
+       { 0x00000724, 0x0000 },    /* R1828  - AIF1TX5MIX Input 3 Source */
+       { 0x00000725, 0x0080 },    /* R1829  - AIF1TX5MIX Input 3 Volume */
+       { 0x00000726, 0x0000 },    /* R1830  - AIF1TX5MIX Input 4 Source */
+       { 0x00000727, 0x0080 },    /* R1831  - AIF1TX5MIX Input 4 Volume */
+       { 0x00000728, 0x0000 },    /* R1832  - AIF1TX6MIX Input 1 Source */
+       { 0x00000729, 0x0080 },    /* R1833  - AIF1TX6MIX Input 1 Volume */
+       { 0x0000072A, 0x0000 },    /* R1834  - AIF1TX6MIX Input 2 Source */
+       { 0x0000072B, 0x0080 },    /* R1835  - AIF1TX6MIX Input 2 Volume */
+       { 0x0000072C, 0x0000 },    /* R1836  - AIF1TX6MIX Input 3 Source */
+       { 0x0000072D, 0x0080 },    /* R1837  - AIF1TX6MIX Input 3 Volume */
+       { 0x0000072E, 0x0000 },    /* R1838  - AIF1TX6MIX Input 4 Source */
+       { 0x0000072F, 0x0080 },    /* R1839  - AIF1TX6MIX Input 4 Volume */
+       { 0x00000730, 0x0000 },    /* R1840  - AIF1TX7MIX Input 1 Source */
+       { 0x00000731, 0x0080 },    /* R1841  - AIF1TX7MIX Input 1 Volume */
+       { 0x00000732, 0x0000 },    /* R1842  - AIF1TX7MIX Input 2 Source */
+       { 0x00000733, 0x0080 },    /* R1843  - AIF1TX7MIX Input 2 Volume */
+       { 0x00000734, 0x0000 },    /* R1844  - AIF1TX7MIX Input 3 Source */
+       { 0x00000735, 0x0080 },    /* R1845  - AIF1TX7MIX Input 3 Volume */
+       { 0x00000736, 0x0000 },    /* R1846  - AIF1TX7MIX Input 4 Source */
+       { 0x00000737, 0x0080 },    /* R1847  - AIF1TX7MIX Input 4 Volume */
+       { 0x00000738, 0x0000 },    /* R1848  - AIF1TX8MIX Input 1 Source */
+       { 0x00000739, 0x0080 },    /* R1849  - AIF1TX8MIX Input 1 Volume */
+       { 0x0000073A, 0x0000 },    /* R1850  - AIF1TX8MIX Input 2 Source */
+       { 0x0000073B, 0x0080 },    /* R1851  - AIF1TX8MIX Input 2 Volume */
+       { 0x0000073C, 0x0000 },    /* R1852  - AIF1TX8MIX Input 3 Source */
+       { 0x0000073D, 0x0080 },    /* R1853  - AIF1TX8MIX Input 3 Volume */
+       { 0x0000073E, 0x0000 },    /* R1854  - AIF1TX8MIX Input 4 Source */
+       { 0x0000073F, 0x0080 },    /* R1855  - AIF1TX8MIX Input 4 Volume */
+       { 0x00000740, 0x0000 },    /* R1856  - AIF2TX1MIX Input 1 Source */
+       { 0x00000741, 0x0080 },    /* R1857  - AIF2TX1MIX Input 1 Volume */
+       { 0x00000742, 0x0000 },    /* R1858  - AIF2TX1MIX Input 2 Source */
+       { 0x00000743, 0x0080 },    /* R1859  - AIF2TX1MIX Input 2 Volume */
+       { 0x00000744, 0x0000 },    /* R1860  - AIF2TX1MIX Input 3 Source */
+       { 0x00000745, 0x0080 },    /* R1861  - AIF2TX1MIX Input 3 Volume */
+       { 0x00000746, 0x0000 },    /* R1862  - AIF2TX1MIX Input 4 Source */
+       { 0x00000747, 0x0080 },    /* R1863  - AIF2TX1MIX Input 4 Volume */
+       { 0x00000748, 0x0000 },    /* R1864  - AIF2TX2MIX Input 1 Source */
+       { 0x00000749, 0x0080 },    /* R1865  - AIF2TX2MIX Input 1 Volume */
+       { 0x0000074A, 0x0000 },    /* R1866  - AIF2TX2MIX Input 2 Source */
+       { 0x0000074B, 0x0080 },    /* R1867  - AIF2TX2MIX Input 2 Volume */
+       { 0x0000074C, 0x0000 },    /* R1868  - AIF2TX2MIX Input 3 Source */
+       { 0x0000074D, 0x0080 },    /* R1869  - AIF2TX2MIX Input 3 Volume */
+       { 0x0000074E, 0x0000 },    /* R1870  - AIF2TX2MIX Input 4 Source */
+       { 0x0000074F, 0x0080 },    /* R1871  - AIF2TX2MIX Input 4 Volume */
+       { 0x00000780, 0x0000 },    /* R1920  - AIF3TX1MIX Input 1 Source */
+       { 0x00000781, 0x0080 },    /* R1921  - AIF3TX1MIX Input 1 Volume */
+       { 0x00000782, 0x0000 },    /* R1922  - AIF3TX1MIX Input 2 Source */
+       { 0x00000783, 0x0080 },    /* R1923  - AIF3TX1MIX Input 2 Volume */
+       { 0x00000784, 0x0000 },    /* R1924  - AIF3TX1MIX Input 3 Source */
+       { 0x00000785, 0x0080 },    /* R1925  - AIF3TX1MIX Input 3 Volume */
+       { 0x00000786, 0x0000 },    /* R1926  - AIF3TX1MIX Input 4 Source */
+       { 0x00000787, 0x0080 },    /* R1927  - AIF3TX1MIX Input 4 Volume */
+       { 0x00000788, 0x0000 },    /* R1928  - AIF3TX2MIX Input 1 Source */
+       { 0x00000789, 0x0080 },    /* R1929  - AIF3TX2MIX Input 1 Volume */
+       { 0x0000078A, 0x0000 },    /* R1930  - AIF3TX2MIX Input 2 Source */
+       { 0x0000078B, 0x0080 },    /* R1931  - AIF3TX2MIX Input 2 Volume */
+       { 0x0000078C, 0x0000 },    /* R1932  - AIF3TX2MIX Input 3 Source */
+       { 0x0000078D, 0x0080 },    /* R1933  - AIF3TX2MIX Input 3 Volume */
+       { 0x0000078E, 0x0000 },    /* R1934  - AIF3TX2MIX Input 4 Source */
+       { 0x0000078F, 0x0080 },    /* R1935  - AIF3TX2MIX Input 4 Volume */
+       { 0x000007C0, 0x0000 },    /* R1984  - SLIMTX1MIX Input 1 Source */
+       { 0x000007C1, 0x0080 },    /* R1985  - SLIMTX1MIX Input 1 Volume */
+       { 0x000007C2, 0x0000 },    /* R1986  - SLIMTX1MIX Input 2 Source */
+       { 0x000007C3, 0x0080 },    /* R1987  - SLIMTX1MIX Input 2 Volume */
+       { 0x000007C4, 0x0000 },    /* R1988  - SLIMTX1MIX Input 3 Source */
+       { 0x000007C5, 0x0080 },    /* R1989  - SLIMTX1MIX Input 3 Volume */
+       { 0x000007C6, 0x0000 },    /* R1990  - SLIMTX1MIX Input 4 Source */
+       { 0x000007C7, 0x0080 },    /* R1991  - SLIMTX1MIX Input 4 Volume */
+       { 0x000007C8, 0x0000 },    /* R1992  - SLIMTX2MIX Input 1 Source */
+       { 0x000007C9, 0x0080 },    /* R1993  - SLIMTX2MIX Input 1 Volume */
+       { 0x000007CA, 0x0000 },    /* R1994  - SLIMTX2MIX Input 2 Source */
+       { 0x000007CB, 0x0080 },    /* R1995  - SLIMTX2MIX Input 2 Volume */
+       { 0x000007CC, 0x0000 },    /* R1996  - SLIMTX2MIX Input 3 Source */
+       { 0x000007CD, 0x0080 },    /* R1997  - SLIMTX2MIX Input 3 Volume */
+       { 0x000007CE, 0x0000 },    /* R1998  - SLIMTX2MIX Input 4 Source */
+       { 0x000007CF, 0x0080 },    /* R1999  - SLIMTX2MIX Input 4 Volume */
+       { 0x000007D0, 0x0000 },    /* R2000  - SLIMTX3MIX Input 1 Source */
+       { 0x000007D1, 0x0080 },    /* R2001  - SLIMTX3MIX Input 1 Volume */
+       { 0x000007D2, 0x0000 },    /* R2002  - SLIMTX3MIX Input 2 Source */
+       { 0x000007D3, 0x0080 },    /* R2003  - SLIMTX3MIX Input 2 Volume */
+       { 0x000007D4, 0x0000 },    /* R2004  - SLIMTX3MIX Input 3 Source */
+       { 0x000007D5, 0x0080 },    /* R2005  - SLIMTX3MIX Input 3 Volume */
+       { 0x000007D6, 0x0000 },    /* R2006  - SLIMTX3MIX Input 4 Source */
+       { 0x000007D7, 0x0080 },    /* R2007  - SLIMTX3MIX Input 4 Volume */
+       { 0x000007D8, 0x0000 },    /* R2008  - SLIMTX4MIX Input 1 Source */
+       { 0x000007D9, 0x0080 },    /* R2009  - SLIMTX4MIX Input 1 Volume */
+       { 0x000007DA, 0x0000 },    /* R2010  - SLIMTX4MIX Input 2 Source */
+       { 0x000007DB, 0x0080 },    /* R2011  - SLIMTX4MIX Input 2 Volume */
+       { 0x000007DC, 0x0000 },    /* R2012  - SLIMTX4MIX Input 3 Source */
+       { 0x000007DD, 0x0080 },    /* R2013  - SLIMTX4MIX Input 3 Volume */
+       { 0x000007DE, 0x0000 },    /* R2014  - SLIMTX4MIX Input 4 Source */
+       { 0x000007DF, 0x0080 },    /* R2015  - SLIMTX4MIX Input 4 Volume */
+       { 0x000007E0, 0x0000 },    /* R2016  - SLIMTX5MIX Input 1 Source */
+       { 0x000007E1, 0x0080 },    /* R2017  - SLIMTX5MIX Input 1 Volume */
+       { 0x000007E2, 0x0000 },    /* R2018  - SLIMTX5MIX Input 2 Source */
+       { 0x000007E3, 0x0080 },    /* R2019  - SLIMTX5MIX Input 2 Volume */
+       { 0x000007E4, 0x0000 },    /* R2020  - SLIMTX5MIX Input 3 Source */
+       { 0x000007E5, 0x0080 },    /* R2021  - SLIMTX5MIX Input 3 Volume */
+       { 0x000007E6, 0x0000 },    /* R2022  - SLIMTX5MIX Input 4 Source */
+       { 0x000007E7, 0x0080 },    /* R2023  - SLIMTX5MIX Input 4 Volume */
+       { 0x000007E8, 0x0000 },    /* R2024  - SLIMTX6MIX Input 1 Source */
+       { 0x000007E9, 0x0080 },    /* R2025  - SLIMTX6MIX Input 1 Volume */
+       { 0x000007EA, 0x0000 },    /* R2026  - SLIMTX6MIX Input 2 Source */
+       { 0x000007EB, 0x0080 },    /* R2027  - SLIMTX6MIX Input 2 Volume */
+       { 0x000007EC, 0x0000 },    /* R2028  - SLIMTX6MIX Input 3 Source */
+       { 0x000007ED, 0x0080 },    /* R2029  - SLIMTX6MIX Input 3 Volume */
+       { 0x000007EE, 0x0000 },    /* R2030  - SLIMTX6MIX Input 4 Source */
+       { 0x000007EF, 0x0080 },    /* R2031  - SLIMTX6MIX Input 4 Volume */
+       { 0x000007F0, 0x0000 },    /* R2032  - SLIMTX7MIX Input 1 Source */
+       { 0x000007F1, 0x0080 },    /* R2033  - SLIMTX7MIX Input 1 Volume */
+       { 0x000007F2, 0x0000 },    /* R2034  - SLIMTX7MIX Input 2 Source */
+       { 0x000007F3, 0x0080 },    /* R2035  - SLIMTX7MIX Input 2 Volume */
+       { 0x000007F4, 0x0000 },    /* R2036  - SLIMTX7MIX Input 3 Source */
+       { 0x000007F5, 0x0080 },    /* R2037  - SLIMTX7MIX Input 3 Volume */
+       { 0x000007F6, 0x0000 },    /* R2038  - SLIMTX7MIX Input 4 Source */
+       { 0x000007F7, 0x0080 },    /* R2039  - SLIMTX7MIX Input 4 Volume */
+       { 0x000007F8, 0x0000 },    /* R2040  - SLIMTX8MIX Input 1 Source */
+       { 0x000007F9, 0x0080 },    /* R2041  - SLIMTX8MIX Input 1 Volume */
+       { 0x000007FA, 0x0000 },    /* R2042  - SLIMTX8MIX Input 2 Source */
+       { 0x000007FB, 0x0080 },    /* R2043  - SLIMTX8MIX Input 2 Volume */
+       { 0x000007FC, 0x0000 },    /* R2044  - SLIMTX8MIX Input 3 Source */
+       { 0x000007FD, 0x0080 },    /* R2045  - SLIMTX8MIX Input 3 Volume */
+       { 0x000007FE, 0x0000 },    /* R2046  - SLIMTX8MIX Input 4 Source */
+       { 0x000007FF, 0x0080 },    /* R2047  - SLIMTX8MIX Input 4 Volume */
+       { 0x00000880, 0x0000 },    /* R2176  - EQ1MIX Input 1 Source */
+       { 0x00000881, 0x0080 },    /* R2177  - EQ1MIX Input 1 Volume */
+       { 0x00000882, 0x0000 },    /* R2178  - EQ1MIX Input 2 Source */
+       { 0x00000883, 0x0080 },    /* R2179  - EQ1MIX Input 2 Volume */
+       { 0x00000884, 0x0000 },    /* R2180  - EQ1MIX Input 3 Source */
+       { 0x00000885, 0x0080 },    /* R2181  - EQ1MIX Input 3 Volume */
+       { 0x00000886, 0x0000 },    /* R2182  - EQ1MIX Input 4 Source */
+       { 0x00000887, 0x0080 },    /* R2183  - EQ1MIX Input 4 Volume */
+       { 0x00000888, 0x0000 },    /* R2184  - EQ2MIX Input 1 Source */
+       { 0x00000889, 0x0080 },    /* R2185  - EQ2MIX Input 1 Volume */
+       { 0x0000088A, 0x0000 },    /* R2186  - EQ2MIX Input 2 Source */
+       { 0x0000088B, 0x0080 },    /* R2187  - EQ2MIX Input 2 Volume */
+       { 0x0000088C, 0x0000 },    /* R2188  - EQ2MIX Input 3 Source */
+       { 0x0000088D, 0x0080 },    /* R2189  - EQ2MIX Input 3 Volume */
+       { 0x0000088E, 0x0000 },    /* R2190  - EQ2MIX Input 4 Source */
+       { 0x0000088F, 0x0080 },    /* R2191  - EQ2MIX Input 4 Volume */
+       { 0x00000890, 0x0000 },    /* R2192  - EQ3MIX Input 1 Source */
+       { 0x00000891, 0x0080 },    /* R2193  - EQ3MIX Input 1 Volume */
+       { 0x00000892, 0x0000 },    /* R2194  - EQ3MIX Input 2 Source */
+       { 0x00000893, 0x0080 },    /* R2195  - EQ3MIX Input 2 Volume */
+       { 0x00000894, 0x0000 },    /* R2196  - EQ3MIX Input 3 Source */
+       { 0x00000895, 0x0080 },    /* R2197  - EQ3MIX Input 3 Volume */
+       { 0x00000896, 0x0000 },    /* R2198  - EQ3MIX Input 4 Source */
+       { 0x00000897, 0x0080 },    /* R2199  - EQ3MIX Input 4 Volume */
+       { 0x00000898, 0x0000 },    /* R2200  - EQ4MIX Input 1 Source */
+       { 0x00000899, 0x0080 },    /* R2201  - EQ4MIX Input 1 Volume */
+       { 0x0000089A, 0x0000 },    /* R2202  - EQ4MIX Input 2 Source */
+       { 0x0000089B, 0x0080 },    /* R2203  - EQ4MIX Input 2 Volume */
+       { 0x0000089C, 0x0000 },    /* R2204  - EQ4MIX Input 3 Source */
+       { 0x0000089D, 0x0080 },    /* R2205  - EQ4MIX Input 3 Volume */
+       { 0x0000089E, 0x0000 },    /* R2206  - EQ4MIX Input 4 Source */
+       { 0x0000089F, 0x0080 },    /* R2207  - EQ4MIX Input 4 Volume */
+       { 0x000008C0, 0x0000 },    /* R2240  - DRC1LMIX Input 1 Source */
+       { 0x000008C1, 0x0080 },    /* R2241  - DRC1LMIX Input 1 Volume */
+       { 0x000008C2, 0x0000 },    /* R2242  - DRC1LMIX Input 2 Source */
+       { 0x000008C3, 0x0080 },    /* R2243  - DRC1LMIX Input 2 Volume */
+       { 0x000008C4, 0x0000 },    /* R2244  - DRC1LMIX Input 3 Source */
+       { 0x000008C5, 0x0080 },    /* R2245  - DRC1LMIX Input 3 Volume */
+       { 0x000008C6, 0x0000 },    /* R2246  - DRC1LMIX Input 4 Source */
+       { 0x000008C7, 0x0080 },    /* R2247  - DRC1LMIX Input 4 Volume */
+       { 0x000008C8, 0x0000 },    /* R2248  - DRC1RMIX Input 1 Source */
+       { 0x000008C9, 0x0080 },    /* R2249  - DRC1RMIX Input 1 Volume */
+       { 0x000008CA, 0x0000 },    /* R2250  - DRC1RMIX Input 2 Source */
+       { 0x000008CB, 0x0080 },    /* R2251  - DRC1RMIX Input 2 Volume */
+       { 0x000008CC, 0x0000 },    /* R2252  - DRC1RMIX Input 3 Source */
+       { 0x000008CD, 0x0080 },    /* R2253  - DRC1RMIX Input 3 Volume */
+       { 0x000008CE, 0x0000 },    /* R2254  - DRC1RMIX Input 4 Source */
+       { 0x000008CF, 0x0080 },    /* R2255  - DRC1RMIX Input 4 Volume */
+       { 0x000008D0, 0x0000 },    /* R2256  - DRC2LMIX Input 1 Source */
+       { 0x000008D1, 0x0080 },    /* R2257  - DRC2LMIX Input 1 Volume */
+       { 0x000008D2, 0x0000 },    /* R2258  - DRC2LMIX Input 2 Source */
+       { 0x000008D3, 0x0080 },    /* R2259  - DRC2LMIX Input 2 Volume */
+       { 0x000008D4, 0x0000 },    /* R2260  - DRC2LMIX Input 3 Source */
+       { 0x000008D5, 0x0080 },    /* R2261  - DRC2LMIX Input 3 Volume */
+       { 0x000008D6, 0x0000 },    /* R2262  - DRC2LMIX Input 4 Source */
+       { 0x000008D7, 0x0080 },    /* R2263  - DRC2LMIX Input 4 Volume */
+       { 0x000008D8, 0x0000 },    /* R2264  - DRC2RMIX Input 1 Source */
+       { 0x000008D9, 0x0080 },    /* R2265  - DRC2RMIX Input 1 Volume */
+       { 0x000008DA, 0x0000 },    /* R2266  - DRC2RMIX Input 2 Source */
+       { 0x000008DB, 0x0080 },    /* R2267  - DRC2RMIX Input 2 Volume */
+       { 0x000008DC, 0x0000 },    /* R2268  - DRC2RMIX Input 3 Source */
+       { 0x000008DD, 0x0080 },    /* R2269  - DRC2RMIX Input 3 Volume */
+       { 0x000008DE, 0x0000 },    /* R2270  - DRC2RMIX Input 4 Source */
+       { 0x000008DF, 0x0080 },    /* R2271  - DRC2RMIX Input 4 Volume */
+       { 0x00000900, 0x0000 },    /* R2304  - HPLP1MIX Input 1 Source */
+       { 0x00000901, 0x0080 },    /* R2305  - HPLP1MIX Input 1 Volume */
+       { 0x00000902, 0x0000 },    /* R2306  - HPLP1MIX Input 2 Source */
+       { 0x00000903, 0x0080 },    /* R2307  - HPLP1MIX Input 2 Volume */
+       { 0x00000904, 0x0000 },    /* R2308  - HPLP1MIX Input 3 Source */
+       { 0x00000905, 0x0080 },    /* R2309  - HPLP1MIX Input 3 Volume */
+       { 0x00000906, 0x0000 },    /* R2310  - HPLP1MIX Input 4 Source */
+       { 0x00000907, 0x0080 },    /* R2311  - HPLP1MIX Input 4 Volume */
+       { 0x00000908, 0x0000 },    /* R2312  - HPLP2MIX Input 1 Source */
+       { 0x00000909, 0x0080 },    /* R2313  - HPLP2MIX Input 1 Volume */
+       { 0x0000090A, 0x0000 },    /* R2314  - HPLP2MIX Input 2 Source */
+       { 0x0000090B, 0x0080 },    /* R2315  - HPLP2MIX Input 2 Volume */
+       { 0x0000090C, 0x0000 },    /* R2316  - HPLP2MIX Input 3 Source */
+       { 0x0000090D, 0x0080 },    /* R2317  - HPLP2MIX Input 3 Volume */
+       { 0x0000090E, 0x0000 },    /* R2318  - HPLP2MIX Input 4 Source */
+       { 0x0000090F, 0x0080 },    /* R2319  - HPLP2MIX Input 4 Volume */
+       { 0x00000910, 0x0000 },    /* R2320  - HPLP3MIX Input 1 Source */
+       { 0x00000911, 0x0080 },    /* R2321  - HPLP3MIX Input 1 Volume */
+       { 0x00000912, 0x0000 },    /* R2322  - HPLP3MIX Input 2 Source */
+       { 0x00000913, 0x0080 },    /* R2323  - HPLP3MIX Input 2 Volume */
+       { 0x00000914, 0x0000 },    /* R2324  - HPLP3MIX Input 3 Source */
+       { 0x00000915, 0x0080 },    /* R2325  - HPLP3MIX Input 3 Volume */
+       { 0x00000916, 0x0000 },    /* R2326  - HPLP3MIX Input 4 Source */
+       { 0x00000917, 0x0080 },    /* R2327  - HPLP3MIX Input 4 Volume */
+       { 0x00000918, 0x0000 },    /* R2328  - HPLP4MIX Input 1 Source */
+       { 0x00000919, 0x0080 },    /* R2329  - HPLP4MIX Input 1 Volume */
+       { 0x0000091A, 0x0000 },    /* R2330  - HPLP4MIX Input 2 Source */
+       { 0x0000091B, 0x0080 },    /* R2331  - HPLP4MIX Input 2 Volume */
+       { 0x0000091C, 0x0000 },    /* R2332  - HPLP4MIX Input 3 Source */
+       { 0x0000091D, 0x0080 },    /* R2333  - HPLP4MIX Input 3 Volume */
+       { 0x0000091E, 0x0000 },    /* R2334  - HPLP4MIX Input 4 Source */
+       { 0x0000091F, 0x0080 },    /* R2335  - HPLP4MIX Input 4 Volume */
+       { 0x00000940, 0x0000 },    /* R2368  - DSP1LMIX Input 1 Source */
+       { 0x00000941, 0x0080 },    /* R2369  - DSP1LMIX Input 1 Volume */
+       { 0x00000942, 0x0000 },    /* R2370  - DSP1LMIX Input 2 Source */
+       { 0x00000943, 0x0080 },    /* R2371  - DSP1LMIX Input 2 Volume */
+       { 0x00000944, 0x0000 },    /* R2372  - DSP1LMIX Input 3 Source */
+       { 0x00000945, 0x0080 },    /* R2373  - DSP1LMIX Input 3 Volume */
+       { 0x00000946, 0x0000 },    /* R2374  - DSP1LMIX Input 4 Source */
+       { 0x00000947, 0x0080 },    /* R2375  - DSP1LMIX Input 4 Volume */
+       { 0x00000948, 0x0000 },    /* R2376  - DSP1RMIX Input 1 Source */
+       { 0x00000949, 0x0080 },    /* R2377  - DSP1RMIX Input 1 Volume */
+       { 0x0000094A, 0x0000 },    /* R2378  - DSP1RMIX Input 2 Source */
+       { 0x0000094B, 0x0080 },    /* R2379  - DSP1RMIX Input 2 Volume */
+       { 0x0000094C, 0x0000 },    /* R2380  - DSP1RMIX Input 3 Source */
+       { 0x0000094D, 0x0080 },    /* R2381  - DSP1RMIX Input 3 Volume */
+       { 0x0000094E, 0x0000 },    /* R2382  - DSP1RMIX Input 4 Source */
+       { 0x0000094F, 0x0080 },    /* R2383  - DSP1RMIX Input 4 Volume */
+       { 0x00000950, 0x0000 },    /* R2384  - DSP1AUX1MIX Input 1 Source */
+       { 0x00000958, 0x0000 },    /* R2392  - DSP1AUX2MIX Input 1 Source */
+       { 0x00000960, 0x0000 },    /* R2400  - DSP1AUX3MIX Input 1 Source */
+       { 0x00000968, 0x0000 },    /* R2408  - DSP1AUX4MIX Input 1 Source */
+       { 0x00000970, 0x0000 },    /* R2416  - DSP1AUX5MIX Input 1 Source */
+       { 0x00000978, 0x0000 },    /* R2424  - DSP1AUX6MIX Input 1 Source */
+       { 0x00000980, 0x0000 },    /* R2432  - DSP2LMIX Input 1 Source */
+       { 0x00000981, 0x0080 },    /* R2433  - DSP2LMIX Input 1 Volume */
+       { 0x00000982, 0x0000 },    /* R2434  - DSP2LMIX Input 2 Source */
+       { 0x00000983, 0x0080 },    /* R2435  - DSP2LMIX Input 2 Volume */
+       { 0x00000984, 0x0000 },    /* R2436  - DSP2LMIX Input 3 Source */
+       { 0x00000985, 0x0080 },    /* R2437  - DSP2LMIX Input 3 Volume */
+       { 0x00000986, 0x0000 },    /* R2438  - DSP2LMIX Input 4 Source */
+       { 0x00000987, 0x0080 },    /* R2439  - DSP2LMIX Input 4 Volume */
+       { 0x00000988, 0x0000 },    /* R2440  - DSP2RMIX Input 1 Source */
+       { 0x00000989, 0x0080 },    /* R2441  - DSP2RMIX Input 1 Volume */
+       { 0x0000098A, 0x0000 },    /* R2442  - DSP2RMIX Input 2 Source */
+       { 0x0000098B, 0x0080 },    /* R2443  - DSP2RMIX Input 2 Volume */
+       { 0x0000098C, 0x0000 },    /* R2444  - DSP2RMIX Input 3 Source */
+       { 0x0000098D, 0x0080 },    /* R2445  - DSP2RMIX Input 3 Volume */
+       { 0x0000098E, 0x0000 },    /* R2446  - DSP2RMIX Input 4 Source */
+       { 0x0000098F, 0x0080 },    /* R2447  - DSP2RMIX Input 4 Volume */
+       { 0x00000990, 0x0000 },    /* R2448  - DSP2AUX1MIX Input 1 Source */
+       { 0x00000998, 0x0000 },    /* R2456  - DSP2AUX2MIX Input 1 Source */
+       { 0x000009A0, 0x0000 },    /* R2464  - DSP2AUX3MIX Input 1 Source */
+       { 0x000009A8, 0x0000 },    /* R2472  - DSP2AUX4MIX Input 1 Source */
+       { 0x000009B0, 0x0000 },    /* R2480  - DSP2AUX5MIX Input 1 Source */
+       { 0x000009B8, 0x0000 },    /* R2488  - DSP2AUX6MIX Input 1 Source */
+       { 0x000009C0, 0x0000 },    /* R2496  - DSP3LMIX Input 1 Source */
+       { 0x000009C1, 0x0080 },    /* R2497  - DSP3LMIX Input 1 Volume */
+       { 0x000009C2, 0x0000 },    /* R2498  - DSP3LMIX Input 2 Source */
+       { 0x000009C3, 0x0080 },    /* R2499  - DSP3LMIX Input 2 Volume */
+       { 0x000009C4, 0x0000 },    /* R2500  - DSP3LMIX Input 3 Source */
+       { 0x000009C5, 0x0080 },    /* R2501  - DSP3LMIX Input 3 Volume */
+       { 0x000009C6, 0x0000 },    /* R2502  - DSP3LMIX Input 4 Source */
+       { 0x000009C7, 0x0080 },    /* R2503  - DSP3LMIX Input 4 Volume */
+       { 0x000009C8, 0x0000 },    /* R2504  - DSP3RMIX Input 1 Source */
+       { 0x000009C9, 0x0080 },    /* R2505  - DSP3RMIX Input 1 Volume */
+       { 0x000009CA, 0x0000 },    /* R2506  - DSP3RMIX Input 2 Source */
+       { 0x000009CB, 0x0080 },    /* R2507  - DSP3RMIX Input 2 Volume */
+       { 0x000009CC, 0x0000 },    /* R2508  - DSP3RMIX Input 3 Source */
+       { 0x000009CD, 0x0080 },    /* R2509  - DSP3RMIX Input 3 Volume */
+       { 0x000009CE, 0x0000 },    /* R2510  - DSP3RMIX Input 4 Source */
+       { 0x000009CF, 0x0080 },    /* R2511  - DSP3RMIX Input 4 Volume */
+       { 0x000009D0, 0x0000 },    /* R2512  - DSP3AUX1MIX Input 1 Source */
+       { 0x000009D8, 0x0000 },    /* R2520  - DSP3AUX2MIX Input 1 Source */
+       { 0x000009E0, 0x0000 },    /* R2528  - DSP3AUX3MIX Input 1 Source */
+       { 0x000009E8, 0x0000 },    /* R2536  - DSP3AUX4MIX Input 1 Source */
+       { 0x000009F0, 0x0000 },    /* R2544  - DSP3AUX5MIX Input 1 Source */
+       { 0x000009F8, 0x0000 },    /* R2552  - DSP3AUX6MIX Input 1 Source */
+       { 0x00000A00, 0x0000 },    /* R2560  - DSP4LMIX Input 1 Source */
+       { 0x00000A01, 0x0080 },    /* R2561  - DSP4LMIX Input 1 Volume */
+       { 0x00000A02, 0x0000 },    /* R2562  - DSP4LMIX Input 2 Source */
+       { 0x00000A03, 0x0080 },    /* R2563  - DSP4LMIX Input 2 Volume */
+       { 0x00000A04, 0x0000 },    /* R2564  - DSP4LMIX Input 3 Source */
+       { 0x00000A05, 0x0080 },    /* R2565  - DSP4LMIX Input 3 Volume */
+       { 0x00000A06, 0x0000 },    /* R2566  - DSP4LMIX Input 4 Source */
+       { 0x00000A07, 0x0080 },    /* R2567  - DSP4LMIX Input 4 Volume */
+       { 0x00000A08, 0x0000 },    /* R2568  - DSP4RMIX Input 1 Source */
+       { 0x00000A09, 0x0080 },    /* R2569  - DSP4RMIX Input 1 Volume */
+       { 0x00000A0A, 0x0000 },    /* R2570  - DSP4RMIX Input 2 Source */
+       { 0x00000A0B, 0x0080 },    /* R2571  - DSP4RMIX Input 2 Volume */
+       { 0x00000A0C, 0x0000 },    /* R2572  - DSP4RMIX Input 3 Source */
+       { 0x00000A0D, 0x0080 },    /* R2573  - DSP4RMIX Input 3 Volume */
+       { 0x00000A0E, 0x0000 },    /* R2574  - DSP4RMIX Input 4 Source */
+       { 0x00000A0F, 0x0080 },    /* R2575  - DSP4RMIX Input 4 Volume */
+       { 0x00000A10, 0x0000 },    /* R2576  - DSP4AUX1MIX Input 1 Source */
+       { 0x00000A18, 0x0000 },    /* R2584  - DSP4AUX2MIX Input 1 Source */
+       { 0x00000A20, 0x0000 },    /* R2592  - DSP4AUX3MIX Input 1 Source */
+       { 0x00000A28, 0x0000 },    /* R2600  - DSP4AUX4MIX Input 1 Source */
+       { 0x00000A30, 0x0000 },    /* R2608  - DSP4AUX5MIX Input 1 Source */
+       { 0x00000A38, 0x0000 },    /* R2616  - DSP4AUX6MIX Input 1 Source */
+       { 0x00000A80, 0x0000 },    /* R2688  - ASRC1LMIX Input 1 Source */
+       { 0x00000A88, 0x0000 },    /* R2696  - ASRC1RMIX Input 1 Source */
+       { 0x00000A90, 0x0000 },    /* R2704  - ASRC2LMIX Input 1 Source */
+       { 0x00000A98, 0x0000 },    /* R2712  - ASRC2RMIX Input 1 Source */
+       { 0x00000B00, 0x0000 },    /* R2816  - ISRC1DEC1MIX Input 1 Source */
+       { 0x00000B08, 0x0000 },    /* R2824  - ISRC1DEC2MIX Input 1 Source */
+       { 0x00000B10, 0x0000 },    /* R2832  - ISRC1DEC3MIX Input 1 Source */
+       { 0x00000B18, 0x0000 },    /* R2840  - ISRC1DEC4MIX Input 1 Source */
+       { 0x00000B20, 0x0000 },    /* R2848  - ISRC1INT1MIX Input 1 Source */
+       { 0x00000B28, 0x0000 },    /* R2856  - ISRC1INT2MIX Input 1 Source */
+       { 0x00000B30, 0x0000 },    /* R2864  - ISRC1INT3MIX Input 1 Source */
+       { 0x00000B38, 0x0000 },    /* R2872  - ISRC1INT4MIX Input 1 Source */
+       { 0x00000B40, 0x0000 },    /* R2880  - ISRC2DEC1MIX Input 1 Source */
+       { 0x00000B48, 0x0000 },    /* R2888  - ISRC2DEC2MIX Input 1 Source */
+       { 0x00000B50, 0x0000 },    /* R2896  - ISRC2DEC3MIX Input 1 Source */
+       { 0x00000B58, 0x0000 },    /* R2904  - ISRC2DEC4MIX Input 1 Source */
+       { 0x00000B60, 0x0000 },    /* R2912  - ISRC2INT1MIX Input 1 Source */
+       { 0x00000B68, 0x0000 },    /* R2920  - ISRC2INT2MIX Input 1 Source */
+       { 0x00000B70, 0x0000 },    /* R2928  - ISRC2INT3MIX Input 1 Source */
+       { 0x00000B78, 0x0000 },    /* R2936  - ISRC2INT4MIX Input 1 Source */
+       { 0x00000B80, 0x0000 },    /* R2944  - ISRC3DEC1MIX Input 1 Source */
+       { 0x00000B88, 0x0000 },    /* R2952  - ISRC3DEC2MIX Input 1 Source */
+       { 0x00000B90, 0x0000 },    /* R2960  - ISRC3DEC3MIX Input 1 Source */
+       { 0x00000B98, 0x0000 },    /* R2968  - ISRC3DEC4MIX Input 1 Source */
+       { 0x00000BA0, 0x0000 },    /* R2976  - ISRC3INT1MIX Input 1 Source */
+       { 0x00000BA8, 0x0000 },    /* R2984  - ISRC3INT2MIX Input 1 Source */
+       { 0x00000BB0, 0x0000 },    /* R2992  - ISRC3INT3MIX Input 1 Source */
+       { 0x00000BB8, 0x0000 },    /* R3000  - ISRC3INT4MIX Input 1 Source */
+       { 0x00000C00, 0xA101 },    /* R3072  - GPIO1 CTRL */
+       { 0x00000C01, 0xA101 },    /* R3073  - GPIO2 CTRL */
+       { 0x00000C02, 0xA101 },    /* R3074  - GPIO3 CTRL */
+       { 0x00000C03, 0xA101 },    /* R3075  - GPIO4 CTRL */
+       { 0x00000C04, 0xA101 },    /* R3076  - GPIO5 CTRL */
+       { 0x00000C0F, 0x0400 },    /* R3087  - IRQ CTRL 1 */
+       { 0x00000C10, 0x1000 },    /* R3088  - GPIO Debounce Config */
+       { 0x00000C20, 0x8002 },    /* R3104  - Misc Pad Ctrl 1 */
+       { 0x00000C21, 0x8001 },    /* R3105  - Misc Pad Ctrl 2 */
+       { 0x00000C22, 0x0000 },    /* R3106  - Misc Pad Ctrl 3 */
+       { 0x00000C23, 0x0000 },    /* R3107  - Misc Pad Ctrl 4 */
+       { 0x00000C24, 0x0000 },    /* R3108  - Misc Pad Ctrl 5 */
+       { 0x00000C25, 0x0000 },    /* R3109  - Misc Pad Ctrl 6 */
+       { 0x00000C30, 0x8282 },    /* R3120  - Misc Pad Ctrl 7 */
+       { 0x00000C31, 0x0082 },    /* R3121  - Misc Pad Ctrl 8 */
+       { 0x00000C32, 0x8282 },    /* R3122  - Misc Pad Ctrl 9 */
+       { 0x00000C33, 0x8282 },    /* R3123  - Misc Pad Ctrl 10 */
+       { 0x00000C34, 0x8282 },    /* R3124  - Misc Pad Ctrl 11 */
+       { 0x00000C35, 0x8282 },    /* R3125  - Misc Pad Ctrl 12 */
+       { 0x00000C36, 0x8282 },    /* R3126  - Misc Pad Ctrl 13 */
+       { 0x00000C37, 0x8282 },    /* R3127  - Misc Pad Ctrl 14 */
+       { 0x00000C38, 0x8282 },    /* R3128  - Misc Pad Ctrl 15 */
+       { 0x00000C39, 0x8282 },    /* R3129  - Misc Pad Ctrl 16 */
+       { 0x00000C3A, 0x8282 },    /* R3130  - Misc Pad Ctrl 17 */
+       { 0x00000C3B, 0x8282 },    /* R3131  - Misc Pad Ctrl 18 */
+       { 0x00000D08, 0xFFFF },    /* R3336  - Interrupt Status 1 Mask */
+       { 0x00000D09, 0xFFFF },    /* R3337  - Interrupt Status 2 Mask */
+       { 0x00000D0A, 0xFFFF },    /* R3338  - Interrupt Status 3 Mask */
+       { 0x00000D0B, 0xFFFF },    /* R3339  - Interrupt Status 4 Mask */
+       { 0x00000D0C, 0xFEFF },    /* R3340  - Interrupt Status 5 Mask */
+       { 0x00000D0F, 0x0000 },    /* R3343  - Interrupt Control */
+       { 0x00000D18, 0xFFFF },    /* R3352  - IRQ2 Status 1 Mask */
+       { 0x00000D19, 0xFFFF },    /* R3353  - IRQ2 Status 2 Mask */
+       { 0x00000D1A, 0xFFFF },    /* R3354  - IRQ2 Status 3 Mask */
+       { 0x00000D1B, 0xFFFF },    /* R3355  - IRQ2 Status 4 Mask */
+       { 0x00000D1C, 0xFFFF },    /* R3356  - IRQ2 Status 5 Mask */
+       { 0x00000D1F, 0x0000 },    /* R3359  - IRQ2 Control */
+       { 0x00000D50, 0x0000 },    /* R3408  - AOD wkup and trig */
+       { 0x00000D53, 0xFFFF },    /* R3411  - AOD IRQ Mask IRQ1 */
+       { 0x00000D54, 0xFFFF },    /* R3412  - AOD IRQ Mask IRQ2 */
+       { 0x00000D56, 0x0000 },    /* R3414  - Jack detect debounce */
+       { 0x00000E00, 0x0000 },    /* R3584  - FX_Ctrl1 */
+       { 0x00000E01, 0x0000 },    /* R3585  - FX_Ctrl2 */
+       { 0x00000E10, 0x6318 },    /* R3600  - EQ1_1 */
+       { 0x00000E11, 0x6300 },    /* R3601  - EQ1_2 */
+       { 0x00000E12, 0x0FC8 },    /* R3602  - EQ1_3 */
+       { 0x00000E13, 0x03FE },    /* R3603  - EQ1_4 */
+       { 0x00000E14, 0x00E0 },    /* R3604  - EQ1_5 */
+       { 0x00000E15, 0x1EC4 },    /* R3605  - EQ1_6 */
+       { 0x00000E16, 0xF136 },    /* R3606  - EQ1_7 */
+       { 0x00000E17, 0x0409 },    /* R3607  - EQ1_8 */
+       { 0x00000E18, 0x04CC },    /* R3608  - EQ1_9 */
+       { 0x00000E19, 0x1C9B },    /* R3609  - EQ1_10 */
+       { 0x00000E1A, 0xF337 },    /* R3610  - EQ1_11 */
+       { 0x00000E1B, 0x040B },    /* R3611  - EQ1_12 */
+       { 0x00000E1C, 0x0CBB },    /* R3612  - EQ1_13 */
+       { 0x00000E1D, 0x16F8 },    /* R3613  - EQ1_14 */
+       { 0x00000E1E, 0xF7D9 },    /* R3614  - EQ1_15 */
+       { 0x00000E1F, 0x040A },    /* R3615  - EQ1_16 */
+       { 0x00000E20, 0x1F14 },    /* R3616  - EQ1_17 */
+       { 0x00000E21, 0x058C },    /* R3617  - EQ1_18 */
+       { 0x00000E22, 0x0563 },    /* R3618  - EQ1_19 */
+       { 0x00000E23, 0x4000 },    /* R3619  - EQ1_20 */
+       { 0x00000E24, 0x0B75 },    /* R3620  - EQ1_21 */
+       { 0x00000E26, 0x6318 },    /* R3622  - EQ2_1 */
+       { 0x00000E27, 0x6300 },    /* R3623  - EQ2_2 */
+       { 0x00000E28, 0x0FC8 },    /* R3624  - EQ2_3 */
+       { 0x00000E29, 0x03FE },    /* R3625  - EQ2_4 */
+       { 0x00000E2A, 0x00E0 },    /* R3626  - EQ2_5 */
+       { 0x00000E2B, 0x1EC4 },    /* R3627  - EQ2_6 */
+       { 0x00000E2C, 0xF136 },    /* R3628  - EQ2_7 */
+       { 0x00000E2D, 0x0409 },    /* R3629  - EQ2_8 */
+       { 0x00000E2E, 0x04CC },    /* R3630  - EQ2_9 */
+       { 0x00000E2F, 0x1C9B },    /* R3631  - EQ2_10 */
+       { 0x00000E30, 0xF337 },    /* R3632  - EQ2_11 */
+       { 0x00000E31, 0x040B },    /* R3633  - EQ2_12 */
+       { 0x00000E32, 0x0CBB },    /* R3634  - EQ2_13 */
+       { 0x00000E33, 0x16F8 },    /* R3635  - EQ2_14 */
+       { 0x00000E34, 0xF7D9 },    /* R3636  - EQ2_15 */
+       { 0x00000E35, 0x040A },    /* R3637  - EQ2_16 */
+       { 0x00000E36, 0x1F14 },    /* R3638  - EQ2_17 */
+       { 0x00000E37, 0x058C },    /* R3639  - EQ2_18 */
+       { 0x00000E38, 0x0563 },    /* R3640  - EQ2_19 */
+       { 0x00000E39, 0x4000 },    /* R3641  - EQ2_20 */
+       { 0x00000E3A, 0x0B75 },    /* R3642  - EQ2_21 */
+       { 0x00000E3C, 0x6318 },    /* R3644  - EQ3_1 */
+       { 0x00000E3D, 0x6300 },    /* R3645  - EQ3_2 */
+       { 0x00000E3E, 0x0FC8 },    /* R3646  - EQ3_3 */
+       { 0x00000E3F, 0x03FE },    /* R3647  - EQ3_4 */
+       { 0x00000E40, 0x00E0 },    /* R3648  - EQ3_5 */
+       { 0x00000E41, 0x1EC4 },    /* R3649  - EQ3_6 */
+       { 0x00000E42, 0xF136 },    /* R3650  - EQ3_7 */
+       { 0x00000E43, 0x0409 },    /* R3651  - EQ3_8 */
+       { 0x00000E44, 0x04CC },    /* R3652  - EQ3_9 */
+       { 0x00000E45, 0x1C9B },    /* R3653  - EQ3_10 */
+       { 0x00000E46, 0xF337 },    /* R3654  - EQ3_11 */
+       { 0x00000E47, 0x040B },    /* R3655  - EQ3_12 */
+       { 0x00000E48, 0x0CBB },    /* R3656  - EQ3_13 */
+       { 0x00000E49, 0x16F8 },    /* R3657  - EQ3_14 */
+       { 0x00000E4A, 0xF7D9 },    /* R3658  - EQ3_15 */
+       { 0x00000E4B, 0x040A },    /* R3659  - EQ3_16 */
+       { 0x00000E4C, 0x1F14 },    /* R3660  - EQ3_17 */
+       { 0x00000E4D, 0x058C },    /* R3661  - EQ3_18 */
+       { 0x00000E4E, 0x0563 },    /* R3662  - EQ3_19 */
+       { 0x00000E4F, 0x4000 },    /* R3663  - EQ3_20 */
+       { 0x00000E50, 0x0B75 },    /* R3664  - EQ3_21 */
+       { 0x00000E52, 0x6318 },    /* R3666  - EQ4_1 */
+       { 0x00000E53, 0x6300 },    /* R3667  - EQ4_2 */
+       { 0x00000E54, 0x0FC8 },    /* R3668  - EQ4_3 */
+       { 0x00000E55, 0x03FE },    /* R3669  - EQ4_4 */
+       { 0x00000E56, 0x00E0 },    /* R3670  - EQ4_5 */
+       { 0x00000E57, 0x1EC4 },    /* R3671  - EQ4_6 */
+       { 0x00000E58, 0xF136 },    /* R3672  - EQ4_7 */
+       { 0x00000E59, 0x0409 },    /* R3673  - EQ4_8 */
+       { 0x00000E5A, 0x04CC },    /* R3674  - EQ4_9 */
+       { 0x00000E5B, 0x1C9B },    /* R3675  - EQ4_10 */
+       { 0x00000E5C, 0xF337 },    /* R3676  - EQ4_11 */
+       { 0x00000E5D, 0x040B },    /* R3677  - EQ4_12 */
+       { 0x00000E5E, 0x0CBB },    /* R3678  - EQ4_13 */
+       { 0x00000E5F, 0x16F8 },    /* R3679  - EQ4_14 */
+       { 0x00000E60, 0xF7D9 },    /* R3680  - EQ4_15 */
+       { 0x00000E61, 0x040A },    /* R3681  - EQ4_16 */
+       { 0x00000E62, 0x1F14 },    /* R3682  - EQ4_17 */
+       { 0x00000E63, 0x058C },    /* R3683  - EQ4_18 */
+       { 0x00000E64, 0x0563 },    /* R3684  - EQ4_19 */
+       { 0x00000E65, 0x4000 },    /* R3685  - EQ4_20 */
+       { 0x00000E66, 0x0B75 },    /* R3686  - EQ4_21 */
+       { 0x00000E80, 0x0018 },    /* R3712  - DRC1 ctrl1 */
+       { 0x00000E81, 0x0933 },    /* R3713  - DRC1 ctrl2 */
+       { 0x00000E82, 0x0018 },    /* R3714  - DRC1 ctrl3 */
+       { 0x00000E83, 0x0000 },    /* R3715  - DRC1 ctrl4 */
+       { 0x00000E84, 0x0000 },    /* R3716  - DRC1 ctrl5 */
+       { 0x00000E89, 0x0018 },    /* R3721  - DRC2 ctrl1 */
+       { 0x00000E8A, 0x0933 },    /* R3722  - DRC2 ctrl2 */
+       { 0x00000E8B, 0x0018 },    /* R3723  - DRC2 ctrl3 */
+       { 0x00000E8C, 0x0000 },    /* R3724  - DRC2 ctrl4 */
+       { 0x00000E8D, 0x0000 },    /* R3725  - DRC2 ctrl5 */
+       { 0x00000EC0, 0x0000 },    /* R3776  - HPLPF1_1 */
+       { 0x00000EC1, 0x0000 },    /* R3777  - HPLPF1_2 */
+       { 0x00000EC4, 0x0000 },    /* R3780  - HPLPF2_1 */
+       { 0x00000EC5, 0x0000 },    /* R3781  - HPLPF2_2 */
+       { 0x00000EC8, 0x0000 },    /* R3784  - HPLPF3_1 */
+       { 0x00000EC9, 0x0000 },    /* R3785  - HPLPF3_2 */
+       { 0x00000ECC, 0x0000 },    /* R3788  - HPLPF4_1 */
+       { 0x00000ECD, 0x0000 },    /* R3789  - HPLPF4_2 */
+       { 0x00000EE0, 0x0000 },    /* R3808  - ASRC_ENABLE */
+       { 0x00000EE2, 0x0000 },    /* R3810  - ASRC_RATE1 */
+       { 0x00000EF0, 0x0000 },    /* R3824  - ISRC 1 CTRL 1 */
+       { 0x00000EF1, 0x0000 },    /* R3825  - ISRC 1 CTRL 2 */
+       { 0x00000EF2, 0x0000 },    /* R3826  - ISRC 1 CTRL 3 */
+       { 0x00000EF3, 0x0000 },    /* R3827  - ISRC 2 CTRL 1 */
+       { 0x00000EF4, 0x0000 },    /* R3828  - ISRC 2 CTRL 2 */
+       { 0x00000EF5, 0x0000 },    /* R3829  - ISRC 2 CTRL 3 */
+       { 0x00000EF6, 0x0000 },    /* R3830  - ISRC 3 CTRL 1 */
+       { 0x00000EF7, 0x0000 },    /* R3831  - ISRC 3 CTRL 2 */
+       { 0x00000EF8, 0x0000 },    /* R3832  - ISRC 3 CTRL 3 */
+       { 0x00000F00, 0x0000 },    /* R3840  - Clock Control */
+       { 0x00000F01, 0x0000 },    /* R3841  - ANC_SRC */
+       { 0x00001100, 0x0010 },    /* R4352  - DSP1 Control 1 */
+       { 0x00001101, 0x0000 },    /* R4353  - DSP1 Clocking 1 */
+       { 0x00001200, 0x0010 },    /* R4608  - DSP2 Control 1 */
+       { 0x00001201, 0x0000 },    /* R4609  - DSP2 Clocking 1 */
+       { 0x00001300, 0x0010 },    /* R4864  - DSP3 Control 1 */
+       { 0x00001301, 0x0000 },    /* R4865  - DSP3 Clocking 1 */
+       { 0x00001400, 0x0010 },    /* R5120  - DSP4 Control 1 */
+       { 0x00001401, 0x0000 },    /* R5121  - DSP4 Clocking 1 */
+       { 0x00001404, 0x0000 },    /* R5124  - DSP4 Status 1 */
+};
+
+static bool wm5110_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case ARIZONA_SOFTWARE_RESET:
+       case ARIZONA_DEVICE_REVISION:
+       case ARIZONA_CTRL_IF_SPI_CFG_1:
+       case ARIZONA_CTRL_IF_I2C1_CFG_1:
+       case ARIZONA_CTRL_IF_I2C2_CFG_1:
+       case ARIZONA_CTRL_IF_I2C1_CFG_2:
+       case ARIZONA_CTRL_IF_I2C2_CFG_2:
+       case ARIZONA_WRITE_SEQUENCER_CTRL_0:
+       case ARIZONA_WRITE_SEQUENCER_CTRL_1:
+       case ARIZONA_WRITE_SEQUENCER_CTRL_2:
+       case ARIZONA_TONE_GENERATOR_1:
+       case ARIZONA_TONE_GENERATOR_2:
+       case ARIZONA_TONE_GENERATOR_3:
+       case ARIZONA_TONE_GENERATOR_4:
+       case ARIZONA_TONE_GENERATOR_5:
+       case ARIZONA_PWM_DRIVE_1:
+       case ARIZONA_PWM_DRIVE_2:
+       case ARIZONA_PWM_DRIVE_3:
+       case ARIZONA_WAKE_CONTROL:
+       case ARIZONA_SEQUENCE_CONTROL:
+       case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1:
+       case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2:
+       case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3:
+       case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3:
+       case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4:
+       case ARIZONA_COMFORT_NOISE_GENERATOR:
+       case ARIZONA_HAPTICS_CONTROL_1:
+       case ARIZONA_HAPTICS_CONTROL_2:
+       case ARIZONA_HAPTICS_PHASE_1_INTENSITY:
+       case ARIZONA_HAPTICS_PHASE_1_DURATION:
+       case ARIZONA_HAPTICS_PHASE_2_INTENSITY:
+       case ARIZONA_HAPTICS_PHASE_2_DURATION:
+       case ARIZONA_HAPTICS_PHASE_3_INTENSITY:
+       case ARIZONA_HAPTICS_PHASE_3_DURATION:
+       case ARIZONA_HAPTICS_STATUS:
+       case ARIZONA_CLOCK_32K_1:
+       case ARIZONA_SYSTEM_CLOCK_1:
+       case ARIZONA_SAMPLE_RATE_1:
+       case ARIZONA_SAMPLE_RATE_2:
+       case ARIZONA_SAMPLE_RATE_3:
+       case ARIZONA_SAMPLE_RATE_1_STATUS:
+       case ARIZONA_SAMPLE_RATE_2_STATUS:
+       case ARIZONA_SAMPLE_RATE_3_STATUS:
+       case ARIZONA_ASYNC_CLOCK_1:
+       case ARIZONA_ASYNC_SAMPLE_RATE_1:
+       case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
+       case ARIZONA_OUTPUT_SYSTEM_CLOCK:
+       case ARIZONA_OUTPUT_ASYNC_CLOCK:
+       case ARIZONA_RATE_ESTIMATOR_1:
+       case ARIZONA_RATE_ESTIMATOR_2:
+       case ARIZONA_RATE_ESTIMATOR_3:
+       case ARIZONA_RATE_ESTIMATOR_4:
+       case ARIZONA_RATE_ESTIMATOR_5:
+       case ARIZONA_FLL1_CONTROL_1:
+       case ARIZONA_FLL1_CONTROL_2:
+       case ARIZONA_FLL1_CONTROL_3:
+       case ARIZONA_FLL1_CONTROL_4:
+       case ARIZONA_FLL1_CONTROL_5:
+       case ARIZONA_FLL1_CONTROL_6:
+       case ARIZONA_FLL1_LOOP_FILTER_TEST_1:
+       case ARIZONA_FLL1_NCO_TEST_0:
+       case ARIZONA_FLL1_SYNCHRONISER_1:
+       case ARIZONA_FLL1_SYNCHRONISER_2:
+       case ARIZONA_FLL1_SYNCHRONISER_3:
+       case ARIZONA_FLL1_SYNCHRONISER_4:
+       case ARIZONA_FLL1_SYNCHRONISER_5:
+       case ARIZONA_FLL1_SYNCHRONISER_6:
+       case ARIZONA_FLL1_SPREAD_SPECTRUM:
+       case ARIZONA_FLL1_GPIO_CLOCK:
+       case ARIZONA_FLL2_CONTROL_1:
+       case ARIZONA_FLL2_CONTROL_2:
+       case ARIZONA_FLL2_CONTROL_3:
+       case ARIZONA_FLL2_CONTROL_4:
+       case ARIZONA_FLL2_CONTROL_5:
+       case ARIZONA_FLL2_CONTROL_6:
+       case ARIZONA_FLL2_LOOP_FILTER_TEST_1:
+       case ARIZONA_FLL2_NCO_TEST_0:
+       case ARIZONA_FLL2_SYNCHRONISER_1:
+       case ARIZONA_FLL2_SYNCHRONISER_2:
+       case ARIZONA_FLL2_SYNCHRONISER_3:
+       case ARIZONA_FLL2_SYNCHRONISER_4:
+       case ARIZONA_FLL2_SYNCHRONISER_5:
+       case ARIZONA_FLL2_SYNCHRONISER_6:
+       case ARIZONA_FLL2_SPREAD_SPECTRUM:
+       case ARIZONA_FLL2_GPIO_CLOCK:
+       case ARIZONA_MIC_CHARGE_PUMP_1:
+       case ARIZONA_LDO1_CONTROL_1:
+       case ARIZONA_LDO2_CONTROL_1:
+       case ARIZONA_MIC_BIAS_CTRL_1:
+       case ARIZONA_MIC_BIAS_CTRL_2:
+       case ARIZONA_MIC_BIAS_CTRL_3:
+       case ARIZONA_ACCESSORY_DETECT_MODE_1:
+       case ARIZONA_HEADPHONE_DETECT_1:
+       case ARIZONA_HEADPHONE_DETECT_2:
+       case ARIZONA_MIC_DETECT_1:
+       case ARIZONA_MIC_DETECT_2:
+       case ARIZONA_MIC_DETECT_3:
+       case ARIZONA_MIC_NOISE_MIX_CONTROL_1:
+       case ARIZONA_JACK_DETECT_ANALOGUE:
+       case ARIZONA_INPUT_ENABLES:
+       case ARIZONA_INPUT_ENABLES_STATUS:
+       case ARIZONA_INPUT_RATE:
+       case ARIZONA_INPUT_VOLUME_RAMP:
+       case ARIZONA_IN1L_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_1L:
+       case ARIZONA_DMIC1L_CONTROL:
+       case ARIZONA_IN1R_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_1R:
+       case ARIZONA_DMIC1R_CONTROL:
+       case ARIZONA_IN2L_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_2L:
+       case ARIZONA_DMIC2L_CONTROL:
+       case ARIZONA_IN2R_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_2R:
+       case ARIZONA_DMIC2R_CONTROL:
+       case ARIZONA_IN3L_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_3L:
+       case ARIZONA_DMIC3L_CONTROL:
+       case ARIZONA_IN3R_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_3R:
+       case ARIZONA_DMIC3R_CONTROL:
+       case ARIZONA_IN4L_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_4L:
+       case ARIZONA_DMIC4L_CONTROL:
+       case ARIZONA_ADC_DIGITAL_VOLUME_4R:
+       case ARIZONA_DMIC4R_CONTROL:
+       case ARIZONA_OUTPUT_ENABLES_1:
+       case ARIZONA_OUTPUT_STATUS_1:
+       case ARIZONA_RAW_OUTPUT_STATUS_1:
+       case ARIZONA_OUTPUT_RATE_1:
+       case ARIZONA_OUTPUT_VOLUME_RAMP:
+       case ARIZONA_OUTPUT_PATH_CONFIG_1L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_1L:
+       case ARIZONA_DAC_VOLUME_LIMIT_1L:
+       case ARIZONA_NOISE_GATE_SELECT_1L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_1R:
+       case ARIZONA_DAC_DIGITAL_VOLUME_1R:
+       case ARIZONA_DAC_VOLUME_LIMIT_1R:
+       case ARIZONA_NOISE_GATE_SELECT_1R:
+       case ARIZONA_OUTPUT_PATH_CONFIG_2L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_2L:
+       case ARIZONA_DAC_VOLUME_LIMIT_2L:
+       case ARIZONA_NOISE_GATE_SELECT_2L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_2R:
+       case ARIZONA_DAC_DIGITAL_VOLUME_2R:
+       case ARIZONA_DAC_VOLUME_LIMIT_2R:
+       case ARIZONA_NOISE_GATE_SELECT_2R:
+       case ARIZONA_OUTPUT_PATH_CONFIG_3L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_3L:
+       case ARIZONA_DAC_VOLUME_LIMIT_3L:
+       case ARIZONA_NOISE_GATE_SELECT_3L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_3R:
+       case ARIZONA_DAC_DIGITAL_VOLUME_3R:
+       case ARIZONA_DAC_VOLUME_LIMIT_3R:
+       case ARIZONA_NOISE_GATE_SELECT_3R:
+       case ARIZONA_OUTPUT_PATH_CONFIG_4L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_4L:
+       case ARIZONA_OUT_VOLUME_4L:
+       case ARIZONA_NOISE_GATE_SELECT_4L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_4R:
+       case ARIZONA_DAC_DIGITAL_VOLUME_4R:
+       case ARIZONA_OUT_VOLUME_4R:
+       case ARIZONA_NOISE_GATE_SELECT_4R:
+       case ARIZONA_OUTPUT_PATH_CONFIG_5L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_5L:
+       case ARIZONA_DAC_VOLUME_LIMIT_5L:
+       case ARIZONA_NOISE_GATE_SELECT_5L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_5R:
+       case ARIZONA_DAC_DIGITAL_VOLUME_5R:
+       case ARIZONA_DAC_VOLUME_LIMIT_5R:
+       case ARIZONA_NOISE_GATE_SELECT_5R:
+       case ARIZONA_OUTPUT_PATH_CONFIG_6L:
+       case ARIZONA_DAC_DIGITAL_VOLUME_6L:
+       case ARIZONA_DAC_VOLUME_LIMIT_6L:
+       case ARIZONA_NOISE_GATE_SELECT_6L:
+       case ARIZONA_OUTPUT_PATH_CONFIG_6R:
+       case ARIZONA_DAC_DIGITAL_VOLUME_6R:
+       case ARIZONA_DAC_VOLUME_LIMIT_6R:
+       case ARIZONA_NOISE_GATE_SELECT_6R:
+       case ARIZONA_DAC_AEC_CONTROL_1:
+       case ARIZONA_NOISE_GATE_CONTROL:
+       case ARIZONA_PDM_SPK1_CTRL_1:
+       case ARIZONA_PDM_SPK1_CTRL_2:
+       case ARIZONA_PDM_SPK2_CTRL_1:
+       case ARIZONA_PDM_SPK2_CTRL_2:
+       case ARIZONA_AIF1_BCLK_CTRL:
+       case ARIZONA_AIF1_TX_PIN_CTRL:
+       case ARIZONA_AIF1_RX_PIN_CTRL:
+       case ARIZONA_AIF1_RATE_CTRL:
+       case ARIZONA_AIF1_FORMAT:
+       case ARIZONA_AIF1_TX_BCLK_RATE:
+       case ARIZONA_AIF1_RX_BCLK_RATE:
+       case ARIZONA_AIF1_FRAME_CTRL_1:
+       case ARIZONA_AIF1_FRAME_CTRL_2:
+       case ARIZONA_AIF1_FRAME_CTRL_3:
+       case ARIZONA_AIF1_FRAME_CTRL_4:
+       case ARIZONA_AIF1_FRAME_CTRL_5:
+       case ARIZONA_AIF1_FRAME_CTRL_6:
+       case ARIZONA_AIF1_FRAME_CTRL_7:
+       case ARIZONA_AIF1_FRAME_CTRL_8:
+       case ARIZONA_AIF1_FRAME_CTRL_9:
+       case ARIZONA_AIF1_FRAME_CTRL_10:
+       case ARIZONA_AIF1_FRAME_CTRL_11:
+       case ARIZONA_AIF1_FRAME_CTRL_12:
+       case ARIZONA_AIF1_FRAME_CTRL_13:
+       case ARIZONA_AIF1_FRAME_CTRL_14:
+       case ARIZONA_AIF1_FRAME_CTRL_15:
+       case ARIZONA_AIF1_FRAME_CTRL_16:
+       case ARIZONA_AIF1_FRAME_CTRL_17:
+       case ARIZONA_AIF1_FRAME_CTRL_18:
+       case ARIZONA_AIF1_TX_ENABLES:
+       case ARIZONA_AIF1_RX_ENABLES:
+       case ARIZONA_AIF2_BCLK_CTRL:
+       case ARIZONA_AIF2_TX_PIN_CTRL:
+       case ARIZONA_AIF2_RX_PIN_CTRL:
+       case ARIZONA_AIF2_RATE_CTRL:
+       case ARIZONA_AIF2_FORMAT:
+       case ARIZONA_AIF2_TX_BCLK_RATE:
+       case ARIZONA_AIF2_RX_BCLK_RATE:
+       case ARIZONA_AIF2_FRAME_CTRL_1:
+       case ARIZONA_AIF2_FRAME_CTRL_2:
+       case ARIZONA_AIF2_FRAME_CTRL_3:
+       case ARIZONA_AIF2_FRAME_CTRL_4:
+       case ARIZONA_AIF2_FRAME_CTRL_11:
+       case ARIZONA_AIF2_FRAME_CTRL_12:
+       case ARIZONA_AIF2_TX_ENABLES:
+       case ARIZONA_AIF2_RX_ENABLES:
+       case ARIZONA_AIF3_BCLK_CTRL:
+       case ARIZONA_AIF3_TX_PIN_CTRL:
+       case ARIZONA_AIF3_RX_PIN_CTRL:
+       case ARIZONA_AIF3_RATE_CTRL:
+       case ARIZONA_AIF3_FORMAT:
+       case ARIZONA_AIF3_TX_BCLK_RATE:
+       case ARIZONA_AIF3_RX_BCLK_RATE:
+       case ARIZONA_AIF3_FRAME_CTRL_1:
+       case ARIZONA_AIF3_FRAME_CTRL_2:
+       case ARIZONA_AIF3_FRAME_CTRL_3:
+       case ARIZONA_AIF3_FRAME_CTRL_4:
+       case ARIZONA_AIF3_FRAME_CTRL_11:
+       case ARIZONA_AIF3_FRAME_CTRL_12:
+       case ARIZONA_AIF3_TX_ENABLES:
+       case ARIZONA_AIF3_RX_ENABLES:
+       case ARIZONA_SLIMBUS_FRAMER_REF_GEAR:
+       case ARIZONA_SLIMBUS_RATES_1:
+       case ARIZONA_SLIMBUS_RATES_2:
+       case ARIZONA_SLIMBUS_RATES_3:
+       case ARIZONA_SLIMBUS_RATES_4:
+       case ARIZONA_SLIMBUS_RATES_5:
+       case ARIZONA_SLIMBUS_RATES_6:
+       case ARIZONA_SLIMBUS_RATES_7:
+       case ARIZONA_SLIMBUS_RATES_8:
+       case ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE:
+       case ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE:
+       case ARIZONA_SLIMBUS_RX_PORT_STATUS:
+       case ARIZONA_SLIMBUS_TX_PORT_STATUS:
+       case ARIZONA_PWM1MIX_INPUT_1_SOURCE:
+       case ARIZONA_PWM1MIX_INPUT_1_VOLUME:
+       case ARIZONA_PWM1MIX_INPUT_2_SOURCE:
+       case ARIZONA_PWM1MIX_INPUT_2_VOLUME:
+       case ARIZONA_PWM1MIX_INPUT_3_SOURCE:
+       case ARIZONA_PWM1MIX_INPUT_3_VOLUME:
+       case ARIZONA_PWM1MIX_INPUT_4_SOURCE:
+       case ARIZONA_PWM1MIX_INPUT_4_VOLUME:
+       case ARIZONA_PWM2MIX_INPUT_1_SOURCE:
+       case ARIZONA_PWM2MIX_INPUT_1_VOLUME:
+       case ARIZONA_PWM2MIX_INPUT_2_SOURCE:
+       case ARIZONA_PWM2MIX_INPUT_2_VOLUME:
+       case ARIZONA_PWM2MIX_INPUT_3_SOURCE:
+       case ARIZONA_PWM2MIX_INPUT_3_VOLUME:
+       case ARIZONA_PWM2MIX_INPUT_4_SOURCE:
+       case ARIZONA_PWM2MIX_INPUT_4_VOLUME:
+       case ARIZONA_MICMIX_INPUT_1_SOURCE:
+       case ARIZONA_MICMIX_INPUT_1_VOLUME:
+       case ARIZONA_MICMIX_INPUT_2_SOURCE:
+       case ARIZONA_MICMIX_INPUT_2_VOLUME:
+       case ARIZONA_MICMIX_INPUT_3_SOURCE:
+       case ARIZONA_MICMIX_INPUT_3_VOLUME:
+       case ARIZONA_MICMIX_INPUT_4_SOURCE:
+       case ARIZONA_MICMIX_INPUT_4_VOLUME:
+       case ARIZONA_NOISEMIX_INPUT_1_SOURCE:
+       case ARIZONA_NOISEMIX_INPUT_1_VOLUME:
+       case ARIZONA_NOISEMIX_INPUT_2_SOURCE:
+       case ARIZONA_NOISEMIX_INPUT_2_VOLUME:
+       case ARIZONA_NOISEMIX_INPUT_3_SOURCE:
+       case ARIZONA_NOISEMIX_INPUT_3_VOLUME:
+       case ARIZONA_NOISEMIX_INPUT_4_SOURCE:
+       case ARIZONA_NOISEMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT1LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT1LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT1LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT1LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT1LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT1LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT1LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT1LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT1RMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT1RMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT1RMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT1RMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT1RMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT1RMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT1RMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT1RMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT2LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT2LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT2LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT2LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT2LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT2LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT2LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT2LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT2RMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT2RMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT2RMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT2RMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT2RMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT2RMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT2RMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT2RMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT3LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT3LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT3LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT3LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT3LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT3LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT3LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT3LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT3RMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT3RMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT3RMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT3RMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT3RMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT3RMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT3RMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT3RMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT4LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT4LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT4LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT4LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT4LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT4LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT4LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT4LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT4RMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT4RMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT4RMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT4RMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT4RMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT4RMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT4RMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT4RMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT5LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT5LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT5LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT5LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT5LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT5LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT5LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT5LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT5RMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT5RMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT5RMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT5RMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT5RMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT5RMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT5RMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT5RMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT6LMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT6LMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT6LMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT6LMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT6LMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT6LMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT6LMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT6LMIX_INPUT_4_VOLUME:
+       case ARIZONA_OUT6RMIX_INPUT_1_SOURCE:
+       case ARIZONA_OUT6RMIX_INPUT_1_VOLUME:
+       case ARIZONA_OUT6RMIX_INPUT_2_SOURCE:
+       case ARIZONA_OUT6RMIX_INPUT_2_VOLUME:
+       case ARIZONA_OUT6RMIX_INPUT_3_SOURCE:
+       case ARIZONA_OUT6RMIX_INPUT_3_VOLUME:
+       case ARIZONA_OUT6RMIX_INPUT_4_SOURCE:
+       case ARIZONA_OUT6RMIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX1MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX1MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX1MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX1MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX1MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX1MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX1MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX2MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX2MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX2MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX2MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX2MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX2MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX2MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX3MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX3MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX3MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX3MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX3MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX3MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX3MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX4MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX4MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX4MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX4MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX4MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX4MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX4MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX5MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX5MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX5MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX5MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX5MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX5MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX5MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX6MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX6MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX6MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX6MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX6MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX6MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX6MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX7MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX7MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX7MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX7MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX7MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX7MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX7MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF1TX8MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF1TX8MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF1TX8MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF1TX8MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF1TX8MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF1TX8MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF1TX8MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF2TX1MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF2TX1MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF2TX1MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF2TX1MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF2TX1MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF2TX1MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF2TX1MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF2TX2MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF2TX2MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF2TX2MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF2TX2MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF3TX1MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF3TX1MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF3TX1MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF3TX1MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF3TX1MIX_INPUT_4_VOLUME:
+       case ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_AIF3TX2MIX_INPUT_1_VOLUME:
+       case ARIZONA_AIF3TX2MIX_INPUT_2_SOURCE:
+       case ARIZONA_AIF3TX2MIX_INPUT_2_VOLUME:
+       case ARIZONA_AIF3TX2MIX_INPUT_3_SOURCE:
+       case ARIZONA_AIF3TX2MIX_INPUT_3_VOLUME:
+       case ARIZONA_AIF3TX2MIX_INPUT_4_SOURCE:
+       case ARIZONA_AIF3TX2MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX1MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX1MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX1MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX1MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX1MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX1MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX1MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX2MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX2MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX2MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX2MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX2MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX2MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX2MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX3MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX3MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX3MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX3MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX3MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX3MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX3MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX4MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX4MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX4MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX4MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX4MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX4MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX4MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX5MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX5MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX5MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX5MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX5MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX5MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX5MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX6MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX6MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX6MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX6MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX6MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX6MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX6MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX7MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX7MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX7MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX7MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX7MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX7MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX7MIX_INPUT_4_VOLUME:
+       case ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE:
+       case ARIZONA_SLIMTX8MIX_INPUT_1_VOLUME:
+       case ARIZONA_SLIMTX8MIX_INPUT_2_SOURCE:
+       case ARIZONA_SLIMTX8MIX_INPUT_2_VOLUME:
+       case ARIZONA_SLIMTX8MIX_INPUT_3_SOURCE:
+       case ARIZONA_SLIMTX8MIX_INPUT_3_VOLUME:
+       case ARIZONA_SLIMTX8MIX_INPUT_4_SOURCE:
+       case ARIZONA_SLIMTX8MIX_INPUT_4_VOLUME:
+       case ARIZONA_EQ1MIX_INPUT_1_SOURCE:
+       case ARIZONA_EQ1MIX_INPUT_1_VOLUME:
+       case ARIZONA_EQ1MIX_INPUT_2_SOURCE:
+       case ARIZONA_EQ1MIX_INPUT_2_VOLUME:
+       case ARIZONA_EQ1MIX_INPUT_3_SOURCE:
+       case ARIZONA_EQ1MIX_INPUT_3_VOLUME:
+       case ARIZONA_EQ1MIX_INPUT_4_SOURCE:
+       case ARIZONA_EQ1MIX_INPUT_4_VOLUME:
+       case ARIZONA_EQ2MIX_INPUT_1_SOURCE:
+       case ARIZONA_EQ2MIX_INPUT_1_VOLUME:
+       case ARIZONA_EQ2MIX_INPUT_2_SOURCE:
+       case ARIZONA_EQ2MIX_INPUT_2_VOLUME:
+       case ARIZONA_EQ2MIX_INPUT_3_SOURCE:
+       case ARIZONA_EQ2MIX_INPUT_3_VOLUME:
+       case ARIZONA_EQ2MIX_INPUT_4_SOURCE:
+       case ARIZONA_EQ2MIX_INPUT_4_VOLUME:
+       case ARIZONA_EQ3MIX_INPUT_1_SOURCE:
+       case ARIZONA_EQ3MIX_INPUT_1_VOLUME:
+       case ARIZONA_EQ3MIX_INPUT_2_SOURCE:
+       case ARIZONA_EQ3MIX_INPUT_2_VOLUME:
+       case ARIZONA_EQ3MIX_INPUT_3_SOURCE:
+       case ARIZONA_EQ3MIX_INPUT_3_VOLUME:
+       case ARIZONA_EQ3MIX_INPUT_4_SOURCE:
+       case ARIZONA_EQ3MIX_INPUT_4_VOLUME:
+       case ARIZONA_EQ4MIX_INPUT_1_SOURCE:
+       case ARIZONA_EQ4MIX_INPUT_1_VOLUME:
+       case ARIZONA_EQ4MIX_INPUT_2_SOURCE:
+       case ARIZONA_EQ4MIX_INPUT_2_VOLUME:
+       case ARIZONA_EQ4MIX_INPUT_3_SOURCE:
+       case ARIZONA_EQ4MIX_INPUT_3_VOLUME:
+       case ARIZONA_EQ4MIX_INPUT_4_SOURCE:
+       case ARIZONA_EQ4MIX_INPUT_4_VOLUME:
+       case ARIZONA_DRC1LMIX_INPUT_1_SOURCE:
+       case ARIZONA_DRC1LMIX_INPUT_1_VOLUME:
+       case ARIZONA_DRC1LMIX_INPUT_2_SOURCE:
+       case ARIZONA_DRC1LMIX_INPUT_2_VOLUME:
+       case ARIZONA_DRC1LMIX_INPUT_3_SOURCE:
+       case ARIZONA_DRC1LMIX_INPUT_3_VOLUME:
+       case ARIZONA_DRC1LMIX_INPUT_4_SOURCE:
+       case ARIZONA_DRC1LMIX_INPUT_4_VOLUME:
+       case ARIZONA_DRC1RMIX_INPUT_1_SOURCE:
+       case ARIZONA_DRC1RMIX_INPUT_1_VOLUME:
+       case ARIZONA_DRC1RMIX_INPUT_2_SOURCE:
+       case ARIZONA_DRC1RMIX_INPUT_2_VOLUME:
+       case ARIZONA_DRC1RMIX_INPUT_3_SOURCE:
+       case ARIZONA_DRC1RMIX_INPUT_3_VOLUME:
+       case ARIZONA_DRC1RMIX_INPUT_4_SOURCE:
+       case ARIZONA_DRC1RMIX_INPUT_4_VOLUME:
+       case ARIZONA_DRC2LMIX_INPUT_1_SOURCE:
+       case ARIZONA_DRC2LMIX_INPUT_1_VOLUME:
+       case ARIZONA_DRC2LMIX_INPUT_2_SOURCE:
+       case ARIZONA_DRC2LMIX_INPUT_2_VOLUME:
+       case ARIZONA_DRC2LMIX_INPUT_3_SOURCE:
+       case ARIZONA_DRC2LMIX_INPUT_3_VOLUME:
+       case ARIZONA_DRC2LMIX_INPUT_4_SOURCE:
+       case ARIZONA_DRC2LMIX_INPUT_4_VOLUME:
+       case ARIZONA_DRC2RMIX_INPUT_1_SOURCE:
+       case ARIZONA_DRC2RMIX_INPUT_1_VOLUME:
+       case ARIZONA_DRC2RMIX_INPUT_2_SOURCE:
+       case ARIZONA_DRC2RMIX_INPUT_2_VOLUME:
+       case ARIZONA_DRC2RMIX_INPUT_3_SOURCE:
+       case ARIZONA_DRC2RMIX_INPUT_3_VOLUME:
+       case ARIZONA_DRC2RMIX_INPUT_4_SOURCE:
+       case ARIZONA_DRC2RMIX_INPUT_4_VOLUME:
+       case ARIZONA_HPLP1MIX_INPUT_1_SOURCE:
+       case ARIZONA_HPLP1MIX_INPUT_1_VOLUME:
+       case ARIZONA_HPLP1MIX_INPUT_2_SOURCE:
+       case ARIZONA_HPLP1MIX_INPUT_2_VOLUME:
+       case ARIZONA_HPLP1MIX_INPUT_3_SOURCE:
+       case ARIZONA_HPLP1MIX_INPUT_3_VOLUME:
+       case ARIZONA_HPLP1MIX_INPUT_4_SOURCE:
+       case ARIZONA_HPLP1MIX_INPUT_4_VOLUME:
+       case ARIZONA_HPLP2MIX_INPUT_1_SOURCE:
+       case ARIZONA_HPLP2MIX_INPUT_1_VOLUME:
+       case ARIZONA_HPLP2MIX_INPUT_2_SOURCE:
+       case ARIZONA_HPLP2MIX_INPUT_2_VOLUME:
+       case ARIZONA_HPLP2MIX_INPUT_3_SOURCE:
+       case ARIZONA_HPLP2MIX_INPUT_3_VOLUME:
+       case ARIZONA_HPLP2MIX_INPUT_4_SOURCE:
+       case ARIZONA_HPLP2MIX_INPUT_4_VOLUME:
+       case ARIZONA_HPLP3MIX_INPUT_1_SOURCE:
+       case ARIZONA_HPLP3MIX_INPUT_1_VOLUME:
+       case ARIZONA_HPLP3MIX_INPUT_2_SOURCE:
+       case ARIZONA_HPLP3MIX_INPUT_2_VOLUME:
+       case ARIZONA_HPLP3MIX_INPUT_3_SOURCE:
+       case ARIZONA_HPLP3MIX_INPUT_3_VOLUME:
+       case ARIZONA_HPLP3MIX_INPUT_4_SOURCE:
+       case ARIZONA_HPLP3MIX_INPUT_4_VOLUME:
+       case ARIZONA_HPLP4MIX_INPUT_1_SOURCE:
+       case ARIZONA_HPLP4MIX_INPUT_1_VOLUME:
+       case ARIZONA_HPLP4MIX_INPUT_2_SOURCE:
+       case ARIZONA_HPLP4MIX_INPUT_2_VOLUME:
+       case ARIZONA_HPLP4MIX_INPUT_3_SOURCE:
+       case ARIZONA_HPLP4MIX_INPUT_3_VOLUME:
+       case ARIZONA_HPLP4MIX_INPUT_4_SOURCE:
+       case ARIZONA_HPLP4MIX_INPUT_4_VOLUME:
+       case ARIZONA_DSP1LMIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1LMIX_INPUT_1_VOLUME:
+       case ARIZONA_DSP1LMIX_INPUT_2_SOURCE:
+       case ARIZONA_DSP1LMIX_INPUT_2_VOLUME:
+       case ARIZONA_DSP1LMIX_INPUT_3_SOURCE:
+       case ARIZONA_DSP1LMIX_INPUT_3_VOLUME:
+       case ARIZONA_DSP1LMIX_INPUT_4_SOURCE:
+       case ARIZONA_DSP1LMIX_INPUT_4_VOLUME:
+       case ARIZONA_DSP1RMIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1RMIX_INPUT_1_VOLUME:
+       case ARIZONA_DSP1RMIX_INPUT_2_SOURCE:
+       case ARIZONA_DSP1RMIX_INPUT_2_VOLUME:
+       case ARIZONA_DSP1RMIX_INPUT_3_SOURCE:
+       case ARIZONA_DSP1RMIX_INPUT_3_VOLUME:
+       case ARIZONA_DSP1RMIX_INPUT_4_SOURCE:
+       case ARIZONA_DSP1RMIX_INPUT_4_VOLUME:
+       case ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1AUX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1AUX3MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1AUX4MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1AUX5MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP1AUX6MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP2LMIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP2LMIX_INPUT_1_VOLUME:
+       case ARIZONA_DSP2LMIX_INPUT_2_SOURCE:
+       case ARIZONA_DSP2LMIX_INPUT_2_VOLUME:
+       case ARIZONA_DSP2LMIX_INPUT_3_SOURCE:
+       case ARIZONA_DSP2LMIX_INPUT_3_VOLUME:
+       case ARIZONA_DSP2LMIX_INPUT_4_SOURCE:
+       case ARIZONA_DSP2LMIX_INPUT_4_VOLUME:
+       case ARIZONA_DSP2RMIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP2RMIX_INPUT_1_VOLUME:
+       case ARIZONA_DSP2RMIX_INPUT_2_SOURCE:
+       case ARIZONA_DSP2RMIX_INPUT_2_VOLUME:
+       case ARIZONA_DSP2RMIX_INPUT_3_SOURCE:
+       case ARIZONA_DSP2RMIX_INPUT_3_VOLUME:
+       case ARIZONA_DSP2RMIX_INPUT_4_SOURCE:
+       case ARIZONA_DSP2RMIX_INPUT_4_VOLUME:
+       case ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP2AUX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP2AUX3MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP2AUX4MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP2AUX5MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP2AUX6MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP3LMIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP3LMIX_INPUT_1_VOLUME:
+       case ARIZONA_DSP3LMIX_INPUT_2_SOURCE:
+       case ARIZONA_DSP3LMIX_INPUT_2_VOLUME:
+       case ARIZONA_DSP3LMIX_INPUT_3_SOURCE:
+       case ARIZONA_DSP3LMIX_INPUT_3_VOLUME:
+       case ARIZONA_DSP3LMIX_INPUT_4_SOURCE:
+       case ARIZONA_DSP3LMIX_INPUT_4_VOLUME:
+       case ARIZONA_DSP3RMIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP3RMIX_INPUT_1_VOLUME:
+       case ARIZONA_DSP3RMIX_INPUT_2_SOURCE:
+       case ARIZONA_DSP3RMIX_INPUT_2_VOLUME:
+       case ARIZONA_DSP3RMIX_INPUT_3_SOURCE:
+       case ARIZONA_DSP3RMIX_INPUT_3_VOLUME:
+       case ARIZONA_DSP3RMIX_INPUT_4_SOURCE:
+       case ARIZONA_DSP3RMIX_INPUT_4_VOLUME:
+       case ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP3AUX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP3AUX3MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP3AUX4MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP3AUX5MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP3AUX6MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP4LMIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP4LMIX_INPUT_1_VOLUME:
+       case ARIZONA_DSP4LMIX_INPUT_2_SOURCE:
+       case ARIZONA_DSP4LMIX_INPUT_2_VOLUME:
+       case ARIZONA_DSP4LMIX_INPUT_3_SOURCE:
+       case ARIZONA_DSP4LMIX_INPUT_3_VOLUME:
+       case ARIZONA_DSP4LMIX_INPUT_4_SOURCE:
+       case ARIZONA_DSP4LMIX_INPUT_4_VOLUME:
+       case ARIZONA_DSP4RMIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP4RMIX_INPUT_1_VOLUME:
+       case ARIZONA_DSP4RMIX_INPUT_2_SOURCE:
+       case ARIZONA_DSP4RMIX_INPUT_2_VOLUME:
+       case ARIZONA_DSP4RMIX_INPUT_3_SOURCE:
+       case ARIZONA_DSP4RMIX_INPUT_3_VOLUME:
+       case ARIZONA_DSP4RMIX_INPUT_4_SOURCE:
+       case ARIZONA_DSP4RMIX_INPUT_4_VOLUME:
+       case ARIZONA_DSP4AUX1MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP4AUX2MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP4AUX3MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP4AUX4MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP4AUX5MIX_INPUT_1_SOURCE:
+       case ARIZONA_DSP4AUX6MIX_INPUT_1_SOURCE:
+       case ARIZONA_ASRC1LMIX_INPUT_1_SOURCE:
+       case ARIZONA_ASRC1RMIX_INPUT_1_SOURCE:
+       case ARIZONA_ASRC2LMIX_INPUT_1_SOURCE:
+       case ARIZONA_ASRC2RMIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE:
+       case ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE:
+       case ARIZONA_GPIO1_CTRL:
+       case ARIZONA_GPIO2_CTRL:
+       case ARIZONA_GPIO3_CTRL:
+       case ARIZONA_GPIO4_CTRL:
+       case ARIZONA_GPIO5_CTRL:
+       case ARIZONA_IRQ_CTRL_1:
+       case ARIZONA_GPIO_DEBOUNCE_CONFIG:
+       case ARIZONA_MISC_PAD_CTRL_1:
+       case ARIZONA_MISC_PAD_CTRL_2:
+       case ARIZONA_MISC_PAD_CTRL_3:
+       case ARIZONA_MISC_PAD_CTRL_4:
+       case ARIZONA_MISC_PAD_CTRL_5:
+       case ARIZONA_MISC_PAD_CTRL_6:
+       case ARIZONA_MISC_PAD_CTRL_7:
+       case ARIZONA_MISC_PAD_CTRL_8:
+       case ARIZONA_MISC_PAD_CTRL_9:
+       case ARIZONA_MISC_PAD_CTRL_10:
+       case ARIZONA_MISC_PAD_CTRL_11:
+       case ARIZONA_MISC_PAD_CTRL_12:
+       case ARIZONA_MISC_PAD_CTRL_13:
+       case ARIZONA_MISC_PAD_CTRL_14:
+       case ARIZONA_MISC_PAD_CTRL_15:
+       case ARIZONA_MISC_PAD_CTRL_16:
+       case ARIZONA_MISC_PAD_CTRL_17:
+       case ARIZONA_MISC_PAD_CTRL_18:
+       case ARIZONA_INTERRUPT_STATUS_1:
+       case ARIZONA_INTERRUPT_STATUS_2:
+       case ARIZONA_INTERRUPT_STATUS_3:
+       case ARIZONA_INTERRUPT_STATUS_4:
+       case ARIZONA_INTERRUPT_STATUS_5:
+       case ARIZONA_INTERRUPT_STATUS_1_MASK:
+       case ARIZONA_INTERRUPT_STATUS_2_MASK:
+       case ARIZONA_INTERRUPT_STATUS_3_MASK:
+       case ARIZONA_INTERRUPT_STATUS_4_MASK:
+       case ARIZONA_INTERRUPT_STATUS_5_MASK:
+       case ARIZONA_INTERRUPT_CONTROL:
+       case ARIZONA_IRQ2_STATUS_1:
+       case ARIZONA_IRQ2_STATUS_2:
+       case ARIZONA_IRQ2_STATUS_3:
+       case ARIZONA_IRQ2_STATUS_4:
+       case ARIZONA_IRQ2_STATUS_5:
+       case ARIZONA_IRQ2_STATUS_1_MASK:
+       case ARIZONA_IRQ2_STATUS_2_MASK:
+       case ARIZONA_IRQ2_STATUS_3_MASK:
+       case ARIZONA_IRQ2_STATUS_4_MASK:
+       case ARIZONA_IRQ2_STATUS_5_MASK:
+       case ARIZONA_IRQ2_CONTROL:
+       case ARIZONA_INTERRUPT_RAW_STATUS_2:
+       case ARIZONA_INTERRUPT_RAW_STATUS_3:
+       case ARIZONA_INTERRUPT_RAW_STATUS_4:
+       case ARIZONA_INTERRUPT_RAW_STATUS_5:
+       case ARIZONA_INTERRUPT_RAW_STATUS_6:
+       case ARIZONA_INTERRUPT_RAW_STATUS_7:
+       case ARIZONA_INTERRUPT_RAW_STATUS_8:
+       case ARIZONA_IRQ_PIN_STATUS:
+       case ARIZONA_AOD_WKUP_AND_TRIG:
+       case ARIZONA_AOD_IRQ1:
+       case ARIZONA_AOD_IRQ2:
+       case ARIZONA_AOD_IRQ_MASK_IRQ1:
+       case ARIZONA_AOD_IRQ_MASK_IRQ2:
+       case ARIZONA_AOD_IRQ_RAW_STATUS:
+       case ARIZONA_JACK_DETECT_DEBOUNCE:
+       case ARIZONA_FX_CTRL1:
+       case ARIZONA_FX_CTRL2:
+       case ARIZONA_EQ1_1:
+       case ARIZONA_EQ1_2:
+       case ARIZONA_EQ1_3:
+       case ARIZONA_EQ1_4:
+       case ARIZONA_EQ1_5:
+       case ARIZONA_EQ1_6:
+       case ARIZONA_EQ1_7:
+       case ARIZONA_EQ1_8:
+       case ARIZONA_EQ1_9:
+       case ARIZONA_EQ1_10:
+       case ARIZONA_EQ1_11:
+       case ARIZONA_EQ1_12:
+       case ARIZONA_EQ1_13:
+       case ARIZONA_EQ1_14:
+       case ARIZONA_EQ1_15:
+       case ARIZONA_EQ1_16:
+       case ARIZONA_EQ1_17:
+       case ARIZONA_EQ1_18:
+       case ARIZONA_EQ1_19:
+       case ARIZONA_EQ1_20:
+       case ARIZONA_EQ1_21:
+       case ARIZONA_EQ2_1:
+       case ARIZONA_EQ2_2:
+       case ARIZONA_EQ2_3:
+       case ARIZONA_EQ2_4:
+       case ARIZONA_EQ2_5:
+       case ARIZONA_EQ2_6:
+       case ARIZONA_EQ2_7:
+       case ARIZONA_EQ2_8:
+       case ARIZONA_EQ2_9:
+       case ARIZONA_EQ2_10:
+       case ARIZONA_EQ2_11:
+       case ARIZONA_EQ2_12:
+       case ARIZONA_EQ2_13:
+       case ARIZONA_EQ2_14:
+       case ARIZONA_EQ2_15:
+       case ARIZONA_EQ2_16:
+       case ARIZONA_EQ2_17:
+       case ARIZONA_EQ2_18:
+       case ARIZONA_EQ2_19:
+       case ARIZONA_EQ2_20:
+       case ARIZONA_EQ2_21:
+       case ARIZONA_EQ3_1:
+       case ARIZONA_EQ3_2:
+       case ARIZONA_EQ3_3:
+       case ARIZONA_EQ3_4:
+       case ARIZONA_EQ3_5:
+       case ARIZONA_EQ3_6:
+       case ARIZONA_EQ3_7:
+       case ARIZONA_EQ3_8:
+       case ARIZONA_EQ3_9:
+       case ARIZONA_EQ3_10:
+       case ARIZONA_EQ3_11:
+       case ARIZONA_EQ3_12:
+       case ARIZONA_EQ3_13:
+       case ARIZONA_EQ3_14:
+       case ARIZONA_EQ3_15:
+       case ARIZONA_EQ3_16:
+       case ARIZONA_EQ3_17:
+       case ARIZONA_EQ3_18:
+       case ARIZONA_EQ3_19:
+       case ARIZONA_EQ3_20:
+       case ARIZONA_EQ3_21:
+       case ARIZONA_EQ4_1:
+       case ARIZONA_EQ4_2:
+       case ARIZONA_EQ4_3:
+       case ARIZONA_EQ4_4:
+       case ARIZONA_EQ4_5:
+       case ARIZONA_EQ4_6:
+       case ARIZONA_EQ4_7:
+       case ARIZONA_EQ4_8:
+       case ARIZONA_EQ4_9:
+       case ARIZONA_EQ4_10:
+       case ARIZONA_EQ4_11:
+       case ARIZONA_EQ4_12:
+       case ARIZONA_EQ4_13:
+       case ARIZONA_EQ4_14:
+       case ARIZONA_EQ4_15:
+       case ARIZONA_EQ4_16:
+       case ARIZONA_EQ4_17:
+       case ARIZONA_EQ4_18:
+       case ARIZONA_EQ4_19:
+       case ARIZONA_EQ4_20:
+       case ARIZONA_EQ4_21:
+       case ARIZONA_DRC1_CTRL1:
+       case ARIZONA_DRC1_CTRL2:
+       case ARIZONA_DRC1_CTRL3:
+       case ARIZONA_DRC1_CTRL4:
+       case ARIZONA_DRC1_CTRL5:
+       case ARIZONA_DRC2_CTRL1:
+       case ARIZONA_DRC2_CTRL2:
+       case ARIZONA_DRC2_CTRL3:
+       case ARIZONA_DRC2_CTRL4:
+       case ARIZONA_DRC2_CTRL5:
+       case ARIZONA_HPLPF1_1:
+       case ARIZONA_HPLPF1_2:
+       case ARIZONA_HPLPF2_1:
+       case ARIZONA_HPLPF2_2:
+       case ARIZONA_HPLPF3_1:
+       case ARIZONA_HPLPF3_2:
+       case ARIZONA_HPLPF4_1:
+       case ARIZONA_HPLPF4_2:
+       case ARIZONA_ASRC_ENABLE:
+       case ARIZONA_ASRC_STATUS:
+       case ARIZONA_ASRC_RATE1:
+       case ARIZONA_ISRC_1_CTRL_1:
+       case ARIZONA_ISRC_1_CTRL_2:
+       case ARIZONA_ISRC_1_CTRL_3:
+       case ARIZONA_ISRC_2_CTRL_1:
+       case ARIZONA_ISRC_2_CTRL_2:
+       case ARIZONA_ISRC_2_CTRL_3:
+       case ARIZONA_ISRC_3_CTRL_1:
+       case ARIZONA_ISRC_3_CTRL_2:
+       case ARIZONA_ISRC_3_CTRL_3:
+       case ARIZONA_CLOCK_CONTROL:
+       case ARIZONA_ANC_SRC:
+       case ARIZONA_DSP_STATUS:
+       case ARIZONA_DSP1_CONTROL_1:
+       case ARIZONA_DSP1_CLOCKING_1:
+       case ARIZONA_DSP1_STATUS_1:
+       case ARIZONA_DSP1_STATUS_2:
+       case ARIZONA_DSP2_CONTROL_1:
+       case ARIZONA_DSP2_CLOCKING_1:
+       case ARIZONA_DSP2_STATUS_1:
+       case ARIZONA_DSP2_STATUS_2:
+       case ARIZONA_DSP3_CONTROL_1:
+       case ARIZONA_DSP3_CLOCKING_1:
+       case ARIZONA_DSP3_STATUS_1:
+       case ARIZONA_DSP3_STATUS_2:
+       case ARIZONA_DSP4_CONTROL_1:
+       case ARIZONA_DSP4_CLOCKING_1:
+       case ARIZONA_DSP4_STATUS_1:
+       case ARIZONA_DSP4_STATUS_2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool wm5110_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case ARIZONA_SOFTWARE_RESET:
+       case ARIZONA_DEVICE_REVISION:
+       case ARIZONA_HAPTICS_STATUS:
+       case ARIZONA_SAMPLE_RATE_1_STATUS:
+       case ARIZONA_SAMPLE_RATE_2_STATUS:
+       case ARIZONA_SAMPLE_RATE_3_STATUS:
+       case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
+       case ARIZONA_MIC_DETECT_3:
+       case ARIZONA_HEADPHONE_DETECT_2:
+       case ARIZONA_INPUT_ENABLES_STATUS:
+       case ARIZONA_OUTPUT_STATUS_1:
+       case ARIZONA_RAW_OUTPUT_STATUS_1:
+       case ARIZONA_SLIMBUS_RX_PORT_STATUS:
+       case ARIZONA_SLIMBUS_TX_PORT_STATUS:
+       case ARIZONA_INTERRUPT_STATUS_1:
+       case ARIZONA_INTERRUPT_STATUS_2:
+       case ARIZONA_INTERRUPT_STATUS_3:
+       case ARIZONA_INTERRUPT_STATUS_4:
+       case ARIZONA_INTERRUPT_STATUS_5:
+       case ARIZONA_IRQ2_STATUS_1:
+       case ARIZONA_IRQ2_STATUS_2:
+       case ARIZONA_IRQ2_STATUS_3:
+       case ARIZONA_IRQ2_STATUS_4:
+       case ARIZONA_IRQ2_STATUS_5:
+       case ARIZONA_INTERRUPT_RAW_STATUS_2:
+       case ARIZONA_INTERRUPT_RAW_STATUS_3:
+       case ARIZONA_INTERRUPT_RAW_STATUS_4:
+       case ARIZONA_INTERRUPT_RAW_STATUS_5:
+       case ARIZONA_INTERRUPT_RAW_STATUS_6:
+       case ARIZONA_INTERRUPT_RAW_STATUS_7:
+       case ARIZONA_INTERRUPT_RAW_STATUS_8:
+       case ARIZONA_IRQ_PIN_STATUS:
+       case ARIZONA_AOD_IRQ1:
+       case ARIZONA_AOD_IRQ2:
+       case ARIZONA_ASRC_STATUS:
+       case ARIZONA_DSP_STATUS:
+       case ARIZONA_DSP1_CONTROL_1:
+       case ARIZONA_DSP1_CLOCKING_1:
+       case ARIZONA_DSP1_STATUS_1:
+       case ARIZONA_DSP1_STATUS_2:
+       case ARIZONA_DSP2_STATUS_1:
+       case ARIZONA_DSP2_STATUS_2:
+       case ARIZONA_DSP3_STATUS_1:
+       case ARIZONA_DSP3_STATUS_2:
+       case ARIZONA_DSP4_STATUS_1:
+       case ARIZONA_DSP4_STATUS_2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+const struct regmap_config wm5110_spi_regmap = {
+       .reg_bits = 32,
+       .pad_bits = 16,
+       .val_bits = 16,
+
+       .max_register = ARIZONA_DSP1_STATUS_2,
+       .readable_reg = wm5110_readable_register,
+       .volatile_reg = wm5110_volatile_register,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = wm5110_reg_default,
+       .num_reg_defaults = ARRAY_SIZE(wm5110_reg_default),
+};
+EXPORT_SYMBOL_GPL(wm5110_spi_regmap);
+
+const struct regmap_config wm5110_i2c_regmap = {
+       .reg_bits = 32,
+       .val_bits = 16,
+
+       .max_register = ARIZONA_DSP1_STATUS_2,
+       .readable_reg = wm5110_readable_register,
+       .volatile_reg = wm5110_volatile_register,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = wm5110_reg_default,
+       .num_reg_defaults = ARRAY_SIZE(wm5110_reg_default),
+};
+EXPORT_SYMBOL_GPL(wm5110_i2c_regmap);
index 8a9b11ca076ac3c528e914b52dd78d958b714fae..7c1ae24605d936e51e0ae485c59dcbf9c2f5372b 100644 (file)
@@ -32,9 +32,6 @@
 #include <linux/mfd/wm8350/supply.h>
 #include <linux/mfd/wm8350/wdt.h>
 
-#define WM8350_UNLOCK_KEY              0x0013
-#define WM8350_LOCK_KEY                        0x0000
-
 #define WM8350_CLOCK_CONTROL_1         0x28
 #define WM8350_AIF_TEST                        0x74
 
 /*
  * WM8350 Device IO
  */
-static DEFINE_MUTEX(io_mutex);
 static DEFINE_MUTEX(reg_lock_mutex);
 
-/* Perform a physical read from the device.
- */
-static int wm8350_phys_read(struct wm8350 *wm8350, u8 reg, int num_regs,
-                           u16 *dest)
-{
-       int i, ret;
-       int bytes = num_regs * 2;
-
-       dev_dbg(wm8350->dev, "volatile read\n");
-       ret = regmap_raw_read(wm8350->regmap, reg, dest, bytes);
-
-       for (i = reg; i < reg + num_regs; i++) {
-               /* Cache is CPU endian */
-               dest[i - reg] = be16_to_cpu(dest[i - reg]);
-
-               /* Mask out non-readable bits */
-               dest[i - reg] &= wm8350_reg_io_map[i].readable;
-       }
-
-       dump(num_regs, dest);
-
-       return ret;
-}
-
-static int wm8350_read(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *dest)
-{
-       int i;
-       int end = reg + num_regs;
-       int ret = 0;
-       int bytes = num_regs * 2;
-
-       if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
-               dev_err(wm8350->dev, "invalid reg %x\n",
-                       reg + num_regs - 1);
-               return -EINVAL;
-       }
-
-       dev_dbg(wm8350->dev,
-               "%s R%d(0x%2.2x) %d regs\n", __func__, reg, reg, num_regs);
-
-#if WM8350_BUS_DEBUG
-       /* we can _safely_ read any register, but warn if read not supported */
-       for (i = reg; i < end; i++) {
-               if (!wm8350_reg_io_map[i].readable)
-                       dev_warn(wm8350->dev,
-                               "reg R%d is not readable\n", i);
-       }
-#endif
-
-       /* if any volatile registers are required, then read back all */
-       for (i = reg; i < end; i++)
-               if (wm8350_reg_io_map[i].vol)
-                       return wm8350_phys_read(wm8350, reg, num_regs, dest);
-
-       /* no volatiles, then cache is good */
-       dev_dbg(wm8350->dev, "cache read\n");
-       memcpy(dest, &wm8350->reg_cache[reg], bytes);
-       dump(num_regs, dest);
-       return ret;
-}
-
-static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg)
-{
-       if (reg == WM8350_SECURITY ||
-           wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY)
-               return 0;
-
-       if ((reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
-            reg <= WM8350_GPIO_FUNCTION_SELECT_4) ||
-           (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 &&
-            reg <= WM8350_BATTERY_CHARGER_CONTROL_3))
-               return 1;
-       return 0;
-}
-
-static int wm8350_write(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *src)
-{
-       int i;
-       int end = reg + num_regs;
-       int bytes = num_regs * 2;
-
-       if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
-               dev_err(wm8350->dev, "invalid reg %x\n",
-                       reg + num_regs - 1);
-               return -EINVAL;
-       }
-
-       /* it's generally not a good idea to write to RO or locked registers */
-       for (i = reg; i < end; i++) {
-               if (!wm8350_reg_io_map[i].writable) {
-                       dev_err(wm8350->dev,
-                               "attempted write to read only reg R%d\n", i);
-                       return -EINVAL;
-               }
-
-               if (is_reg_locked(wm8350, i)) {
-                       dev_err(wm8350->dev,
-                              "attempted write to locked reg R%d\n", i);
-                       return -EINVAL;
-               }
-
-               src[i - reg] &= wm8350_reg_io_map[i].writable;
-
-               wm8350->reg_cache[i] =
-                       (wm8350->reg_cache[i] & ~wm8350_reg_io_map[i].writable)
-                       | src[i - reg];
-
-               src[i - reg] = cpu_to_be16(src[i - reg]);
-       }
-
-       /* Actually write it out */
-       return regmap_raw_write(wm8350->regmap, reg, src, bytes);
-}
-
 /*
  * Safe read, modify, write methods
  */
 int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
 {
-       u16 data;
-       int err;
-
-       mutex_lock(&io_mutex);
-       err = wm8350_read(wm8350, reg, 1, &data);
-       if (err) {
-               dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
-               goto out;
-       }
-
-       data &= ~mask;
-       err = wm8350_write(wm8350, reg, 1, &data);
-       if (err)
-               dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
-out:
-       mutex_unlock(&io_mutex);
-       return err;
+       return regmap_update_bits(wm8350->regmap, reg, mask, 0);
 }
 EXPORT_SYMBOL_GPL(wm8350_clear_bits);
 
 int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
 {
-       u16 data;
-       int err;
-
-       mutex_lock(&io_mutex);
-       err = wm8350_read(wm8350, reg, 1, &data);
-       if (err) {
-               dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
-               goto out;
-       }
-
-       data |= mask;
-       err = wm8350_write(wm8350, reg, 1, &data);
-       if (err)
-               dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
-out:
-       mutex_unlock(&io_mutex);
-       return err;
+       return regmap_update_bits(wm8350->regmap, reg, mask, mask);
 }
 EXPORT_SYMBOL_GPL(wm8350_set_bits);
 
 u16 wm8350_reg_read(struct wm8350 *wm8350, int reg)
 {
-       u16 data;
+       unsigned int data;
        int err;
 
-       mutex_lock(&io_mutex);
-       err = wm8350_read(wm8350, reg, 1, &data);
+       err = regmap_read(wm8350->regmap, reg, &data);
        if (err)
                dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
 
-       mutex_unlock(&io_mutex);
        return data;
 }
 EXPORT_SYMBOL_GPL(wm8350_reg_read);
@@ -245,13 +93,11 @@ EXPORT_SYMBOL_GPL(wm8350_reg_read);
 int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val)
 {
        int ret;
-       u16 data = val;
 
-       mutex_lock(&io_mutex);
-       ret = wm8350_write(wm8350, reg, 1, &data);
+       ret = regmap_write(wm8350->regmap, reg, val);
+
        if (ret)
                dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
-       mutex_unlock(&io_mutex);
        return ret;
 }
 EXPORT_SYMBOL_GPL(wm8350_reg_write);
@@ -261,12 +107,11 @@ int wm8350_block_read(struct wm8350 *wm8350, int start_reg, int regs,
 {
        int err = 0;
 
-       mutex_lock(&io_mutex);
-       err = wm8350_read(wm8350, start_reg, regs, dest);
+       err = regmap_bulk_read(wm8350->regmap, start_reg, dest, regs);
        if (err)
                dev_err(wm8350->dev, "block read starting from R%d failed\n",
                        start_reg);
-       mutex_unlock(&io_mutex);
+
        return err;
 }
 EXPORT_SYMBOL_GPL(wm8350_block_read);
@@ -276,12 +121,11 @@ int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs,
 {
        int ret = 0;
 
-       mutex_lock(&io_mutex);
-       ret = wm8350_write(wm8350, start_reg, regs, src);
+       ret = regmap_bulk_write(wm8350->regmap, start_reg, src, regs);
        if (ret)
                dev_err(wm8350->dev, "block write starting at R%d failed\n",
                        start_reg);
-       mutex_unlock(&io_mutex);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(wm8350_block_write);
@@ -295,15 +139,20 @@ EXPORT_SYMBOL_GPL(wm8350_block_write);
  */
 int wm8350_reg_lock(struct wm8350 *wm8350)
 {
-       u16 key = WM8350_LOCK_KEY;
        int ret;
 
+       mutex_lock(&reg_lock_mutex);
+
        ldbg(__func__);
-       mutex_lock(&io_mutex);
-       ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
+
+       ret = wm8350_reg_write(wm8350, WM8350_SECURITY, WM8350_LOCK_KEY);
        if (ret)
                dev_err(wm8350->dev, "lock failed\n");
-       mutex_unlock(&io_mutex);
+
+       wm8350->unlocked = false;
+
+       mutex_unlock(&reg_lock_mutex);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(wm8350_reg_lock);
@@ -319,15 +168,20 @@ EXPORT_SYMBOL_GPL(wm8350_reg_lock);
  */
 int wm8350_reg_unlock(struct wm8350 *wm8350)
 {
-       u16 key = WM8350_UNLOCK_KEY;
        int ret;
 
+       mutex_lock(&reg_lock_mutex);
+
        ldbg(__func__);
-       mutex_lock(&io_mutex);
-       ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
+
+       ret = wm8350_reg_write(wm8350, WM8350_SECURITY, WM8350_UNLOCK_KEY);
        if (ret)
                dev_err(wm8350->dev, "unlock failed\n");
-       mutex_unlock(&io_mutex);
+
+       wm8350->unlocked = true;
+
+       mutex_unlock(&reg_lock_mutex);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(wm8350_reg_unlock);
@@ -394,146 +248,6 @@ static irqreturn_t wm8350_auxadc_irq(int irq, void *irq_data)
        return IRQ_HANDLED;
 }
 
-/*
- * Cache is always host endian.
- */
-static int wm8350_create_cache(struct wm8350 *wm8350, int type, int mode)
-{
-       int i, ret = 0;
-       u16 value;
-       const u16 *reg_map;
-
-       switch (type) {
-       case 0:
-               switch (mode) {
-#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
-               case 0:
-                       reg_map = wm8350_mode0_defaults;
-                       break;
-#endif
-#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
-               case 1:
-                       reg_map = wm8350_mode1_defaults;
-                       break;
-#endif
-#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
-               case 2:
-                       reg_map = wm8350_mode2_defaults;
-                       break;
-#endif
-#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
-               case 3:
-                       reg_map = wm8350_mode3_defaults;
-                       break;
-#endif
-               default:
-                       dev_err(wm8350->dev,
-                               "WM8350 configuration mode %d not supported\n",
-                               mode);
-                       return -EINVAL;
-               }
-               break;
-
-       case 1:
-               switch (mode) {
-#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_0
-               case 0:
-                       reg_map = wm8351_mode0_defaults;
-                       break;
-#endif
-#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_1
-               case 1:
-                       reg_map = wm8351_mode1_defaults;
-                       break;
-#endif
-#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_2
-               case 2:
-                       reg_map = wm8351_mode2_defaults;
-                       break;
-#endif
-#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_3
-               case 3:
-                       reg_map = wm8351_mode3_defaults;
-                       break;
-#endif
-               default:
-                       dev_err(wm8350->dev,
-                               "WM8351 configuration mode %d not supported\n",
-                               mode);
-                       return -EINVAL;
-               }
-               break;
-
-       case 2:
-               switch (mode) {
-#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0
-               case 0:
-                       reg_map = wm8352_mode0_defaults;
-                       break;
-#endif
-#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_1
-               case 1:
-                       reg_map = wm8352_mode1_defaults;
-                       break;
-#endif
-#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_2
-               case 2:
-                       reg_map = wm8352_mode2_defaults;
-                       break;
-#endif
-#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_3
-               case 3:
-                       reg_map = wm8352_mode3_defaults;
-                       break;
-#endif
-               default:
-                       dev_err(wm8350->dev,
-                               "WM8352 configuration mode %d not supported\n",
-                               mode);
-                       return -EINVAL;
-               }
-               break;
-
-       default:
-               dev_err(wm8350->dev,
-                       "WM835x configuration mode %d not supported\n",
-                       mode);
-               return -EINVAL;
-       }
-
-       wm8350->reg_cache =
-               kmalloc(sizeof(u16) * (WM8350_MAX_REGISTER + 1), GFP_KERNEL);
-       if (wm8350->reg_cache == NULL)
-               return -ENOMEM;
-
-       /* Read the initial cache state back from the device - this is
-        * a PMIC so the device many not be in a virgin state and we
-        * can't rely on the silicon values.
-        */
-       ret = regmap_raw_read(wm8350->regmap, 0, wm8350->reg_cache,
-                             sizeof(u16) * (WM8350_MAX_REGISTER + 1));
-       if (ret < 0) {
-               dev_err(wm8350->dev,
-                       "failed to read initial cache values\n");
-               goto out;
-       }
-
-       /* Mask out uncacheable/unreadable bits and the audio. */
-       for (i = 0; i < WM8350_MAX_REGISTER; i++) {
-               if (wm8350_reg_io_map[i].readable &&
-                   (i < WM8350_CLOCK_CONTROL_1 || i > WM8350_AIF_TEST)) {
-                       value = be16_to_cpu(wm8350->reg_cache[i]);
-                       value &= wm8350_reg_io_map[i].readable;
-                       wm8350->reg_cache[i] = value;
-               } else
-                       wm8350->reg_cache[i] = reg_map[i];
-       }
-
-out:
-       kfree(wm8350->reg_cache);
-       return ret;
-}
-
 /*
  * Register a client device.  This is non-fatal since there is no need to
  * fail the entire device init due to a single platform device failing.
@@ -681,18 +395,12 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
                goto err;
        }
 
-       ret = wm8350_create_cache(wm8350, mask_rev, mode);
-       if (ret < 0) {
-               dev_err(wm8350->dev, "Failed to create register cache\n");
-               return ret;
-       }
-
        mutex_init(&wm8350->auxadc_mutex);
        init_completion(&wm8350->auxadc_done);
 
        ret = wm8350_irq_init(wm8350, irq, pdata);
        if (ret < 0)
-               goto err_free;
+               goto err;
 
        if (wm8350->irq_base) {
                ret = request_threaded_irq(wm8350->irq_base +
@@ -730,8 +438,6 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
 
 err_irq:
        wm8350_irq_exit(wm8350);
-err_free:
-       kfree(wm8350->reg_cache);
 err:
        return ret;
 }
@@ -758,8 +464,6 @@ void wm8350_device_exit(struct wm8350 *wm8350)
                free_irq(wm8350->irq_base + WM8350_IRQ_AUXADC_DATARDY, wm8350);
 
        wm8350_irq_exit(wm8350);
-
-       kfree(wm8350->reg_cache);
 }
 EXPORT_SYMBOL_GPL(wm8350_device_exit);
 
index a68aceb4e48c880fbf7b79e64459762241eeaa29..2e57101c8d3dabfc395f2bf764bddc23a411bbe5 100644 (file)
 #include <linux/regmap.h>
 #include <linux/slab.h>
 
-static const struct regmap_config wm8350_regmap = {
-       .reg_bits = 8,
-       .val_bits = 16,
-};
-
 static int wm8350_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
index 9fd01bf63c510eafab2c1efc987728576aa54f5e..624ff90501cde3c5fdf1e79f026db8cfa321eb37 100644 (file)
@@ -432,11 +432,9 @@ static void wm8350_irq_sync_unlock(struct irq_data *data)
        for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
                /* If there's been a change in the mask write it back
                 * to the hardware. */
-               if (wm8350->irq_masks[i] !=
-                   wm8350->reg_cache[WM8350_INT_STATUS_1_MASK + i])
-                       WARN_ON(wm8350_reg_write(wm8350,
-                                        WM8350_INT_STATUS_1_MASK + i,
-                                                wm8350->irq_masks[i]));
+               WARN_ON(regmap_update_bits(wm8350->regmap,
+                                          WM8350_INT_STATUS_1_MASK + i,
+                                          0xffff, wm8350->irq_masks[i]));
        }
 
        mutex_unlock(&wm8350->irq_lock);
index e965139e5cd5ba116369eedd05b72435621b6796..9efc64750fb68d8a323f2a7241d99cf47d781b0f 100644 (file)
 
 #include <linux/mfd/wm8350/core.h>
 
-#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
-
-#undef WM8350_HAVE_CONFIG_MODE
-#define WM8350_HAVE_CONFIG_MODE
-
-const u16 wm8350_mode0_defaults[] = {
-       0x17FF,     /* R0   - Reset/ID */
-       0x1000,     /* R1   - ID */
-       0x0000,     /* R2 */
-       0x1002,     /* R3   - System Control 1 */
-       0x0004,     /* R4   - System Control 2 */
-       0x0000,     /* R5   - System Hibernate */
-       0x8A00,     /* R6   - Interface Control */
-       0x0000,     /* R7 */
-       0x8000,     /* R8   - Power mgmt (1) */
-       0x0000,     /* R9   - Power mgmt (2) */
-       0x0000,     /* R10  - Power mgmt (3) */
-       0x2000,     /* R11  - Power mgmt (4) */
-       0x0E00,     /* R12  - Power mgmt (5) */
-       0x0000,     /* R13  - Power mgmt (6) */
-       0x0000,     /* R14  - Power mgmt (7) */
-       0x0000,     /* R15 */
-       0x0000,     /* R16  - RTC Seconds/Minutes */
-       0x0100,     /* R17  - RTC Hours/Day */
-       0x0101,     /* R18  - RTC Date/Month */
-       0x1400,     /* R19  - RTC Year */
-       0x0000,     /* R20  - Alarm Seconds/Minutes */
-       0x0000,     /* R21  - Alarm Hours/Day */
-       0x0000,     /* R22  - Alarm Date/Month */
-       0x0320,     /* R23  - RTC Time Control */
-       0x0000,     /* R24  - System Interrupts */
-       0x0000,     /* R25  - Interrupt Status 1 */
-       0x0000,     /* R26  - Interrupt Status 2 */
-       0x0000,     /* R27  - Power Up Interrupt Status */
-       0x0000,     /* R28  - Under Voltage Interrupt status */
-       0x0000,     /* R29  - Over Current Interrupt status */
-       0x0000,     /* R30  - GPIO Interrupt Status */
-       0x0000,     /* R31  - Comparator Interrupt Status */
-       0x3FFF,     /* R32  - System Interrupts Mask */
-       0x0000,     /* R33  - Interrupt Status 1 Mask */
-       0x0000,     /* R34  - Interrupt Status 2 Mask */
-       0x0000,     /* R35  - Power Up Interrupt Status Mask */
-       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
-       0x0000,     /* R37  - Over Current Interrupt status Mask */
-       0x0000,     /* R38  - GPIO Interrupt Status Mask */
-       0x0000,     /* R39  - Comparator Interrupt Status Mask */
-       0x0040,     /* R40  - Clock Control 1 */
-       0x0000,     /* R41  - Clock Control 2 */
-       0x3B00,     /* R42  - FLL Control 1 */
-       0x7086,     /* R43  - FLL Control 2 */
-       0xC226,     /* R44  - FLL Control 3 */
-       0x0000,     /* R45  - FLL Control 4 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47 */
-       0x0000,     /* R48  - DAC Control */
-       0x0000,     /* R49 */
-       0x00C0,     /* R50  - DAC Digital Volume L */
-       0x00C0,     /* R51  - DAC Digital Volume R */
-       0x0000,     /* R52 */
-       0x0040,     /* R53  - DAC LR Rate */
-       0x0000,     /* R54  - DAC Clock Control */
-       0x0000,     /* R55 */
-       0x0000,     /* R56 */
-       0x0000,     /* R57 */
-       0x4000,     /* R58  - DAC Mute */
-       0x0000,     /* R59  - DAC Mute Volume */
-       0x0000,     /* R60  - DAC Side */
-       0x0000,     /* R61 */
-       0x0000,     /* R62 */
-       0x0000,     /* R63 */
-       0x8000,     /* R64  - ADC Control */
-       0x0000,     /* R65 */
-       0x00C0,     /* R66  - ADC Digital Volume L */
-       0x00C0,     /* R67  - ADC Digital Volume R */
-       0x0000,     /* R68  - ADC Divider */
-       0x0000,     /* R69 */
-       0x0040,     /* R70  - ADC LR Rate */
-       0x0000,     /* R71 */
-       0x0303,     /* R72  - Input Control */
-       0x0000,     /* R73  - IN3 Input Control */
-       0x0000,     /* R74  - Mic Bias Control */
-       0x0000,     /* R75 */
-       0x0000,     /* R76  - Output Control */
-       0x0000,     /* R77  - Jack Detect */
-       0x0000,     /* R78  - Anti Pop Control */
-       0x0000,     /* R79 */
-       0x0040,     /* R80  - Left Input Volume */
-       0x0040,     /* R81  - Right Input Volume */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87 */
-       0x0800,     /* R88  - Left Mixer Control */
-       0x1000,     /* R89  - Right Mixer Control */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92  - OUT3 Mixer Control */
-       0x0000,     /* R93  - OUT4 Mixer Control */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96  - Output Left Mixer Volume */
-       0x0000,     /* R97  - Output Right Mixer Volume */
-       0x0000,     /* R98  - Input Mixer Volume L */
-       0x0000,     /* R99  - Input Mixer Volume R */
-       0x0000,     /* R100 - Input Mixer Volume */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x00E4,     /* R104 - LOUT1 Volume */
-       0x00E4,     /* R105 - ROUT1 Volume */
-       0x00E4,     /* R106 - LOUT2 Volume */
-       0x02E4,     /* R107 - ROUT2 Volume */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 - BEEP Volume */
-       0x0A00,     /* R112 - AI Formating */
-       0x0000,     /* R113 - ADC DAC COMP */
-       0x0020,     /* R114 - AI ADC Control */
-       0x0020,     /* R115 - AI DAC Control */
-       0x0000,     /* R116 - AIF Test */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x1FFF,     /* R128 - GPIO Debounce */
-       0x0000,     /* R129 - GPIO Pin pull up Control */
-       0x03FC,     /* R130 - GPIO Pull down Control */
-       0x0000,     /* R131 - GPIO Interrupt Mode */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 - GPIO Control */
-       0x0FFC,     /* R134 - GPIO Configuration (i/o) */
-       0x0FFC,     /* R135 - GPIO Pin Polarity / Type */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x0013,     /* R140 - GPIO Function Select 1 */
-       0x0000,     /* R141 - GPIO Function Select 2 */
-       0x0000,     /* R142 - GPIO Function Select 3 */
-       0x0003,     /* R143 - GPIO Function Select 4 */
-       0x0000,     /* R144 - Digitiser Control (1) */
-       0x0002,     /* R145 - Digitiser Control (2) */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x7000,     /* R152 - AUX1 Readback */
-       0x7000,     /* R153 - AUX2 Readback */
-       0x7000,     /* R154 - AUX3 Readback */
-       0x7000,     /* R155 - AUX4 Readback */
-       0x0000,     /* R156 - USB Voltage Readback */
-       0x0000,     /* R157 - LINE Voltage Readback */
-       0x0000,     /* R158 - BATT Voltage Readback */
-       0x0000,     /* R159 - Chip Temp Readback */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 - Generic Comparator Control */
-       0x0000,     /* R164 - Generic comparator 1 */
-       0x0000,     /* R165 - Generic comparator 2 */
-       0x0000,     /* R166 - Generic comparator 3 */
-       0x0000,     /* R167 - Generic comparator 4 */
-       0xA00F,     /* R168 - Battery Charger Control 1 */
-       0x0B06,     /* R169 - Battery Charger Control 2 */
-       0x0000,     /* R170 - Battery Charger Control 3 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Current Sink Driver A */
-       0x0000,     /* R173 - CSA Flash control */
-       0x0000,     /* R174 - Current Sink Driver B */
-       0x0000,     /* R175 - CSB Flash control */
-       0x0000,     /* R176 - DCDC/LDO requested */
-       0x002D,     /* R177 - DCDC Active options */
-       0x0000,     /* R178 - DCDC Sleep options */
-       0x0025,     /* R179 - Power-check comparator */
-       0x000E,     /* R180 - DCDC1 Control */
-       0x0000,     /* R181 - DCDC1 Timeouts */
-       0x1006,     /* R182 - DCDC1 Low Power */
-       0x0018,     /* R183 - DCDC2 Control */
-       0x0000,     /* R184 - DCDC2 Timeouts */
-       0x0000,     /* R185 */
-       0x0000,     /* R186 - DCDC3 Control */
-       0x0000,     /* R187 - DCDC3 Timeouts */
-       0x0006,     /* R188 - DCDC3 Low Power */
-       0x0000,     /* R189 - DCDC4 Control */
-       0x0000,     /* R190 - DCDC4 Timeouts */
-       0x0006,     /* R191 - DCDC4 Low Power */
-       0x0008,     /* R192 - DCDC5 Control */
-       0x0000,     /* R193 - DCDC5 Timeouts */
-       0x0000,     /* R194 */
-       0x0000,     /* R195 - DCDC6 Control */
-       0x0000,     /* R196 - DCDC6 Timeouts */
-       0x0006,     /* R197 - DCDC6 Low Power */
-       0x0000,     /* R198 */
-       0x0003,     /* R199 - Limit Switch Control */
-       0x001C,     /* R200 - LDO1 Control */
-       0x0000,     /* R201 - LDO1 Timeouts */
-       0x001C,     /* R202 - LDO1 Low Power */
-       0x001B,     /* R203 - LDO2 Control */
-       0x0000,     /* R204 - LDO2 Timeouts */
-       0x001C,     /* R205 - LDO2 Low Power */
-       0x001B,     /* R206 - LDO3 Control */
-       0x0000,     /* R207 - LDO3 Timeouts */
-       0x001C,     /* R208 - LDO3 Low Power */
-       0x001B,     /* R209 - LDO4 Control */
-       0x0000,     /* R210 - LDO4 Timeouts */
-       0x001C,     /* R211 - LDO4 Low Power */
-       0x0000,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 - VCC_FAULT Masks */
-       0x001F,     /* R216 - Main Bandgap Control */
-       0x0000,     /* R217 - OSC Control */
-       0x9000,     /* R218 - RTC Tick Control */
-       0x0000,     /* R219 */
-       0x4000,     /* R220 - RAM BIST 1 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0000,     /* R223 */
-       0x0000,     /* R224 */
-       0x0000,     /* R225 - DCDC/LDO status */
-       0x0000,     /* R226 */
-       0x0000,     /* R227 */
-       0x0000,     /* R228 */
-       0x0000,     /* R229 */
-       0xE000,     /* R230 - GPIO Pin Status */
-       0x0000,     /* R231 */
-       0x0000,     /* R232 */
-       0x0000,     /* R233 */
-       0x0000,     /* R234 */
-       0x0000,     /* R235 */
-       0x0000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0000,     /* R238 */
-       0x0000,     /* R239 */
-       0x0000,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0000,     /* R243 */
-       0x0000,     /* R244 */
-       0x0000,     /* R245 */
-       0x0000,     /* R246 */
-       0x0000,     /* R247 */
-       0x0000,     /* R248 */
-       0x0000,     /* R249 */
-       0x0000,     /* R250 */
-       0x0000,     /* R251 */
-       0x0000,     /* R252 */
-       0x0000,     /* R253 */
-       0x0000,     /* R254 */
-       0x0000,     /* R255 */
-};
-#endif
-
-#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
-
-#undef WM8350_HAVE_CONFIG_MODE
-#define WM8350_HAVE_CONFIG_MODE
-
-const u16 wm8350_mode1_defaults[] = {
-       0x17FF,     /* R0   - Reset/ID */
-       0x1000,     /* R1   - ID */
-       0x0000,     /* R2 */
-       0x1002,     /* R3   - System Control 1 */
-       0x0014,     /* R4   - System Control 2 */
-       0x0000,     /* R5   - System Hibernate */
-       0x8A00,     /* R6   - Interface Control */
-       0x0000,     /* R7 */
-       0x8000,     /* R8   - Power mgmt (1) */
-       0x0000,     /* R9   - Power mgmt (2) */
-       0x0000,     /* R10  - Power mgmt (3) */
-       0x2000,     /* R11  - Power mgmt (4) */
-       0x0E00,     /* R12  - Power mgmt (5) */
-       0x0000,     /* R13  - Power mgmt (6) */
-       0x0000,     /* R14  - Power mgmt (7) */
-       0x0000,     /* R15 */
-       0x0000,     /* R16  - RTC Seconds/Minutes */
-       0x0100,     /* R17  - RTC Hours/Day */
-       0x0101,     /* R18  - RTC Date/Month */
-       0x1400,     /* R19  - RTC Year */
-       0x0000,     /* R20  - Alarm Seconds/Minutes */
-       0x0000,     /* R21  - Alarm Hours/Day */
-       0x0000,     /* R22  - Alarm Date/Month */
-       0x0320,     /* R23  - RTC Time Control */
-       0x0000,     /* R24  - System Interrupts */
-       0x0000,     /* R25  - Interrupt Status 1 */
-       0x0000,     /* R26  - Interrupt Status 2 */
-       0x0000,     /* R27  - Power Up Interrupt Status */
-       0x0000,     /* R28  - Under Voltage Interrupt status */
-       0x0000,     /* R29  - Over Current Interrupt status */
-       0x0000,     /* R30  - GPIO Interrupt Status */
-       0x0000,     /* R31  - Comparator Interrupt Status */
-       0x3FFF,     /* R32  - System Interrupts Mask */
-       0x0000,     /* R33  - Interrupt Status 1 Mask */
-       0x0000,     /* R34  - Interrupt Status 2 Mask */
-       0x0000,     /* R35  - Power Up Interrupt Status Mask */
-       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
-       0x0000,     /* R37  - Over Current Interrupt status Mask */
-       0x0000,     /* R38  - GPIO Interrupt Status Mask */
-       0x0000,     /* R39  - Comparator Interrupt Status Mask */
-       0x0040,     /* R40  - Clock Control 1 */
-       0x0000,     /* R41  - Clock Control 2 */
-       0x3B00,     /* R42  - FLL Control 1 */
-       0x7086,     /* R43  - FLL Control 2 */
-       0xC226,     /* R44  - FLL Control 3 */
-       0x0000,     /* R45  - FLL Control 4 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47 */
-       0x0000,     /* R48  - DAC Control */
-       0x0000,     /* R49 */
-       0x00C0,     /* R50  - DAC Digital Volume L */
-       0x00C0,     /* R51  - DAC Digital Volume R */
-       0x0000,     /* R52 */
-       0x0040,     /* R53  - DAC LR Rate */
-       0x0000,     /* R54  - DAC Clock Control */
-       0x0000,     /* R55 */
-       0x0000,     /* R56 */
-       0x0000,     /* R57 */
-       0x4000,     /* R58  - DAC Mute */
-       0x0000,     /* R59  - DAC Mute Volume */
-       0x0000,     /* R60  - DAC Side */
-       0x0000,     /* R61 */
-       0x0000,     /* R62 */
-       0x0000,     /* R63 */
-       0x8000,     /* R64  - ADC Control */
-       0x0000,     /* R65 */
-       0x00C0,     /* R66  - ADC Digital Volume L */
-       0x00C0,     /* R67  - ADC Digital Volume R */
-       0x0000,     /* R68  - ADC Divider */
-       0x0000,     /* R69 */
-       0x0040,     /* R70  - ADC LR Rate */
-       0x0000,     /* R71 */
-       0x0303,     /* R72  - Input Control */
-       0x0000,     /* R73  - IN3 Input Control */
-       0x0000,     /* R74  - Mic Bias Control */
-       0x0000,     /* R75 */
-       0x0000,     /* R76  - Output Control */
-       0x0000,     /* R77  - Jack Detect */
-       0x0000,     /* R78  - Anti Pop Control */
-       0x0000,     /* R79 */
-       0x0040,     /* R80  - Left Input Volume */
-       0x0040,     /* R81  - Right Input Volume */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87 */
-       0x0800,     /* R88  - Left Mixer Control */
-       0x1000,     /* R89  - Right Mixer Control */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92  - OUT3 Mixer Control */
-       0x0000,     /* R93  - OUT4 Mixer Control */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96  - Output Left Mixer Volume */
-       0x0000,     /* R97  - Output Right Mixer Volume */
-       0x0000,     /* R98  - Input Mixer Volume L */
-       0x0000,     /* R99  - Input Mixer Volume R */
-       0x0000,     /* R100 - Input Mixer Volume */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x00E4,     /* R104 - LOUT1 Volume */
-       0x00E4,     /* R105 - ROUT1 Volume */
-       0x00E4,     /* R106 - LOUT2 Volume */
-       0x02E4,     /* R107 - ROUT2 Volume */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 - BEEP Volume */
-       0x0A00,     /* R112 - AI Formating */
-       0x0000,     /* R113 - ADC DAC COMP */
-       0x0020,     /* R114 - AI ADC Control */
-       0x0020,     /* R115 - AI DAC Control */
-       0x0000,     /* R116 - AIF Test */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x1FFF,     /* R128 - GPIO Debounce */
-       0x0000,     /* R129 - GPIO Pin pull up Control */
-       0x03FC,     /* R130 - GPIO Pull down Control */
-       0x0000,     /* R131 - GPIO Interrupt Mode */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 - GPIO Control */
-       0x00FB,     /* R134 - GPIO Configuration (i/o) */
-       0x04FE,     /* R135 - GPIO Pin Polarity / Type */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x0312,     /* R140 - GPIO Function Select 1 */
-       0x1003,     /* R141 - GPIO Function Select 2 */
-       0x1331,     /* R142 - GPIO Function Select 3 */
-       0x0003,     /* R143 - GPIO Function Select 4 */
-       0x0000,     /* R144 - Digitiser Control (1) */
-       0x0002,     /* R145 - Digitiser Control (2) */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x7000,     /* R152 - AUX1 Readback */
-       0x7000,     /* R153 - AUX2 Readback */
-       0x7000,     /* R154 - AUX3 Readback */
-       0x7000,     /* R155 - AUX4 Readback */
-       0x0000,     /* R156 - USB Voltage Readback */
-       0x0000,     /* R157 - LINE Voltage Readback */
-       0x0000,     /* R158 - BATT Voltage Readback */
-       0x0000,     /* R159 - Chip Temp Readback */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 - Generic Comparator Control */
-       0x0000,     /* R164 - Generic comparator 1 */
-       0x0000,     /* R165 - Generic comparator 2 */
-       0x0000,     /* R166 - Generic comparator 3 */
-       0x0000,     /* R167 - Generic comparator 4 */
-       0xA00F,     /* R168 - Battery Charger Control 1 */
-       0x0B06,     /* R169 - Battery Charger Control 2 */
-       0x0000,     /* R170 - Battery Charger Control 3 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Current Sink Driver A */
-       0x0000,     /* R173 - CSA Flash control */
-       0x0000,     /* R174 - Current Sink Driver B */
-       0x0000,     /* R175 - CSB Flash control */
-       0x0000,     /* R176 - DCDC/LDO requested */
-       0x002D,     /* R177 - DCDC Active options */
-       0x0000,     /* R178 - DCDC Sleep options */
-       0x0025,     /* R179 - Power-check comparator */
-       0x0062,     /* R180 - DCDC1 Control */
-       0x0400,     /* R181 - DCDC1 Timeouts */
-       0x1006,     /* R182 - DCDC1 Low Power */
-       0x0018,     /* R183 - DCDC2 Control */
-       0x0000,     /* R184 - DCDC2 Timeouts */
-       0x0000,     /* R185 */
-       0x0026,     /* R186 - DCDC3 Control */
-       0x0400,     /* R187 - DCDC3 Timeouts */
-       0x0006,     /* R188 - DCDC3 Low Power */
-       0x0062,     /* R189 - DCDC4 Control */
-       0x0400,     /* R190 - DCDC4 Timeouts */
-       0x0006,     /* R191 - DCDC4 Low Power */
-       0x0008,     /* R192 - DCDC5 Control */
-       0x0000,     /* R193 - DCDC5 Timeouts */
-       0x0000,     /* R194 */
-       0x0026,     /* R195 - DCDC6 Control */
-       0x0800,     /* R196 - DCDC6 Timeouts */
-       0x0006,     /* R197 - DCDC6 Low Power */
-       0x0000,     /* R198 */
-       0x0003,     /* R199 - Limit Switch Control */
-       0x0006,     /* R200 - LDO1 Control */
-       0x0400,     /* R201 - LDO1 Timeouts */
-       0x001C,     /* R202 - LDO1 Low Power */
-       0x0006,     /* R203 - LDO2 Control */
-       0x0400,     /* R204 - LDO2 Timeouts */
-       0x001C,     /* R205 - LDO2 Low Power */
-       0x001B,     /* R206 - LDO3 Control */
-       0x0000,     /* R207 - LDO3 Timeouts */
-       0x001C,     /* R208 - LDO3 Low Power */
-       0x001B,     /* R209 - LDO4 Control */
-       0x0000,     /* R210 - LDO4 Timeouts */
-       0x001C,     /* R211 - LDO4 Low Power */
-       0x0000,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 - VCC_FAULT Masks */
-       0x001F,     /* R216 - Main Bandgap Control */
-       0x0000,     /* R217 - OSC Control */
-       0x9000,     /* R218 - RTC Tick Control */
-       0x0000,     /* R219 */
-       0x4000,     /* R220 - RAM BIST 1 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0000,     /* R223 */
-       0x0000,     /* R224 */
-       0x0000,     /* R225 - DCDC/LDO status */
-       0x0000,     /* R226 */
-       0x0000,     /* R227 */
-       0x0000,     /* R228 */
-       0x0000,     /* R229 */
-       0xE000,     /* R230 - GPIO Pin Status */
-       0x0000,     /* R231 */
-       0x0000,     /* R232 */
-       0x0000,     /* R233 */
-       0x0000,     /* R234 */
-       0x0000,     /* R235 */
-       0x0000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0000,     /* R238 */
-       0x0000,     /* R239 */
-       0x0000,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0000,     /* R243 */
-       0x0000,     /* R244 */
-       0x0000,     /* R245 */
-       0x0000,     /* R246 */
-       0x0000,     /* R247 */
-       0x0000,     /* R248 */
-       0x0000,     /* R249 */
-       0x0000,     /* R250 */
-       0x0000,     /* R251 */
-       0x0000,     /* R252 */
-       0x0000,     /* R253 */
-       0x0000,     /* R254 */
-       0x0000,     /* R255 */
-};
-#endif
-
-#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
-
-#undef WM8350_HAVE_CONFIG_MODE
-#define WM8350_HAVE_CONFIG_MODE
-
-const u16 wm8350_mode2_defaults[] = {
-       0x17FF,     /* R0   - Reset/ID */
-       0x1000,     /* R1   - ID */
-       0x0000,     /* R2 */
-       0x1002,     /* R3   - System Control 1 */
-       0x0014,     /* R4   - System Control 2 */
-       0x0000,     /* R5   - System Hibernate */
-       0x8A00,     /* R6   - Interface Control */
-       0x0000,     /* R7 */
-       0x8000,     /* R8   - Power mgmt (1) */
-       0x0000,     /* R9   - Power mgmt (2) */
-       0x0000,     /* R10  - Power mgmt (3) */
-       0x2000,     /* R11  - Power mgmt (4) */
-       0x0E00,     /* R12  - Power mgmt (5) */
-       0x0000,     /* R13  - Power mgmt (6) */
-       0x0000,     /* R14  - Power mgmt (7) */
-       0x0000,     /* R15 */
-       0x0000,     /* R16  - RTC Seconds/Minutes */
-       0x0100,     /* R17  - RTC Hours/Day */
-       0x0101,     /* R18  - RTC Date/Month */
-       0x1400,     /* R19  - RTC Year */
-       0x0000,     /* R20  - Alarm Seconds/Minutes */
-       0x0000,     /* R21  - Alarm Hours/Day */
-       0x0000,     /* R22  - Alarm Date/Month */
-       0x0320,     /* R23  - RTC Time Control */
-       0x0000,     /* R24  - System Interrupts */
-       0x0000,     /* R25  - Interrupt Status 1 */
-       0x0000,     /* R26  - Interrupt Status 2 */
-       0x0000,     /* R27  - Power Up Interrupt Status */
-       0x0000,     /* R28  - Under Voltage Interrupt status */
-       0x0000,     /* R29  - Over Current Interrupt status */
-       0x0000,     /* R30  - GPIO Interrupt Status */
-       0x0000,     /* R31  - Comparator Interrupt Status */
-       0x3FFF,     /* R32  - System Interrupts Mask */
-       0x0000,     /* R33  - Interrupt Status 1 Mask */
-       0x0000,     /* R34  - Interrupt Status 2 Mask */
-       0x0000,     /* R35  - Power Up Interrupt Status Mask */
-       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
-       0x0000,     /* R37  - Over Current Interrupt status Mask */
-       0x0000,     /* R38  - GPIO Interrupt Status Mask */
-       0x0000,     /* R39  - Comparator Interrupt Status Mask */
-       0x0040,     /* R40  - Clock Control 1 */
-       0x0000,     /* R41  - Clock Control 2 */
-       0x3B00,     /* R42  - FLL Control 1 */
-       0x7086,     /* R43  - FLL Control 2 */
-       0xC226,     /* R44  - FLL Control 3 */
-       0x0000,     /* R45  - FLL Control 4 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47 */
-       0x0000,     /* R48  - DAC Control */
-       0x0000,     /* R49 */
-       0x00C0,     /* R50  - DAC Digital Volume L */
-       0x00C0,     /* R51  - DAC Digital Volume R */
-       0x0000,     /* R52 */
-       0x0040,     /* R53  - DAC LR Rate */
-       0x0000,     /* R54  - DAC Clock Control */
-       0x0000,     /* R55 */
-       0x0000,     /* R56 */
-       0x0000,     /* R57 */
-       0x4000,     /* R58  - DAC Mute */
-       0x0000,     /* R59  - DAC Mute Volume */
-       0x0000,     /* R60  - DAC Side */
-       0x0000,     /* R61 */
-       0x0000,     /* R62 */
-       0x0000,     /* R63 */
-       0x8000,     /* R64  - ADC Control */
-       0x0000,     /* R65 */
-       0x00C0,     /* R66  - ADC Digital Volume L */
-       0x00C0,     /* R67  - ADC Digital Volume R */
-       0x0000,     /* R68  - ADC Divider */
-       0x0000,     /* R69 */
-       0x0040,     /* R70  - ADC LR Rate */
-       0x0000,     /* R71 */
-       0x0303,     /* R72  - Input Control */
-       0x0000,     /* R73  - IN3 Input Control */
-       0x0000,     /* R74  - Mic Bias Control */
-       0x0000,     /* R75 */
-       0x0000,     /* R76  - Output Control */
-       0x0000,     /* R77  - Jack Detect */
-       0x0000,     /* R78  - Anti Pop Control */
-       0x0000,     /* R79 */
-       0x0040,     /* R80  - Left Input Volume */
-       0x0040,     /* R81  - Right Input Volume */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87 */
-       0x0800,     /* R88  - Left Mixer Control */
-       0x1000,     /* R89  - Right Mixer Control */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92  - OUT3 Mixer Control */
-       0x0000,     /* R93  - OUT4 Mixer Control */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96  - Output Left Mixer Volume */
-       0x0000,     /* R97  - Output Right Mixer Volume */
-       0x0000,     /* R98  - Input Mixer Volume L */
-       0x0000,     /* R99  - Input Mixer Volume R */
-       0x0000,     /* R100 - Input Mixer Volume */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x00E4,     /* R104 - LOUT1 Volume */
-       0x00E4,     /* R105 - ROUT1 Volume */
-       0x00E4,     /* R106 - LOUT2 Volume */
-       0x02E4,     /* R107 - ROUT2 Volume */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 - BEEP Volume */
-       0x0A00,     /* R112 - AI Formating */
-       0x0000,     /* R113 - ADC DAC COMP */
-       0x0020,     /* R114 - AI ADC Control */
-       0x0020,     /* R115 - AI DAC Control */
-       0x0000,     /* R116 - AIF Test */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x1FFF,     /* R128 - GPIO Debounce */
-       0x0000,     /* R129 - GPIO Pin pull up Control */
-       0x03FC,     /* R130 - GPIO Pull down Control */
-       0x0000,     /* R131 - GPIO Interrupt Mode */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 - GPIO Control */
-       0x08FB,     /* R134 - GPIO Configuration (i/o) */
-       0x0CFE,     /* R135 - GPIO Pin Polarity / Type */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x0312,     /* R140 - GPIO Function Select 1 */
-       0x0003,     /* R141 - GPIO Function Select 2 */
-       0x2331,     /* R142 - GPIO Function Select 3 */
-       0x0003,     /* R143 - GPIO Function Select 4 */
-       0x0000,     /* R144 - Digitiser Control (1) */
-       0x0002,     /* R145 - Digitiser Control (2) */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x7000,     /* R152 - AUX1 Readback */
-       0x7000,     /* R153 - AUX2 Readback */
-       0x7000,     /* R154 - AUX3 Readback */
-       0x7000,     /* R155 - AUX4 Readback */
-       0x0000,     /* R156 - USB Voltage Readback */
-       0x0000,     /* R157 - LINE Voltage Readback */
-       0x0000,     /* R158 - BATT Voltage Readback */
-       0x0000,     /* R159 - Chip Temp Readback */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 - Generic Comparator Control */
-       0x0000,     /* R164 - Generic comparator 1 */
-       0x0000,     /* R165 - Generic comparator 2 */
-       0x0000,     /* R166 - Generic comparator 3 */
-       0x0000,     /* R167 - Generic comparator 4 */
-       0xA00F,     /* R168 - Battery Charger Control 1 */
-       0x0B06,     /* R169 - Battery Charger Control 2 */
-       0x0000,     /* R170 - Battery Charger Control 3 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Current Sink Driver A */
-       0x0000,     /* R173 - CSA Flash control */
-       0x0000,     /* R174 - Current Sink Driver B */
-       0x0000,     /* R175 - CSB Flash control */
-       0x0000,     /* R176 - DCDC/LDO requested */
-       0x002D,     /* R177 - DCDC Active options */
-       0x0000,     /* R178 - DCDC Sleep options */
-       0x0025,     /* R179 - Power-check comparator */
-       0x000E,     /* R180 - DCDC1 Control */
-       0x0400,     /* R181 - DCDC1 Timeouts */
-       0x1006,     /* R182 - DCDC1 Low Power */
-       0x0018,     /* R183 - DCDC2 Control */
-       0x0000,     /* R184 - DCDC2 Timeouts */
-       0x0000,     /* R185 */
-       0x002E,     /* R186 - DCDC3 Control */
-       0x0800,     /* R187 - DCDC3 Timeouts */
-       0x0006,     /* R188 - DCDC3 Low Power */
-       0x000E,     /* R189 - DCDC4 Control */
-       0x0800,     /* R190 - DCDC4 Timeouts */
-       0x0006,     /* R191 - DCDC4 Low Power */
-       0x0008,     /* R192 - DCDC5 Control */
-       0x0000,     /* R193 - DCDC5 Timeouts */
-       0x0000,     /* R194 */
-       0x0026,     /* R195 - DCDC6 Control */
-       0x0C00,     /* R196 - DCDC6 Timeouts */
-       0x0006,     /* R197 - DCDC6 Low Power */
-       0x0000,     /* R198 */
-       0x0003,     /* R199 - Limit Switch Control */
-       0x001A,     /* R200 - LDO1 Control */
-       0x0800,     /* R201 - LDO1 Timeouts */
-       0x001C,     /* R202 - LDO1 Low Power */
-       0x0010,     /* R203 - LDO2 Control */
-       0x0800,     /* R204 - LDO2 Timeouts */
-       0x001C,     /* R205 - LDO2 Low Power */
-       0x000A,     /* R206 - LDO3 Control */
-       0x0C00,     /* R207 - LDO3 Timeouts */
-       0x001C,     /* R208 - LDO3 Low Power */
-       0x001A,     /* R209 - LDO4 Control */
-       0x0800,     /* R210 - LDO4 Timeouts */
-       0x001C,     /* R211 - LDO4 Low Power */
-       0x0000,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 - VCC_FAULT Masks */
-       0x001F,     /* R216 - Main Bandgap Control */
-       0x0000,     /* R217 - OSC Control */
-       0x9000,     /* R218 - RTC Tick Control */
-       0x0000,     /* R219 */
-       0x4000,     /* R220 - RAM BIST 1 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0000,     /* R223 */
-       0x0000,     /* R224 */
-       0x0000,     /* R225 - DCDC/LDO status */
-       0x0000,     /* R226 */
-       0x0000,     /* R227 */
-       0x0000,     /* R228 */
-       0x0000,     /* R229 */
-       0xE000,     /* R230 - GPIO Pin Status */
-       0x0000,     /* R231 */
-       0x0000,     /* R232 */
-       0x0000,     /* R233 */
-       0x0000,     /* R234 */
-       0x0000,     /* R235 */
-       0x0000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0000,     /* R238 */
-       0x0000,     /* R239 */
-       0x0000,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0000,     /* R243 */
-       0x0000,     /* R244 */
-       0x0000,     /* R245 */
-       0x0000,     /* R246 */
-       0x0000,     /* R247 */
-       0x0000,     /* R248 */
-       0x0000,     /* R249 */
-       0x0000,     /* R250 */
-       0x0000,     /* R251 */
-       0x0000,     /* R252 */
-       0x0000,     /* R253 */
-       0x0000,     /* R254 */
-       0x0000,     /* R255 */
-};
-#endif
-
-#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
-
-#undef WM8350_HAVE_CONFIG_MODE
-#define WM8350_HAVE_CONFIG_MODE
-
-const u16 wm8350_mode3_defaults[] = {
-       0x17FF,     /* R0   - Reset/ID */
-       0x1000,     /* R1   - ID */
-       0x0000,     /* R2 */
-       0x1000,     /* R3   - System Control 1 */
-       0x0004,     /* R4   - System Control 2 */
-       0x0000,     /* R5   - System Hibernate */
-       0x8A00,     /* R6   - Interface Control */
-       0x0000,     /* R7 */
-       0x8000,     /* R8   - Power mgmt (1) */
-       0x0000,     /* R9   - Power mgmt (2) */
-       0x0000,     /* R10  - Power mgmt (3) */
-       0x2000,     /* R11  - Power mgmt (4) */
-       0x0E00,     /* R12  - Power mgmt (5) */
-       0x0000,     /* R13  - Power mgmt (6) */
-       0x0000,     /* R14  - Power mgmt (7) */
-       0x0000,     /* R15 */
-       0x0000,     /* R16  - RTC Seconds/Minutes */
-       0x0100,     /* R17  - RTC Hours/Day */
-       0x0101,     /* R18  - RTC Date/Month */
-       0x1400,     /* R19  - RTC Year */
-       0x0000,     /* R20  - Alarm Seconds/Minutes */
-       0x0000,     /* R21  - Alarm Hours/Day */
-       0x0000,     /* R22  - Alarm Date/Month */
-       0x0320,     /* R23  - RTC Time Control */
-       0x0000,     /* R24  - System Interrupts */
-       0x0000,     /* R25  - Interrupt Status 1 */
-       0x0000,     /* R26  - Interrupt Status 2 */
-       0x0000,     /* R27  - Power Up Interrupt Status */
-       0x0000,     /* R28  - Under Voltage Interrupt status */
-       0x0000,     /* R29  - Over Current Interrupt status */
-       0x0000,     /* R30  - GPIO Interrupt Status */
-       0x0000,     /* R31  - Comparator Interrupt Status */
-       0x3FFF,     /* R32  - System Interrupts Mask */
-       0x0000,     /* R33  - Interrupt Status 1 Mask */
-       0x0000,     /* R34  - Interrupt Status 2 Mask */
-       0x0000,     /* R35  - Power Up Interrupt Status Mask */
-       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
-       0x0000,     /* R37  - Over Current Interrupt status Mask */
-       0x0000,     /* R38  - GPIO Interrupt Status Mask */
-       0x0000,     /* R39  - Comparator Interrupt Status Mask */
-       0x0040,     /* R40  - Clock Control 1 */
-       0x0000,     /* R41  - Clock Control 2 */
-       0x3B00,     /* R42  - FLL Control 1 */
-       0x7086,     /* R43  - FLL Control 2 */
-       0xC226,     /* R44  - FLL Control 3 */
-       0x0000,     /* R45  - FLL Control 4 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47 */
-       0x0000,     /* R48  - DAC Control */
-       0x0000,     /* R49 */
-       0x00C0,     /* R50  - DAC Digital Volume L */
-       0x00C0,     /* R51  - DAC Digital Volume R */
-       0x0000,     /* R52 */
-       0x0040,     /* R53  - DAC LR Rate */
-       0x0000,     /* R54  - DAC Clock Control */
-       0x0000,     /* R55 */
-       0x0000,     /* R56 */
-       0x0000,     /* R57 */
-       0x4000,     /* R58  - DAC Mute */
-       0x0000,     /* R59  - DAC Mute Volume */
-       0x0000,     /* R60  - DAC Side */
-       0x0000,     /* R61 */
-       0x0000,     /* R62 */
-       0x0000,     /* R63 */
-       0x8000,     /* R64  - ADC Control */
-       0x0000,     /* R65 */
-       0x00C0,     /* R66  - ADC Digital Volume L */
-       0x00C0,     /* R67  - ADC Digital Volume R */
-       0x0000,     /* R68  - ADC Divider */
-       0x0000,     /* R69 */
-       0x0040,     /* R70  - ADC LR Rate */
-       0x0000,     /* R71 */
-       0x0303,     /* R72  - Input Control */
-       0x0000,     /* R73  - IN3 Input Control */
-       0x0000,     /* R74  - Mic Bias Control */
-       0x0000,     /* R75 */
-       0x0000,     /* R76  - Output Control */
-       0x0000,     /* R77  - Jack Detect */
-       0x0000,     /* R78  - Anti Pop Control */
-       0x0000,     /* R79 */
-       0x0040,     /* R80  - Left Input Volume */
-       0x0040,     /* R81  - Right Input Volume */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87 */
-       0x0800,     /* R88  - Left Mixer Control */
-       0x1000,     /* R89  - Right Mixer Control */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92  - OUT3 Mixer Control */
-       0x0000,     /* R93  - OUT4 Mixer Control */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96  - Output Left Mixer Volume */
-       0x0000,     /* R97  - Output Right Mixer Volume */
-       0x0000,     /* R98  - Input Mixer Volume L */
-       0x0000,     /* R99  - Input Mixer Volume R */
-       0x0000,     /* R100 - Input Mixer Volume */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x00E4,     /* R104 - LOUT1 Volume */
-       0x00E4,     /* R105 - ROUT1 Volume */
-       0x00E4,     /* R106 - LOUT2 Volume */
-       0x02E4,     /* R107 - ROUT2 Volume */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 - BEEP Volume */
-       0x0A00,     /* R112 - AI Formating */
-       0x0000,     /* R113 - ADC DAC COMP */
-       0x0020,     /* R114 - AI ADC Control */
-       0x0020,     /* R115 - AI DAC Control */
-       0x0000,     /* R116 - AIF Test */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x1FFF,     /* R128 - GPIO Debounce */
-       0x0000,     /* R129 - GPIO Pin pull up Control */
-       0x03FC,     /* R130 - GPIO Pull down Control */
-       0x0000,     /* R131 - GPIO Interrupt Mode */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 - GPIO Control */
-       0x0A7B,     /* R134 - GPIO Configuration (i/o) */
-       0x06FE,     /* R135 - GPIO Pin Polarity / Type */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x1312,     /* R140 - GPIO Function Select 1 */
-       0x1030,     /* R141 - GPIO Function Select 2 */
-       0x2231,     /* R142 - GPIO Function Select 3 */
-       0x0003,     /* R143 - GPIO Function Select 4 */
-       0x0000,     /* R144 - Digitiser Control (1) */
-       0x0002,     /* R145 - Digitiser Control (2) */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x7000,     /* R152 - AUX1 Readback */
-       0x7000,     /* R153 - AUX2 Readback */
-       0x7000,     /* R154 - AUX3 Readback */
-       0x7000,     /* R155 - AUX4 Readback */
-       0x0000,     /* R156 - USB Voltage Readback */
-       0x0000,     /* R157 - LINE Voltage Readback */
-       0x0000,     /* R158 - BATT Voltage Readback */
-       0x0000,     /* R159 - Chip Temp Readback */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 - Generic Comparator Control */
-       0x0000,     /* R164 - Generic comparator 1 */
-       0x0000,     /* R165 - Generic comparator 2 */
-       0x0000,     /* R166 - Generic comparator 3 */
-       0x0000,     /* R167 - Generic comparator 4 */
-       0xA00F,     /* R168 - Battery Charger Control 1 */
-       0x0B06,     /* R169 - Battery Charger Control 2 */
-       0x0000,     /* R170 - Battery Charger Control 3 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Current Sink Driver A */
-       0x0000,     /* R173 - CSA Flash control */
-       0x0000,     /* R174 - Current Sink Driver B */
-       0x0000,     /* R175 - CSB Flash control */
-       0x0000,     /* R176 - DCDC/LDO requested */
-       0x002D,     /* R177 - DCDC Active options */
-       0x0000,     /* R178 - DCDC Sleep options */
-       0x0025,     /* R179 - Power-check comparator */
-       0x000E,     /* R180 - DCDC1 Control */
-       0x0400,     /* R181 - DCDC1 Timeouts */
-       0x1006,     /* R182 - DCDC1 Low Power */
-       0x0018,     /* R183 - DCDC2 Control */
-       0x0000,     /* R184 - DCDC2 Timeouts */
-       0x0000,     /* R185 */
-       0x000E,     /* R186 - DCDC3 Control */
-       0x0400,     /* R187 - DCDC3 Timeouts */
-       0x0006,     /* R188 - DCDC3 Low Power */
-       0x0026,     /* R189 - DCDC4 Control */
-       0x0400,     /* R190 - DCDC4 Timeouts */
-       0x0006,     /* R191 - DCDC4 Low Power */
-       0x0008,     /* R192 - DCDC5 Control */
-       0x0000,     /* R193 - DCDC5 Timeouts */
-       0x0000,     /* R194 */
-       0x0026,     /* R195 - DCDC6 Control */
-       0x0400,     /* R196 - DCDC6 Timeouts */
-       0x0006,     /* R197 - DCDC6 Low Power */
-       0x0000,     /* R198 */
-       0x0003,     /* R199 - Limit Switch Control */
-       0x001C,     /* R200 - LDO1 Control */
-       0x0000,     /* R201 - LDO1 Timeouts */
-       0x001C,     /* R202 - LDO1 Low Power */
-       0x001C,     /* R203 - LDO2 Control */
-       0x0400,     /* R204 - LDO2 Timeouts */
-       0x001C,     /* R205 - LDO2 Low Power */
-       0x001C,     /* R206 - LDO3 Control */
-       0x0400,     /* R207 - LDO3 Timeouts */
-       0x001C,     /* R208 - LDO3 Low Power */
-       0x001F,     /* R209 - LDO4 Control */
-       0x0400,     /* R210 - LDO4 Timeouts */
-       0x001C,     /* R211 - LDO4 Low Power */
-       0x0000,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 - VCC_FAULT Masks */
-       0x001F,     /* R216 - Main Bandgap Control */
-       0x0000,     /* R217 - OSC Control */
-       0x9000,     /* R218 - RTC Tick Control */
-       0x0000,     /* R219 */
-       0x4000,     /* R220 - RAM BIST 1 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0000,     /* R223 */
-       0x0000,     /* R224 */
-       0x0000,     /* R225 - DCDC/LDO status */
-       0x0000,     /* R226 */
-       0x0000,     /* R227 */
-       0x0000,     /* R228 */
-       0x0000,     /* R229 */
-       0xE000,     /* R230 - GPIO Pin Status */
-       0x0000,     /* R231 */
-       0x0000,     /* R232 */
-       0x0000,     /* R233 */
-       0x0000,     /* R234 */
-       0x0000,     /* R235 */
-       0x0000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0000,     /* R238 */
-       0x0000,     /* R239 */
-       0x0000,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0000,     /* R243 */
-       0x0000,     /* R244 */
-       0x0000,     /* R245 */
-       0x0000,     /* R246 */
-       0x0000,     /* R247 */
-       0x0000,     /* R248 */
-       0x0000,     /* R249 */
-       0x0000,     /* R250 */
-       0x0000,     /* R251 */
-       0x0000,     /* R252 */
-       0x0000,     /* R253 */
-       0x0000,     /* R254 */
-       0x0000,     /* R255 */
-};
-#endif
-
-#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_0
-
-#undef WM8350_HAVE_CONFIG_MODE
-#define WM8350_HAVE_CONFIG_MODE
-
-const u16 wm8351_mode0_defaults[] = {
-       0x6143,     /* R0   - Reset/ID */
-       0x0000,     /* R1   - ID */
-       0x0001,     /* R2   - Revision */
-       0x1C02,     /* R3   - System Control 1 */
-       0x0004,     /* R4   - System Control 2 */
-       0x0000,     /* R5   - System Hibernate */
-       0x8A00,     /* R6   - Interface Control */
-       0x0000,     /* R7 */
-       0x8000,     /* R8   - Power mgmt (1) */
-       0x0000,     /* R9   - Power mgmt (2) */
-       0x0000,     /* R10  - Power mgmt (3) */
-       0x2000,     /* R11  - Power mgmt (4) */
-       0x0E00,     /* R12  - Power mgmt (5) */
-       0x0000,     /* R13  - Power mgmt (6) */
-       0x0000,     /* R14  - Power mgmt (7) */
-       0x0000,     /* R15 */
-       0x0000,     /* R16  - RTC Seconds/Minutes */
-       0x0100,     /* R17  - RTC Hours/Day */
-       0x0101,     /* R18  - RTC Date/Month */
-       0x1400,     /* R19  - RTC Year */
-       0x0000,     /* R20  - Alarm Seconds/Minutes */
-       0x0000,     /* R21  - Alarm Hours/Day */
-       0x0000,     /* R22  - Alarm Date/Month */
-       0x0320,     /* R23  - RTC Time Control */
-       0x0000,     /* R24  - System Interrupts */
-       0x0000,     /* R25  - Interrupt Status 1 */
-       0x0000,     /* R26  - Interrupt Status 2 */
-       0x0000,     /* R27 */
-       0x0000,     /* R28  - Under Voltage Interrupt status */
-       0x0000,     /* R29  - Over Current Interrupt status */
-       0x0000,     /* R30  - GPIO Interrupt Status */
-       0x0000,     /* R31  - Comparator Interrupt Status */
-       0x3FFF,     /* R32  - System Interrupts Mask */
-       0x0000,     /* R33  - Interrupt Status 1 Mask */
-       0x0000,     /* R34  - Interrupt Status 2 Mask */
-       0x0000,     /* R35 */
-       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
-       0x0000,     /* R37  - Over Current Interrupt status Mask */
-       0x0000,     /* R38  - GPIO Interrupt Status Mask */
-       0x0000,     /* R39  - Comparator Interrupt Status Mask */
-       0x0040,     /* R40  - Clock Control 1 */
-       0x0000,     /* R41  - Clock Control 2 */
-       0x3A00,     /* R42  - FLL Control 1 */
-       0x7086,     /* R43  - FLL Control 2 */
-       0xC226,     /* R44  - FLL Control 3 */
-       0x0000,     /* R45  - FLL Control 4 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47 */
-       0x0000,     /* R48  - DAC Control */
-       0x0000,     /* R49 */
-       0x00C0,     /* R50  - DAC Digital Volume L */
-       0x00C0,     /* R51  - DAC Digital Volume R */
-       0x0000,     /* R52 */
-       0x0040,     /* R53  - DAC LR Rate */
-       0x0000,     /* R54  - DAC Clock Control */
-       0x0000,     /* R55 */
-       0x0000,     /* R56 */
-       0x0000,     /* R57 */
-       0x4000,     /* R58  - DAC Mute */
-       0x0000,     /* R59  - DAC Mute Volume */
-       0x0000,     /* R60  - DAC Side */
-       0x0000,     /* R61 */
-       0x0000,     /* R62 */
-       0x0000,     /* R63 */
-       0x8000,     /* R64  - ADC Control */
-       0x0000,     /* R65 */
-       0x00C0,     /* R66  - ADC Digital Volume L */
-       0x00C0,     /* R67  - ADC Digital Volume R */
-       0x0000,     /* R68  - ADC Divider */
-       0x0000,     /* R69 */
-       0x0040,     /* R70  - ADC LR Rate */
-       0x0000,     /* R71 */
-       0x0303,     /* R72  - Input Control */
-       0x0000,     /* R73  - IN3 Input Control */
-       0x0000,     /* R74  - Mic Bias Control */
-       0x0000,     /* R75 */
-       0x0000,     /* R76  - Output Control */
-       0x0000,     /* R77  - Jack Detect */
-       0x0000,     /* R78  - Anti Pop Control */
-       0x0000,     /* R79 */
-       0x0040,     /* R80  - Left Input Volume */
-       0x0040,     /* R81  - Right Input Volume */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87 */
-       0x0800,     /* R88  - Left Mixer Control */
-       0x1000,     /* R89  - Right Mixer Control */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92  - OUT3 Mixer Control */
-       0x0000,     /* R93  - OUT4 Mixer Control */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96  - Output Left Mixer Volume */
-       0x0000,     /* R97  - Output Right Mixer Volume */
-       0x0000,     /* R98  - Input Mixer Volume L */
-       0x0000,     /* R99  - Input Mixer Volume R */
-       0x0000,     /* R100 - Input Mixer Volume */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x00E4,     /* R104 - OUT1L Volume */
-       0x00E4,     /* R105 - OUT1R Volume */
-       0x00E4,     /* R106 - OUT2L Volume */
-       0x02E4,     /* R107 - OUT2R Volume */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 - BEEP Volume */
-       0x0A00,     /* R112 - AI Formating */
-       0x0000,     /* R113 - ADC DAC COMP */
-       0x0020,     /* R114 - AI ADC Control */
-       0x0020,     /* R115 - AI DAC Control */
-       0x0000,     /* R116 */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x1FFF,     /* R128 - GPIO Debounce */
-       0x0000,     /* R129 - GPIO Pin pull up Control */
-       0x0000,     /* R130 - GPIO Pull down Control */
-       0x0000,     /* R131 - GPIO Interrupt Mode */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 - GPIO Control */
-       0x0FFC,     /* R134 - GPIO Configuration (i/o) */
-       0x0FFC,     /* R135 - GPIO Pin Polarity / Type */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x0013,     /* R140 - GPIO Function Select 1 */
-       0x0000,     /* R141 - GPIO Function Select 2 */
-       0x0000,     /* R142 - GPIO Function Select 3 */
-       0x0003,     /* R143 - GPIO Function Select 4 */
-       0x0000,     /* R144 - Digitiser Control (1) */
-       0x0002,     /* R145 - Digitiser Control (2) */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x7000,     /* R152 - AUX1 Readback */
-       0x7000,     /* R153 - AUX2 Readback */
-       0x7000,     /* R154 - AUX3 Readback */
-       0x7000,     /* R155 - AUX4 Readback */
-       0x0000,     /* R156 - USB Voltage Readback */
-       0x0000,     /* R157 - LINE Voltage Readback */
-       0x0000,     /* R158 - BATT Voltage Readback */
-       0x0000,     /* R159 - Chip Temp Readback */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 - Generic Comparator Control */
-       0x0000,     /* R164 - Generic comparator 1 */
-       0x0000,     /* R165 - Generic comparator 2 */
-       0x0000,     /* R166 - Generic comparator 3 */
-       0x0000,     /* R167 - Generic comparator 4 */
-       0xA00F,     /* R168 - Battery Charger Control 1 */
-       0x0B06,     /* R169 - Battery Charger Control 2 */
-       0x0000,     /* R170 - Battery Charger Control 3 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Current Sink Driver A */
-       0x0000,     /* R173 - CSA Flash control */
-       0x0000,     /* R174 */
-       0x0000,     /* R175 */
-       0x0000,     /* R176 - DCDC/LDO requested */
-       0x032D,     /* R177 - DCDC Active options */
-       0x0000,     /* R178 - DCDC Sleep options */
-       0x0025,     /* R179 - Power-check comparator */
-       0x000E,     /* R180 - DCDC1 Control */
-       0x0000,     /* R181 - DCDC1 Timeouts */
-       0x1006,     /* R182 - DCDC1 Low Power */
-       0x0018,     /* R183 - DCDC2 Control */
-       0x0000,     /* R184 - DCDC2 Timeouts */
-       0x0000,     /* R185 */
-       0x0000,     /* R186 - DCDC3 Control */
-       0x0000,     /* R187 - DCDC3 Timeouts */
-       0x0006,     /* R188 - DCDC3 Low Power */
-       0x0000,     /* R189 - DCDC4 Control */
-       0x0000,     /* R190 - DCDC4 Timeouts */
-       0x0006,     /* R191 - DCDC4 Low Power */
-       0x0008,     /* R192 */
-       0x0000,     /* R193 */
-       0x0000,     /* R194 */
-       0x0000,     /* R195 */
-       0x0000,     /* R196 */
-       0x0006,     /* R197 */
-       0x0000,     /* R198 */
-       0x0003,     /* R199 - Limit Switch Control */
-       0x001C,     /* R200 - LDO1 Control */
-       0x0000,     /* R201 - LDO1 Timeouts */
-       0x001C,     /* R202 - LDO1 Low Power */
-       0x001B,     /* R203 - LDO2 Control */
-       0x0000,     /* R204 - LDO2 Timeouts */
-       0x001C,     /* R205 - LDO2 Low Power */
-       0x001B,     /* R206 - LDO3 Control */
-       0x0000,     /* R207 - LDO3 Timeouts */
-       0x001C,     /* R208 - LDO3 Low Power */
-       0x001B,     /* R209 - LDO4 Control */
-       0x0000,     /* R210 - LDO4 Timeouts */
-       0x001C,     /* R211 - LDO4 Low Power */
-       0x0000,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 - VCC_FAULT Masks */
-       0x001F,     /* R216 - Main Bandgap Control */
-       0x0000,     /* R217 - OSC Control */
-       0x9000,     /* R218 - RTC Tick Control */
-       0x0000,     /* R219 - Security1 */
-       0x4000,     /* R220 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0000,     /* R223 */
-       0x0000,     /* R224 - Signal overrides */
-       0x0000,     /* R225 - DCDC/LDO status */
-       0x0000,     /* R226 - Charger Overides/status */
-       0x0000,     /* R227 - misc overrides */
-       0x0000,     /* R228 - Supply overrides/status 1 */
-       0x0000,     /* R229 - Supply overrides/status 2 */
-       0xE000,     /* R230 - GPIO Pin Status */
-       0x0000,     /* R231 - comparotor overrides */
-       0x0000,     /* R232 */
-       0x0000,     /* R233 - State Machine status */
-       0x1200,     /* R234 - FLL Test 1 */
-       0x0000,     /* R235 */
-       0x8000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0000,     /* R238 */
-       0x0000,     /* R239 */
-       0x0003,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0004,     /* R243 */
-       0x0300,     /* R244 */
-       0x0000,     /* R245 */
-       0x0200,     /* R246 */
-       0x0000,     /* R247 */
-       0x1000,     /* R248 - DCDC1 Test Controls */
-       0x1000,     /* R249 */
-       0x1000,     /* R250 - DCDC3 Test Controls */
-       0x1000,     /* R251 - DCDC4 Test Controls */
-};
-#endif
-
-#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_1
-
-#undef WM8350_HAVE_CONFIG_MODE
-#define WM8350_HAVE_CONFIG_MODE
-
-const u16 wm8351_mode1_defaults[] = {
-       0x6143,     /* R0   - Reset/ID */
-       0x0000,     /* R1   - ID */
-       0x0001,     /* R2   - Revision */
-       0x1C02,     /* R3   - System Control 1 */
-       0x0204,     /* R4   - System Control 2 */
-       0x0000,     /* R5   - System Hibernate */
-       0x8A00,     /* R6   - Interface Control */
-       0x0000,     /* R7 */
-       0x8000,     /* R8   - Power mgmt (1) */
-       0x0000,     /* R9   - Power mgmt (2) */
-       0x0000,     /* R10  - Power mgmt (3) */
-       0x2000,     /* R11  - Power mgmt (4) */
-       0x0E00,     /* R12  - Power mgmt (5) */
-       0x0000,     /* R13  - Power mgmt (6) */
-       0x0000,     /* R14  - Power mgmt (7) */
-       0x0000,     /* R15 */
-       0x0000,     /* R16  - RTC Seconds/Minutes */
-       0x0100,     /* R17  - RTC Hours/Day */
-       0x0101,     /* R18  - RTC Date/Month */
-       0x1400,     /* R19  - RTC Year */
-       0x0000,     /* R20  - Alarm Seconds/Minutes */
-       0x0000,     /* R21  - Alarm Hours/Day */
-       0x0000,     /* R22  - Alarm Date/Month */
-       0x0320,     /* R23  - RTC Time Control */
-       0x0000,     /* R24  - System Interrupts */
-       0x0000,     /* R25  - Interrupt Status 1 */
-       0x0000,     /* R26  - Interrupt Status 2 */
-       0x0000,     /* R27 */
-       0x0000,     /* R28  - Under Voltage Interrupt status */
-       0x0000,     /* R29  - Over Current Interrupt status */
-       0x0000,     /* R30  - GPIO Interrupt Status */
-       0x0000,     /* R31  - Comparator Interrupt Status */
-       0x3FFF,     /* R32  - System Interrupts Mask */
-       0x0000,     /* R33  - Interrupt Status 1 Mask */
-       0x0000,     /* R34  - Interrupt Status 2 Mask */
-       0x0000,     /* R35 */
-       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
-       0x0000,     /* R37  - Over Current Interrupt status Mask */
-       0x0000,     /* R38  - GPIO Interrupt Status Mask */
-       0x0000,     /* R39  - Comparator Interrupt Status Mask */
-       0x0040,     /* R40  - Clock Control 1 */
-       0x0000,     /* R41  - Clock Control 2 */
-       0x3A00,     /* R42  - FLL Control 1 */
-       0x7086,     /* R43  - FLL Control 2 */
-       0xC226,     /* R44  - FLL Control 3 */
-       0x0000,     /* R45  - FLL Control 4 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47 */
-       0x0000,     /* R48  - DAC Control */
-       0x0000,     /* R49 */
-       0x00C0,     /* R50  - DAC Digital Volume L */
-       0x00C0,     /* R51  - DAC Digital Volume R */
-       0x0000,     /* R52 */
-       0x0040,     /* R53  - DAC LR Rate */
-       0x0000,     /* R54  - DAC Clock Control */
-       0x0000,     /* R55 */
-       0x0000,     /* R56 */
-       0x0000,     /* R57 */
-       0x4000,     /* R58  - DAC Mute */
-       0x0000,     /* R59  - DAC Mute Volume */
-       0x0000,     /* R60  - DAC Side */
-       0x0000,     /* R61 */
-       0x0000,     /* R62 */
-       0x0000,     /* R63 */
-       0x8000,     /* R64  - ADC Control */
-       0x0000,     /* R65 */
-       0x00C0,     /* R66  - ADC Digital Volume L */
-       0x00C0,     /* R67  - ADC Digital Volume R */
-       0x0000,     /* R68  - ADC Divider */
-       0x0000,     /* R69 */
-       0x0040,     /* R70  - ADC LR Rate */
-       0x0000,     /* R71 */
-       0x0303,     /* R72  - Input Control */
-       0x0000,     /* R73  - IN3 Input Control */
-       0x0000,     /* R74  - Mic Bias Control */
-       0x0000,     /* R75 */
-       0x0000,     /* R76  - Output Control */
-       0x0000,     /* R77  - Jack Detect */
-       0x0000,     /* R78  - Anti Pop Control */
-       0x0000,     /* R79 */
-       0x0040,     /* R80  - Left Input Volume */
-       0x0040,     /* R81  - Right Input Volume */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87 */
-       0x0800,     /* R88  - Left Mixer Control */
-       0x1000,     /* R89  - Right Mixer Control */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92  - OUT3 Mixer Control */
-       0x0000,     /* R93  - OUT4 Mixer Control */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96  - Output Left Mixer Volume */
-       0x0000,     /* R97  - Output Right Mixer Volume */
-       0x0000,     /* R98  - Input Mixer Volume L */
-       0x0000,     /* R99  - Input Mixer Volume R */
-       0x0000,     /* R100 - Input Mixer Volume */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x00E4,     /* R104 - OUT1L Volume */
-       0x00E4,     /* R105 - OUT1R Volume */
-       0x00E4,     /* R106 - OUT2L Volume */
-       0x02E4,     /* R107 - OUT2R Volume */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 - BEEP Volume */
-       0x0A00,     /* R112 - AI Formating */
-       0x0000,     /* R113 - ADC DAC COMP */
-       0x0020,     /* R114 - AI ADC Control */
-       0x0020,     /* R115 - AI DAC Control */
-       0x0000,     /* R116 */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x1FFF,     /* R128 - GPIO Debounce */
-       0x0000,     /* R129 - GPIO Pin pull up Control */
-       0x0000,     /* R130 - GPIO Pull down Control */
-       0x0000,     /* R131 - GPIO Interrupt Mode */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 - GPIO Control */
-       0x0CFB,     /* R134 - GPIO Configuration (i/o) */
-       0x0C1F,     /* R135 - GPIO Pin Polarity / Type */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x0300,     /* R140 - GPIO Function Select 1 */
-       0x1110,     /* R141 - GPIO Function Select 2 */
-       0x0013,     /* R142 - GPIO Function Select 3 */
-       0x0003,     /* R143 - GPIO Function Select 4 */
-       0x0000,     /* R144 - Digitiser Control (1) */
-       0x0002,     /* R145 - Digitiser Control (2) */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x7000,     /* R152 - AUX1 Readback */
-       0x7000,     /* R153 - AUX2 Readback */
-       0x7000,     /* R154 - AUX3 Readback */
-       0x7000,     /* R155 - AUX4 Readback */
-       0x0000,     /* R156 - USB Voltage Readback */
-       0x0000,     /* R157 - LINE Voltage Readback */
-       0x0000,     /* R158 - BATT Voltage Readback */
-       0x0000,     /* R159 - Chip Temp Readback */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 - Generic Comparator Control */
-       0x0000,     /* R164 - Generic comparator 1 */
-       0x0000,     /* R165 - Generic comparator 2 */
-       0x0000,     /* R166 - Generic comparator 3 */
-       0x0000,     /* R167 - Generic comparator 4 */
-       0xA00F,     /* R168 - Battery Charger Control 1 */
-       0x0B06,     /* R169 - Battery Charger Control 2 */
-       0x0000,     /* R170 - Battery Charger Control 3 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Current Sink Driver A */
-       0x0000,     /* R173 - CSA Flash control */
-       0x0000,     /* R174 */
-       0x0000,     /* R175 */
-       0x0000,     /* R176 - DCDC/LDO requested */
-       0x032D,     /* R177 - DCDC Active options */
-       0x0000,     /* R178 - DCDC Sleep options */
-       0x0025,     /* R179 - Power-check comparator */
-       0x000E,     /* R180 - DCDC1 Control */
-       0x0C00,     /* R181 - DCDC1 Timeouts */
-       0x1006,     /* R182 - DCDC1 Low Power */
-       0x0018,     /* R183 - DCDC2 Control */
-       0x0000,     /* R184 - DCDC2 Timeouts */
-       0x0000,     /* R185 */
-       0x0026,     /* R186 - DCDC3 Control */
-       0x0400,     /* R187 - DCDC3 Timeouts */
-       0x0006,     /* R188 - DCDC3 Low Power */
-       0x0062,     /* R189 - DCDC4 Control */
-       0x0800,     /* R190 - DCDC4 Timeouts */
-       0x0006,     /* R191 - DCDC4 Low Power */
-       0x0008,     /* R192 */
-       0x0000,     /* R193 */
-       0x0000,     /* R194 */
-       0x000A,     /* R195 */
-       0x1000,     /* R196 */
-       0x0006,     /* R197 */
-       0x0000,     /* R198 */
-       0x0003,     /* R199 - Limit Switch Control */
-       0x0006,     /* R200 - LDO1 Control */
-       0x0000,     /* R201 - LDO1 Timeouts */
-       0x001C,     /* R202 - LDO1 Low Power */
-       0x0010,     /* R203 - LDO2 Control */
-       0x0C00,     /* R204 - LDO2 Timeouts */
-       0x001C,     /* R205 - LDO2 Low Power */
-       0x001F,     /* R206 - LDO3 Control */
-       0x0800,     /* R207 - LDO3 Timeouts */
-       0x001C,     /* R208 - LDO3 Low Power */
-       0x000A,     /* R209 - LDO4 Control */
-       0x0800,     /* R210 - LDO4 Timeouts */
-       0x001C,     /* R211 - LDO4 Low Power */
-       0x0000,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 - VCC_FAULT Masks */
-       0x001F,     /* R216 - Main Bandgap Control */
-       0x0000,     /* R217 - OSC Control */
-       0x9000,     /* R218 - RTC Tick Control */
-       0x0000,     /* R219 - Security1 */
-       0x4000,     /* R220 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0000,     /* R223 */
-       0x0000,     /* R224 - Signal overrides */
-       0x0000,     /* R225 - DCDC/LDO status */
-       0x0000,     /* R226 - Charger Overides/status */
-       0x0000,     /* R227 - misc overrides */
-       0x0000,     /* R228 - Supply overrides/status 1 */
-       0x0000,     /* R229 - Supply overrides/status 2 */
-       0xE000,     /* R230 - GPIO Pin Status */
-       0x0000,     /* R231 - comparotor overrides */
-       0x0000,     /* R232 */
-       0x0000,     /* R233 - State Machine status */
-       0x1200,     /* R234 - FLL Test 1 */
-       0x0000,     /* R235 */
-       0x8000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0000,     /* R238 */
-       0x0000,     /* R239 */
-       0x0003,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0004,     /* R243 */
-       0x0300,     /* R244 */
-       0x0000,     /* R245 */
-       0x0200,     /* R246 */
-       0x1000,     /* R247 */
-       0x1000,     /* R248 - DCDC1 Test Controls */
-       0x1000,     /* R249 */
-       0x1000,     /* R250 - DCDC3 Test Controls */
-       0x1000,     /* R251 - DCDC4 Test Controls */
-};
-#endif
-
-#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_2
-
-#undef WM8350_HAVE_CONFIG_MODE
-#define WM8350_HAVE_CONFIG_MODE
-
-const u16 wm8351_mode2_defaults[] = {
-       0x6143,     /* R0   - Reset/ID */
-       0x0000,     /* R1   - ID */
-       0x0001,     /* R2   - Revision */
-       0x1C02,     /* R3   - System Control 1 */
-       0x0214,     /* R4   - System Control 2 */
-       0x0000,     /* R5   - System Hibernate */
-       0x8A00,     /* R6   - Interface Control */
-       0x0000,     /* R7 */
-       0x8000,     /* R8   - Power mgmt (1) */
-       0x0000,     /* R9   - Power mgmt (2) */
-       0x0000,     /* R10  - Power mgmt (3) */
-       0x2000,     /* R11  - Power mgmt (4) */
-       0x0E00,     /* R12  - Power mgmt (5) */
-       0x0000,     /* R13  - Power mgmt (6) */
-       0x0000,     /* R14  - Power mgmt (7) */
-       0x0000,     /* R15 */
-       0x0000,     /* R16  - RTC Seconds/Minutes */
-       0x0100,     /* R17  - RTC Hours/Day */
-       0x0101,     /* R18  - RTC Date/Month */
-       0x1400,     /* R19  - RTC Year */
-       0x0000,     /* R20  - Alarm Seconds/Minutes */
-       0x0000,     /* R21  - Alarm Hours/Day */
-       0x0000,     /* R22  - Alarm Date/Month */
-       0x0320,     /* R23  - RTC Time Control */
-       0x0000,     /* R24  - System Interrupts */
-       0x0000,     /* R25  - Interrupt Status 1 */
-       0x0000,     /* R26  - Interrupt Status 2 */
-       0x0000,     /* R27 */
-       0x0000,     /* R28  - Under Voltage Interrupt status */
-       0x0000,     /* R29  - Over Current Interrupt status */
-       0x0000,     /* R30  - GPIO Interrupt Status */
-       0x0000,     /* R31  - Comparator Interrupt Status */
-       0x3FFF,     /* R32  - System Interrupts Mask */
-       0x0000,     /* R33  - Interrupt Status 1 Mask */
-       0x0000,     /* R34  - Interrupt Status 2 Mask */
-       0x0000,     /* R35 */
-       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
-       0x0000,     /* R37  - Over Current Interrupt status Mask */
-       0x0000,     /* R38  - GPIO Interrupt Status Mask */
-       0x0000,     /* R39  - Comparator Interrupt Status Mask */
-       0x0040,     /* R40  - Clock Control 1 */
-       0x0000,     /* R41  - Clock Control 2 */
-       0x3A00,     /* R42  - FLL Control 1 */
-       0x7086,     /* R43  - FLL Control 2 */
-       0xC226,     /* R44  - FLL Control 3 */
-       0x0000,     /* R45  - FLL Control 4 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47 */
-       0x0000,     /* R48  - DAC Control */
-       0x0000,     /* R49 */
-       0x00C0,     /* R50  - DAC Digital Volume L */
-       0x00C0,     /* R51  - DAC Digital Volume R */
-       0x0000,     /* R52 */
-       0x0040,     /* R53  - DAC LR Rate */
-       0x0000,     /* R54  - DAC Clock Control */
-       0x0000,     /* R55 */
-       0x0000,     /* R56 */
-       0x0000,     /* R57 */
-       0x4000,     /* R58  - DAC Mute */
-       0x0000,     /* R59  - DAC Mute Volume */
-       0x0000,     /* R60  - DAC Side */
-       0x0000,     /* R61 */
-       0x0000,     /* R62 */
-       0x0000,     /* R63 */
-       0x8000,     /* R64  - ADC Control */
-       0x0000,     /* R65 */
-       0x00C0,     /* R66  - ADC Digital Volume L */
-       0x00C0,     /* R67  - ADC Digital Volume R */
-       0x0000,     /* R68  - ADC Divider */
-       0x0000,     /* R69 */
-       0x0040,     /* R70  - ADC LR Rate */
-       0x0000,     /* R71 */
-       0x0303,     /* R72  - Input Control */
-       0x0000,     /* R73  - IN3 Input Control */
-       0x0000,     /* R74  - Mic Bias Control */
-       0x0000,     /* R75 */
-       0x0000,     /* R76  - Output Control */
-       0x0000,     /* R77  - Jack Detect */
-       0x0000,     /* R78  - Anti Pop Control */
-       0x0000,     /* R79 */
-       0x0040,     /* R80  - Left Input Volume */
-       0x0040,     /* R81  - Right Input Volume */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87 */
-       0x0800,     /* R88  - Left Mixer Control */
-       0x1000,     /* R89  - Right Mixer Control */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92  - OUT3 Mixer Control */
-       0x0000,     /* R93  - OUT4 Mixer Control */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96  - Output Left Mixer Volume */
-       0x0000,     /* R97  - Output Right Mixer Volume */
-       0x0000,     /* R98  - Input Mixer Volume L */
-       0x0000,     /* R99  - Input Mixer Volume R */
-       0x0000,     /* R100 - Input Mixer Volume */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x00E4,     /* R104 - OUT1L Volume */
-       0x00E4,     /* R105 - OUT1R Volume */
-       0x00E4,     /* R106 - OUT2L Volume */
-       0x02E4,     /* R107 - OUT2R Volume */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 - BEEP Volume */
-       0x0A00,     /* R112 - AI Formating */
-       0x0000,     /* R113 - ADC DAC COMP */
-       0x0020,     /* R114 - AI ADC Control */
-       0x0020,     /* R115 - AI DAC Control */
-       0x0000,     /* R116 */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x1FFF,     /* R128 - GPIO Debounce */
-       0x0000,     /* R129 - GPIO Pin pull up Control */
-       0x0110,     /* R130 - GPIO Pull down Control */
-       0x0000,     /* R131 - GPIO Interrupt Mode */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 - GPIO Control */
-       0x09FA,     /* R134 - GPIO Configuration (i/o) */
-       0x0DF6,     /* R135 - GPIO Pin Polarity / Type */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x1310,     /* R140 - GPIO Function Select 1 */
-       0x0003,     /* R141 - GPIO Function Select 2 */
-       0x2000,     /* R142 - GPIO Function Select 3 */
-       0x0000,     /* R143 - GPIO Function Select 4 */
-       0x0000,     /* R144 - Digitiser Control (1) */
-       0x0002,     /* R145 - Digitiser Control (2) */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x7000,     /* R152 - AUX1 Readback */
-       0x7000,     /* R153 - AUX2 Readback */
-       0x7000,     /* R154 - AUX3 Readback */
-       0x7000,     /* R155 - AUX4 Readback */
-       0x0000,     /* R156 - USB Voltage Readback */
-       0x0000,     /* R157 - LINE Voltage Readback */
-       0x0000,     /* R158 - BATT Voltage Readback */
-       0x0000,     /* R159 - Chip Temp Readback */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 - Generic Comparator Control */
-       0x0000,     /* R164 - Generic comparator 1 */
-       0x0000,     /* R165 - Generic comparator 2 */
-       0x0000,     /* R166 - Generic comparator 3 */
-       0x0000,     /* R167 - Generic comparator 4 */
-       0xA00F,     /* R168 - Battery Charger Control 1 */
-       0x0B06,     /* R169 - Battery Charger Control 2 */
-       0x0000,     /* R170 - Battery Charger Control 3 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Current Sink Driver A */
-       0x0000,     /* R173 - CSA Flash control */
-       0x0000,     /* R174 */
-       0x0000,     /* R175 */
-       0x0000,     /* R176 - DCDC/LDO requested */
-       0x032D,     /* R177 - DCDC Active options */
-       0x0000,     /* R178 - DCDC Sleep options */
-       0x0025,     /* R179 - Power-check comparator */
-       0x001A,     /* R180 - DCDC1 Control */
-       0x0800,     /* R181 - DCDC1 Timeouts */
-       0x1006,     /* R182 - DCDC1 Low Power */
-       0x0018,     /* R183 - DCDC2 Control */
-       0x0000,     /* R184 - DCDC2 Timeouts */
-       0x0000,     /* R185 */
-       0x0056,     /* R186 - DCDC3 Control */
-       0x0400,     /* R187 - DCDC3 Timeouts */
-       0x0006,     /* R188 - DCDC3 Low Power */
-       0x0026,     /* R189 - DCDC4 Control */
-       0x0C00,     /* R190 - DCDC4 Timeouts */
-       0x0006,     /* R191 - DCDC4 Low Power */
-       0x0008,     /* R192 */
-       0x0000,     /* R193 */
-       0x0000,     /* R194 */
-       0x0026,     /* R195 */
-       0x0C00,     /* R196 */
-       0x0006,     /* R197 */
-       0x0000,     /* R198 */
-       0x0003,     /* R199 - Limit Switch Control */
-       0x001C,     /* R200 - LDO1 Control */
-       0x0400,     /* R201 - LDO1 Timeouts */
-       0x001C,     /* R202 - LDO1 Low Power */
-       0x0010,     /* R203 - LDO2 Control */
-       0x0C00,     /* R204 - LDO2 Timeouts */
-       0x001C,     /* R205 - LDO2 Low Power */
-       0x0015,     /* R206 - LDO3 Control */
-       0x0000,     /* R207 - LDO3 Timeouts */
-       0x001C,     /* R208 - LDO3 Low Power */
-       0x001A,     /* R209 - LDO4 Control */
-       0x0000,     /* R210 - LDO4 Timeouts */
-       0x001C,     /* R211 - LDO4 Low Power */
-       0x0000,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 - VCC_FAULT Masks */
-       0x001F,     /* R216 - Main Bandgap Control */
-       0x0000,     /* R217 - OSC Control */
-       0x9000,     /* R218 - RTC Tick Control */
-       0x0000,     /* R219 - Security1 */
-       0x4000,     /* R220 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0000,     /* R223 */
-       0x0000,     /* R224 - Signal overrides */
-       0x0000,     /* R225 - DCDC/LDO status */
-       0x0000,     /* R226 - Charger Overides/status */
-       0x0000,     /* R227 - misc overrides */
-       0x0000,     /* R228 - Supply overrides/status 1 */
-       0x0000,     /* R229 - Supply overrides/status 2 */
-       0xE000,     /* R230 - GPIO Pin Status */
-       0x0000,     /* R231 - comparotor overrides */
-       0x0000,     /* R232 */
-       0x0000,     /* R233 - State Machine status */
-       0x1200,     /* R234 - FLL Test 1 */
-       0x0000,     /* R235 */
-       0x8000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0000,     /* R238 */
-       0x0000,     /* R239 */
-       0x0003,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0004,     /* R243 */
-       0x0300,     /* R244 */
-       0x0000,     /* R245 */
-       0x0200,     /* R246 */
-       0x0000,     /* R247 */
-       0x1000,     /* R248 - DCDC1 Test Controls */
-       0x1000,     /* R249 */
-       0x1000,     /* R250 - DCDC3 Test Controls */
-       0x1000,     /* R251 - DCDC4 Test Controls */
-};
-#endif
-
-#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_3
-
-#undef WM8350_HAVE_CONFIG_MODE
-#define WM8350_HAVE_CONFIG_MODE
-
-const u16 wm8351_mode3_defaults[] = {
-       0x6143,     /* R0   - Reset/ID */
-       0x0000,     /* R1   - ID */
-       0x0001,     /* R2   - Revision */
-       0x1C02,     /* R3   - System Control 1 */
-       0x0204,     /* R4   - System Control 2 */
-       0x0000,     /* R5   - System Hibernate */
-       0x8A00,     /* R6   - Interface Control */
-       0x0000,     /* R7 */
-       0x8000,     /* R8   - Power mgmt (1) */
-       0x0000,     /* R9   - Power mgmt (2) */
-       0x0000,     /* R10  - Power mgmt (3) */
-       0x2000,     /* R11  - Power mgmt (4) */
-       0x0E00,     /* R12  - Power mgmt (5) */
-       0x0000,     /* R13  - Power mgmt (6) */
-       0x0000,     /* R14  - Power mgmt (7) */
-       0x0000,     /* R15 */
-       0x0000,     /* R16  - RTC Seconds/Minutes */
-       0x0100,     /* R17  - RTC Hours/Day */
-       0x0101,     /* R18  - RTC Date/Month */
-       0x1400,     /* R19  - RTC Year */
-       0x0000,     /* R20  - Alarm Seconds/Minutes */
-       0x0000,     /* R21  - Alarm Hours/Day */
-       0x0000,     /* R22  - Alarm Date/Month */
-       0x0320,     /* R23  - RTC Time Control */
-       0x0000,     /* R24  - System Interrupts */
-       0x0000,     /* R25  - Interrupt Status 1 */
-       0x0000,     /* R26  - Interrupt Status 2 */
-       0x0000,     /* R27 */
-       0x0000,     /* R28  - Under Voltage Interrupt status */
-       0x0000,     /* R29  - Over Current Interrupt status */
-       0x0000,     /* R30  - GPIO Interrupt Status */
-       0x0000,     /* R31  - Comparator Interrupt Status */
-       0x3FFF,     /* R32  - System Interrupts Mask */
-       0x0000,     /* R33  - Interrupt Status 1 Mask */
-       0x0000,     /* R34  - Interrupt Status 2 Mask */
-       0x0000,     /* R35 */
-       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
-       0x0000,     /* R37  - Over Current Interrupt status Mask */
-       0x0000,     /* R38  - GPIO Interrupt Status Mask */
-       0x0000,     /* R39  - Comparator Interrupt Status Mask */
-       0x0040,     /* R40  - Clock Control 1 */
-       0x0000,     /* R41  - Clock Control 2 */
-       0x3A00,     /* R42  - FLL Control 1 */
-       0x7086,     /* R43  - FLL Control 2 */
-       0xC226,     /* R44  - FLL Control 3 */
-       0x0000,     /* R45  - FLL Control 4 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47 */
-       0x0000,     /* R48  - DAC Control */
-       0x0000,     /* R49 */
-       0x00C0,     /* R50  - DAC Digital Volume L */
-       0x00C0,     /* R51  - DAC Digital Volume R */
-       0x0000,     /* R52 */
-       0x0040,     /* R53  - DAC LR Rate */
-       0x0000,     /* R54  - DAC Clock Control */
-       0x0000,     /* R55 */
-       0x0000,     /* R56 */
-       0x0000,     /* R57 */
-       0x4000,     /* R58  - DAC Mute */
-       0x0000,     /* R59  - DAC Mute Volume */
-       0x0000,     /* R60  - DAC Side */
-       0x0000,     /* R61 */
-       0x0000,     /* R62 */
-       0x0000,     /* R63 */
-       0x8000,     /* R64  - ADC Control */
-       0x0000,     /* R65 */
-       0x00C0,     /* R66  - ADC Digital Volume L */
-       0x00C0,     /* R67  - ADC Digital Volume R */
-       0x0000,     /* R68  - ADC Divider */
-       0x0000,     /* R69 */
-       0x0040,     /* R70  - ADC LR Rate */
-       0x0000,     /* R71 */
-       0x0303,     /* R72  - Input Control */
-       0x0000,     /* R73  - IN3 Input Control */
-       0x0000,     /* R74  - Mic Bias Control */
-       0x0000,     /* R75 */
-       0x0000,     /* R76  - Output Control */
-       0x0000,     /* R77  - Jack Detect */
-       0x0000,     /* R78  - Anti Pop Control */
-       0x0000,     /* R79 */
-       0x0040,     /* R80  - Left Input Volume */
-       0x0040,     /* R81  - Right Input Volume */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87 */
-       0x0800,     /* R88  - Left Mixer Control */
-       0x1000,     /* R89  - Right Mixer Control */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92  - OUT3 Mixer Control */
-       0x0000,     /* R93  - OUT4 Mixer Control */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96  - Output Left Mixer Volume */
-       0x0000,     /* R97  - Output Right Mixer Volume */
-       0x0000,     /* R98  - Input Mixer Volume L */
-       0x0000,     /* R99  - Input Mixer Volume R */
-       0x0000,     /* R100 - Input Mixer Volume */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x00E4,     /* R104 - OUT1L Volume */
-       0x00E4,     /* R105 - OUT1R Volume */
-       0x00E4,     /* R106 - OUT2L Volume */
-       0x02E4,     /* R107 - OUT2R Volume */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 - BEEP Volume */
-       0x0A00,     /* R112 - AI Formating */
-       0x0000,     /* R113 - ADC DAC COMP */
-       0x0020,     /* R114 - AI ADC Control */
-       0x0020,     /* R115 - AI DAC Control */
-       0x0000,     /* R116 */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x1FFF,     /* R128 - GPIO Debounce */
-       0x0010,     /* R129 - GPIO Pin pull up Control */
-       0x0000,     /* R130 - GPIO Pull down Control */
-       0x0000,     /* R131 - GPIO Interrupt Mode */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 - GPIO Control */
-       0x0BFB,     /* R134 - GPIO Configuration (i/o) */
-       0x0FFD,     /* R135 - GPIO Pin Polarity / Type */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x0310,     /* R140 - GPIO Function Select 1 */
-       0x0001,     /* R141 - GPIO Function Select 2 */
-       0x2300,     /* R142 - GPIO Function Select 3 */
-       0x0003,     /* R143 - GPIO Function Select 4 */
-       0x0000,     /* R144 - Digitiser Control (1) */
-       0x0002,     /* R145 - Digitiser Control (2) */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x7000,     /* R152 - AUX1 Readback */
-       0x7000,     /* R153 - AUX2 Readback */
-       0x7000,     /* R154 - AUX3 Readback */
-       0x7000,     /* R155 - AUX4 Readback */
-       0x0000,     /* R156 - USB Voltage Readback */
-       0x0000,     /* R157 - LINE Voltage Readback */
-       0x0000,     /* R158 - BATT Voltage Readback */
-       0x0000,     /* R159 - Chip Temp Readback */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 - Generic Comparator Control */
-       0x0000,     /* R164 - Generic comparator 1 */
-       0x0000,     /* R165 - Generic comparator 2 */
-       0x0000,     /* R166 - Generic comparator 3 */
-       0x0000,     /* R167 - Generic comparator 4 */
-       0xA00F,     /* R168 - Battery Charger Control 1 */
-       0x0B06,     /* R169 - Battery Charger Control 2 */
-       0x0000,     /* R170 - Battery Charger Control 3 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Current Sink Driver A */
-       0x0000,     /* R173 - CSA Flash control */
-       0x0000,     /* R174 */
-       0x0000,     /* R175 */
-       0x0000,     /* R176 - DCDC/LDO requested */
-       0x032D,     /* R177 - DCDC Active options */
-       0x0000,     /* R178 - DCDC Sleep options */
-       0x0025,     /* R179 - Power-check comparator */
-       0x000E,     /* R180 - DCDC1 Control */
-       0x0400,     /* R181 - DCDC1 Timeouts */
-       0x1006,     /* R182 - DCDC1 Low Power */
-       0x0018,     /* R183 - DCDC2 Control */
-       0x0000,     /* R184 - DCDC2 Timeouts */
-       0x0000,     /* R185 */
-       0x0026,     /* R186 - DCDC3 Control */
-       0x0800,     /* R187 - DCDC3 Timeouts */
-       0x0006,     /* R188 - DCDC3 Low Power */
-       0x0062,     /* R189 - DCDC4 Control */
-       0x1400,     /* R190 - DCDC4 Timeouts */
-       0x0006,     /* R191 - DCDC4 Low Power */
-       0x0008,     /* R192 */
-       0x0000,     /* R193 */
-       0x0000,     /* R194 */
-       0x0026,     /* R195 */
-       0x0400,     /* R196 */
-       0x0006,     /* R197 */
-       0x0000,     /* R198 */
-       0x0003,     /* R199 - Limit Switch Control */
-       0x0006,     /* R200 - LDO1 Control */
-       0x0C00,     /* R201 - LDO1 Timeouts */
-       0x001C,     /* R202 - LDO1 Low Power */
-       0x0016,     /* R203 - LDO2 Control */
-       0x0000,     /* R204 - LDO2 Timeouts */
-       0x001C,     /* R205 - LDO2 Low Power */
-       0x0019,     /* R206 - LDO3 Control */
-       0x0000,     /* R207 - LDO3 Timeouts */
-       0x001C,     /* R208 - LDO3 Low Power */
-       0x001A,     /* R209 - LDO4 Control */
-       0x1000,     /* R210 - LDO4 Timeouts */
-       0x001C,     /* R211 - LDO4 Low Power */
-       0x0000,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 - VCC_FAULT Masks */
-       0x001F,     /* R216 - Main Bandgap Control */
-       0x0000,     /* R217 - OSC Control */
-       0x9000,     /* R218 - RTC Tick Control */
-       0x0000,     /* R219 - Security1 */
-       0x4000,     /* R220 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0000,     /* R223 */
-       0x0000,     /* R224 - Signal overrides */
-       0x0000,     /* R225 - DCDC/LDO status */
-       0x0000,     /* R226 - Charger Overides/status */
-       0x0000,     /* R227 - misc overrides */
-       0x0000,     /* R228 - Supply overrides/status 1 */
-       0x0000,     /* R229 - Supply overrides/status 2 */
-       0xE000,     /* R230 - GPIO Pin Status */
-       0x0000,     /* R231 - comparotor overrides */
-       0x0000,     /* R232 */
-       0x0000,     /* R233 - State Machine status */
-       0x1200,     /* R234 - FLL Test 1 */
-       0x0000,     /* R235 */
-       0x8000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0000,     /* R238 */
-       0x0000,     /* R239 */
-       0x0003,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0004,     /* R243 */
-       0x0300,     /* R244 */
-       0x0000,     /* R245 */
-       0x0200,     /* R246 */
-       0x0000,     /* R247 */
-       0x1000,     /* R248 - DCDC1 Test Controls */
-       0x1000,     /* R249 */
-       0x1000,     /* R250 - DCDC3 Test Controls */
-       0x1000,     /* R251 - DCDC4 Test Controls */
-};
-#endif
-
-#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0
-
-#undef WM8350_HAVE_CONFIG_MODE
-#define WM8350_HAVE_CONFIG_MODE
-
-const u16 wm8352_mode0_defaults[] = {
-       0x6143,     /* R0   - Reset/ID */
-       0x0000,     /* R1   - ID */
-       0x0002,     /* R2   - Revision */
-       0x1C02,     /* R3   - System Control 1 */
-       0x0004,     /* R4   - System Control 2 */
-       0x0000,     /* R5   - System Hibernate */
-       0x8A00,     /* R6   - Interface Control */
-       0x0000,     /* R7 */
-       0x8000,     /* R8   - Power mgmt (1) */
-       0x0000,     /* R9   - Power mgmt (2) */
-       0x0000,     /* R10  - Power mgmt (3) */
-       0x2000,     /* R11  - Power mgmt (4) */
-       0x0E00,     /* R12  - Power mgmt (5) */
-       0x0000,     /* R13  - Power mgmt (6) */
-       0x0000,     /* R14  - Power mgmt (7) */
-       0x0000,     /* R15 */
-       0x0000,     /* R16  - RTC Seconds/Minutes */
-       0x0100,     /* R17  - RTC Hours/Day */
-       0x0101,     /* R18  - RTC Date/Month */
-       0x1400,     /* R19  - RTC Year */
-       0x0000,     /* R20  - Alarm Seconds/Minutes */
-       0x0000,     /* R21  - Alarm Hours/Day */
-       0x0000,     /* R22  - Alarm Date/Month */
-       0x0320,     /* R23  - RTC Time Control */
-       0x0000,     /* R24  - System Interrupts */
-       0x0000,     /* R25  - Interrupt Status 1 */
-       0x0000,     /* R26  - Interrupt Status 2 */
-       0x0000,     /* R27 */
-       0x0000,     /* R28  - Under Voltage Interrupt status */
-       0x0000,     /* R29  - Over Current Interrupt status */
-       0x0000,     /* R30  - GPIO Interrupt Status */
-       0x0000,     /* R31  - Comparator Interrupt Status */
-       0x3FFF,     /* R32  - System Interrupts Mask */
-       0x0000,     /* R33  - Interrupt Status 1 Mask */
-       0x0000,     /* R34  - Interrupt Status 2 Mask */
-       0x0000,     /* R35 */
-       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
-       0x0000,     /* R37  - Over Current Interrupt status Mask */
-       0x0000,     /* R38  - GPIO Interrupt Status Mask */
-       0x0000,     /* R39  - Comparator Interrupt Status Mask */
-       0x0040,     /* R40  - Clock Control 1 */
-       0x0000,     /* R41  - Clock Control 2 */
-       0x3A00,     /* R42  - FLL Control 1 */
-       0x7086,     /* R43  - FLL Control 2 */
-       0xC226,     /* R44  - FLL Control 3 */
-       0x0000,     /* R45  - FLL Control 4 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47 */
-       0x0000,     /* R48  - DAC Control */
-       0x0000,     /* R49 */
-       0x00C0,     /* R50  - DAC Digital Volume L */
-       0x00C0,     /* R51  - DAC Digital Volume R */
-       0x0000,     /* R52 */
-       0x0040,     /* R53  - DAC LR Rate */
-       0x0000,     /* R54  - DAC Clock Control */
-       0x0000,     /* R55 */
-       0x0000,     /* R56 */
-       0x0000,     /* R57 */
-       0x4000,     /* R58  - DAC Mute */
-       0x0000,     /* R59  - DAC Mute Volume */
-       0x0000,     /* R60  - DAC Side */
-       0x0000,     /* R61 */
-       0x0000,     /* R62 */
-       0x0000,     /* R63 */
-       0x8000,     /* R64  - ADC Control */
-       0x0000,     /* R65 */
-       0x00C0,     /* R66  - ADC Digital Volume L */
-       0x00C0,     /* R67  - ADC Digital Volume R */
-       0x0000,     /* R68  - ADC Divider */
-       0x0000,     /* R69 */
-       0x0040,     /* R70  - ADC LR Rate */
-       0x0000,     /* R71 */
-       0x0303,     /* R72  - Input Control */
-       0x0000,     /* R73  - IN3 Input Control */
-       0x0000,     /* R74  - Mic Bias Control */
-       0x0000,     /* R75 */
-       0x0000,     /* R76  - Output Control */
-       0x0000,     /* R77  - Jack Detect */
-       0x0000,     /* R78  - Anti Pop Control */
-       0x0000,     /* R79 */
-       0x0040,     /* R80  - Left Input Volume */
-       0x0040,     /* R81  - Right Input Volume */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87 */
-       0x0800,     /* R88  - Left Mixer Control */
-       0x1000,     /* R89  - Right Mixer Control */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92  - OUT3 Mixer Control */
-       0x0000,     /* R93  - OUT4 Mixer Control */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96  - Output Left Mixer Volume */
-       0x0000,     /* R97  - Output Right Mixer Volume */
-       0x0000,     /* R98  - Input Mixer Volume L */
-       0x0000,     /* R99  - Input Mixer Volume R */
-       0x0000,     /* R100 - Input Mixer Volume */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x00E4,     /* R104 - OUT1L Volume */
-       0x00E4,     /* R105 - OUT1R Volume */
-       0x00E4,     /* R106 - OUT2L Volume */
-       0x02E4,     /* R107 - OUT2R Volume */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 - BEEP Volume */
-       0x0A00,     /* R112 - AI Formating */
-       0x0000,     /* R113 - ADC DAC COMP */
-       0x0020,     /* R114 - AI ADC Control */
-       0x0020,     /* R115 - AI DAC Control */
-       0x0000,     /* R116 */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x1FFF,     /* R128 - GPIO Debounce */
-       0x0000,     /* R129 - GPIO Pin pull up Control */
-       0x0000,     /* R130 - GPIO Pull down Control */
-       0x0000,     /* R131 - GPIO Interrupt Mode */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 - GPIO Control */
-       0x0FFC,     /* R134 - GPIO Configuration (i/o) */
-       0x0FFC,     /* R135 - GPIO Pin Polarity / Type */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x0013,     /* R140 - GPIO Function Select 1 */
-       0x0000,     /* R141 - GPIO Function Select 2 */
-       0x0000,     /* R142 - GPIO Function Select 3 */
-       0x0003,     /* R143 - GPIO Function Select 4 */
-       0x0000,     /* R144 - Digitiser Control (1) */
-       0x0002,     /* R145 - Digitiser Control (2) */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x7000,     /* R152 - AUX1 Readback */
-       0x7000,     /* R153 - AUX2 Readback */
-       0x7000,     /* R154 - AUX3 Readback */
-       0x7000,     /* R155 - AUX4 Readback */
-       0x0000,     /* R156 - USB Voltage Readback */
-       0x0000,     /* R157 - LINE Voltage Readback */
-       0x0000,     /* R158 - BATT Voltage Readback */
-       0x0000,     /* R159 - Chip Temp Readback */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 - Generic Comparator Control */
-       0x0000,     /* R164 - Generic comparator 1 */
-       0x0000,     /* R165 - Generic comparator 2 */
-       0x0000,     /* R166 - Generic comparator 3 */
-       0x0000,     /* R167 - Generic comparator 4 */
-       0xA00F,     /* R168 - Battery Charger Control 1 */
-       0x0B06,     /* R169 - Battery Charger Control 2 */
-       0x0000,     /* R170 - Battery Charger Control 3 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Current Sink Driver A */
-       0x0000,     /* R173 - CSA Flash control */
-       0x0000,     /* R174 - Current Sink Driver B */
-       0x0000,     /* R175 - CSB Flash control */
-       0x0000,     /* R176 - DCDC/LDO requested */
-       0x032D,     /* R177 - DCDC Active options */
-       0x0000,     /* R178 - DCDC Sleep options */
-       0x0025,     /* R179 - Power-check comparator */
-       0x000E,     /* R180 - DCDC1 Control */
-       0x0000,     /* R181 - DCDC1 Timeouts */
-       0x1006,     /* R182 - DCDC1 Low Power */
-       0x0018,     /* R183 - DCDC2 Control */
-       0x0000,     /* R184 - DCDC2 Timeouts */
-       0x0000,     /* R185 */
-       0x0000,     /* R186 - DCDC3 Control */
-       0x0000,     /* R187 - DCDC3 Timeouts */
-       0x0006,     /* R188 - DCDC3 Low Power */
-       0x0000,     /* R189 - DCDC4 Control */
-       0x0000,     /* R190 - DCDC4 Timeouts */
-       0x0006,     /* R191 - DCDC4 Low Power */
-       0x0008,     /* R192 - DCDC5 Control */
-       0x0000,     /* R193 - DCDC5 Timeouts */
-       0x0000,     /* R194 */
-       0x0000,     /* R195 - DCDC6 Control */
-       0x0000,     /* R196 - DCDC6 Timeouts */
-       0x0006,     /* R197 - DCDC6 Low Power */
-       0x0000,     /* R198 */
-       0x0003,     /* R199 - Limit Switch Control */
-       0x001C,     /* R200 - LDO1 Control */
-       0x0000,     /* R201 - LDO1 Timeouts */
-       0x001C,     /* R202 - LDO1 Low Power */
-       0x001B,     /* R203 - LDO2 Control */
-       0x0000,     /* R204 - LDO2 Timeouts */
-       0x001C,     /* R205 - LDO2 Low Power */
-       0x001B,     /* R206 - LDO3 Control */
-       0x0000,     /* R207 - LDO3 Timeouts */
-       0x001C,     /* R208 - LDO3 Low Power */
-       0x001B,     /* R209 - LDO4 Control */
-       0x0000,     /* R210 - LDO4 Timeouts */
-       0x001C,     /* R211 - LDO4 Low Power */
-       0x0000,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 - VCC_FAULT Masks */
-       0x001F,     /* R216 - Main Bandgap Control */
-       0x0000,     /* R217 - OSC Control */
-       0x9000,     /* R218 - RTC Tick Control */
-       0x0000,     /* R219 - Security1 */
-       0x4000,     /* R220 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0000,     /* R223 */
-       0x0000,     /* R224 - Signal overrides */
-       0x0000,     /* R225 - DCDC/LDO status */
-       0x0000,     /* R226 - Charger Overides/status */
-       0x0000,     /* R227 - misc overrides */
-       0x0000,     /* R228 - Supply overrides/status 1 */
-       0x0000,     /* R229 - Supply overrides/status 2 */
-       0xE000,     /* R230 - GPIO Pin Status */
-       0x0000,     /* R231 - comparotor overrides */
-       0x0000,     /* R232 */
-       0x0000,     /* R233 - State Machine status */
-       0x1200,     /* R234 */
-       0x0000,     /* R235 */
-       0x8000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0000,     /* R238 */
-       0x0000,     /* R239 */
-       0x0003,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0004,     /* R243 */
-       0x0300,     /* R244 */
-       0x0000,     /* R245 */
-       0x0200,     /* R246 */
-       0x0000,     /* R247 */
-       0x1000,     /* R248 - DCDC1 Test Controls */
-       0x5000,     /* R249 */
-       0x1000,     /* R250 - DCDC3 Test Controls */
-       0x1000,     /* R251 - DCDC4 Test Controls */
-       0x5100,     /* R252 */
-       0x1000,     /* R253 - DCDC6 Test Controls */
-};
-#endif
-
-#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_1
-
-#undef WM8350_HAVE_CONFIG_MODE
-#define WM8350_HAVE_CONFIG_MODE
-
-const u16 wm8352_mode1_defaults[] = {
-       0x6143,     /* R0   - Reset/ID */
-       0x0000,     /* R1   - ID */
-       0x0002,     /* R2   - Revision */
-       0x1C02,     /* R3   - System Control 1 */
-       0x0204,     /* R4   - System Control 2 */
-       0x0000,     /* R5   - System Hibernate */
-       0x8A00,     /* R6   - Interface Control */
-       0x0000,     /* R7 */
-       0x8000,     /* R8   - Power mgmt (1) */
-       0x0000,     /* R9   - Power mgmt (2) */
-       0x0000,     /* R10  - Power mgmt (3) */
-       0x2000,     /* R11  - Power mgmt (4) */
-       0x0E00,     /* R12  - Power mgmt (5) */
-       0x0000,     /* R13  - Power mgmt (6) */
-       0x0000,     /* R14  - Power mgmt (7) */
-       0x0000,     /* R15 */
-       0x0000,     /* R16  - RTC Seconds/Minutes */
-       0x0100,     /* R17  - RTC Hours/Day */
-       0x0101,     /* R18  - RTC Date/Month */
-       0x1400,     /* R19  - RTC Year */
-       0x0000,     /* R20  - Alarm Seconds/Minutes */
-       0x0000,     /* R21  - Alarm Hours/Day */
-       0x0000,     /* R22  - Alarm Date/Month */
-       0x0320,     /* R23  - RTC Time Control */
-       0x0000,     /* R24  - System Interrupts */
-       0x0000,     /* R25  - Interrupt Status 1 */
-       0x0000,     /* R26  - Interrupt Status 2 */
-       0x0000,     /* R27 */
-       0x0000,     /* R28  - Under Voltage Interrupt status */
-       0x0000,     /* R29  - Over Current Interrupt status */
-       0x0000,     /* R30  - GPIO Interrupt Status */
-       0x0000,     /* R31  - Comparator Interrupt Status */
-       0x3FFF,     /* R32  - System Interrupts Mask */
-       0x0000,     /* R33  - Interrupt Status 1 Mask */
-       0x0000,     /* R34  - Interrupt Status 2 Mask */
-       0x0000,     /* R35 */
-       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
-       0x0000,     /* R37  - Over Current Interrupt status Mask */
-       0x0000,     /* R38  - GPIO Interrupt Status Mask */
-       0x0000,     /* R39  - Comparator Interrupt Status Mask */
-       0x0040,     /* R40  - Clock Control 1 */
-       0x0000,     /* R41  - Clock Control 2 */
-       0x3A00,     /* R42  - FLL Control 1 */
-       0x7086,     /* R43  - FLL Control 2 */
-       0xC226,     /* R44  - FLL Control 3 */
-       0x0000,     /* R45  - FLL Control 4 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47 */
-       0x0000,     /* R48  - DAC Control */
-       0x0000,     /* R49 */
-       0x00C0,     /* R50  - DAC Digital Volume L */
-       0x00C0,     /* R51  - DAC Digital Volume R */
-       0x0000,     /* R52 */
-       0x0040,     /* R53  - DAC LR Rate */
-       0x0000,     /* R54  - DAC Clock Control */
-       0x0000,     /* R55 */
-       0x0000,     /* R56 */
-       0x0000,     /* R57 */
-       0x4000,     /* R58  - DAC Mute */
-       0x0000,     /* R59  - DAC Mute Volume */
-       0x0000,     /* R60  - DAC Side */
-       0x0000,     /* R61 */
-       0x0000,     /* R62 */
-       0x0000,     /* R63 */
-       0x8000,     /* R64  - ADC Control */
-       0x0000,     /* R65 */
-       0x00C0,     /* R66  - ADC Digital Volume L */
-       0x00C0,     /* R67  - ADC Digital Volume R */
-       0x0000,     /* R68  - ADC Divider */
-       0x0000,     /* R69 */
-       0x0040,     /* R70  - ADC LR Rate */
-       0x0000,     /* R71 */
-       0x0303,     /* R72  - Input Control */
-       0x0000,     /* R73  - IN3 Input Control */
-       0x0000,     /* R74  - Mic Bias Control */
-       0x0000,     /* R75 */
-       0x0000,     /* R76  - Output Control */
-       0x0000,     /* R77  - Jack Detect */
-       0x0000,     /* R78  - Anti Pop Control */
-       0x0000,     /* R79 */
-       0x0040,     /* R80  - Left Input Volume */
-       0x0040,     /* R81  - Right Input Volume */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87 */
-       0x0800,     /* R88  - Left Mixer Control */
-       0x1000,     /* R89  - Right Mixer Control */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92  - OUT3 Mixer Control */
-       0x0000,     /* R93  - OUT4 Mixer Control */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96  - Output Left Mixer Volume */
-       0x0000,     /* R97  - Output Right Mixer Volume */
-       0x0000,     /* R98  - Input Mixer Volume L */
-       0x0000,     /* R99  - Input Mixer Volume R */
-       0x0000,     /* R100 - Input Mixer Volume */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x00E4,     /* R104 - OUT1L Volume */
-       0x00E4,     /* R105 - OUT1R Volume */
-       0x00E4,     /* R106 - OUT2L Volume */
-       0x02E4,     /* R107 - OUT2R Volume */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 - BEEP Volume */
-       0x0A00,     /* R112 - AI Formating */
-       0x0000,     /* R113 - ADC DAC COMP */
-       0x0020,     /* R114 - AI ADC Control */
-       0x0020,     /* R115 - AI DAC Control */
-       0x0000,     /* R116 */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x1FFF,     /* R128 - GPIO Debounce */
-       0x0000,     /* R129 - GPIO Pin pull up Control */
-       0x0000,     /* R130 - GPIO Pull down Control */
-       0x0000,     /* R131 - GPIO Interrupt Mode */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 - GPIO Control */
-       0x0BFB,     /* R134 - GPIO Configuration (i/o) */
-       0x0FFF,     /* R135 - GPIO Pin Polarity / Type */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x0300,     /* R140 - GPIO Function Select 1 */
-       0x0000,     /* R141 - GPIO Function Select 2 */
-       0x2300,     /* R142 - GPIO Function Select 3 */
-       0x0003,     /* R143 - GPIO Function Select 4 */
-       0x0000,     /* R144 - Digitiser Control (1) */
-       0x0002,     /* R145 - Digitiser Control (2) */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x7000,     /* R152 - AUX1 Readback */
-       0x7000,     /* R153 - AUX2 Readback */
-       0x7000,     /* R154 - AUX3 Readback */
-       0x7000,     /* R155 - AUX4 Readback */
-       0x0000,     /* R156 - USB Voltage Readback */
-       0x0000,     /* R157 - LINE Voltage Readback */
-       0x0000,     /* R158 - BATT Voltage Readback */
-       0x0000,     /* R159 - Chip Temp Readback */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 - Generic Comparator Control */
-       0x0000,     /* R164 - Generic comparator 1 */
-       0x0000,     /* R165 - Generic comparator 2 */
-       0x0000,     /* R166 - Generic comparator 3 */
-       0x0000,     /* R167 - Generic comparator 4 */
-       0xA00F,     /* R168 - Battery Charger Control 1 */
-       0x0B06,     /* R169 - Battery Charger Control 2 */
-       0x0000,     /* R170 - Battery Charger Control 3 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Current Sink Driver A */
-       0x0000,     /* R173 - CSA Flash control */
-       0x0000,     /* R174 - Current Sink Driver B */
-       0x0000,     /* R175 - CSB Flash control */
-       0x0000,     /* R176 - DCDC/LDO requested */
-       0x032D,     /* R177 - DCDC Active options */
-       0x0000,     /* R178 - DCDC Sleep options */
-       0x0025,     /* R179 - Power-check comparator */
-       0x0062,     /* R180 - DCDC1 Control */
-       0x0400,     /* R181 - DCDC1 Timeouts */
-       0x1006,     /* R182 - DCDC1 Low Power */
-       0x0018,     /* R183 - DCDC2 Control */
-       0x0000,     /* R184 - DCDC2 Timeouts */
-       0x0000,     /* R185 */
-       0x0006,     /* R186 - DCDC3 Control */
-       0x0800,     /* R187 - DCDC3 Timeouts */
-       0x0006,     /* R188 - DCDC3 Low Power */
-       0x0006,     /* R189 - DCDC4 Control */
-       0x0C00,     /* R190 - DCDC4 Timeouts */
-       0x0006,     /* R191 - DCDC4 Low Power */
-       0x0008,     /* R192 - DCDC5 Control */
-       0x0000,     /* R193 - DCDC5 Timeouts */
-       0x0000,     /* R194 */
-       0x0026,     /* R195 - DCDC6 Control */
-       0x1000,     /* R196 - DCDC6 Timeouts */
-       0x0006,     /* R197 - DCDC6 Low Power */
-       0x0000,     /* R198 */
-       0x0003,     /* R199 - Limit Switch Control */
-       0x0002,     /* R200 - LDO1 Control */
-       0x0000,     /* R201 - LDO1 Timeouts */
-       0x001C,     /* R202 - LDO1 Low Power */
-       0x001A,     /* R203 - LDO2 Control */
-       0x0000,     /* R204 - LDO2 Timeouts */
-       0x001C,     /* R205 - LDO2 Low Power */
-       0x001F,     /* R206 - LDO3 Control */
-       0x0000,     /* R207 - LDO3 Timeouts */
-       0x001C,     /* R208 - LDO3 Low Power */
-       0x001F,     /* R209 - LDO4 Control */
-       0x0000,     /* R210 - LDO4 Timeouts */
-       0x001C,     /* R211 - LDO4 Low Power */
-       0x0000,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 - VCC_FAULT Masks */
-       0x001F,     /* R216 - Main Bandgap Control */
-       0x0000,     /* R217 - OSC Control */
-       0x9000,     /* R218 - RTC Tick Control */
-       0x0000,     /* R219 - Security1 */
-       0x4000,     /* R220 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0000,     /* R223 */
-       0x0000,     /* R224 - Signal overrides */
-       0x0000,     /* R225 - DCDC/LDO status */
-       0x0000,     /* R226 - Charger Overides/status */
-       0x0000,     /* R227 - misc overrides */
-       0x0000,     /* R228 - Supply overrides/status 1 */
-       0x0000,     /* R229 - Supply overrides/status 2 */
-       0xE000,     /* R230 - GPIO Pin Status */
-       0x0000,     /* R231 - comparotor overrides */
-       0x0000,     /* R232 */
-       0x0000,     /* R233 - State Machine status */
-       0x1200,     /* R234 */
-       0x0000,     /* R235 */
-       0x8000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0000,     /* R238 */
-       0x0000,     /* R239 */
-       0x0003,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0004,     /* R243 */
-       0x0300,     /* R244 */
-       0x0000,     /* R245 */
-       0x0200,     /* R246 */
-       0x0000,     /* R247 */
-       0x1000,     /* R248 - DCDC1 Test Controls */
-       0x5000,     /* R249 */
-       0x1000,     /* R250 - DCDC3 Test Controls */
-       0x1000,     /* R251 - DCDC4 Test Controls */
-       0x5100,     /* R252 */
-       0x1000,     /* R253 - DCDC6 Test Controls */
-};
-#endif
-
-#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_2
-
-#undef WM8350_HAVE_CONFIG_MODE
-#define WM8350_HAVE_CONFIG_MODE
-
-const u16 wm8352_mode2_defaults[] = {
-       0x6143,     /* R0   - Reset/ID */
-       0x0000,     /* R1   - ID */
-       0x0002,     /* R2   - Revision */
-       0x1C02,     /* R3   - System Control 1 */
-       0x0204,     /* R4   - System Control 2 */
-       0x0000,     /* R5   - System Hibernate */
-       0x8A00,     /* R6   - Interface Control */
-       0x0000,     /* R7 */
-       0x8000,     /* R8   - Power mgmt (1) */
-       0x0000,     /* R9   - Power mgmt (2) */
-       0x0000,     /* R10  - Power mgmt (3) */
-       0x2000,     /* R11  - Power mgmt (4) */
-       0x0E00,     /* R12  - Power mgmt (5) */
-       0x0000,     /* R13  - Power mgmt (6) */
-       0x0000,     /* R14  - Power mgmt (7) */
-       0x0000,     /* R15 */
-       0x0000,     /* R16  - RTC Seconds/Minutes */
-       0x0100,     /* R17  - RTC Hours/Day */
-       0x0101,     /* R18  - RTC Date/Month */
-       0x1400,     /* R19  - RTC Year */
-       0x0000,     /* R20  - Alarm Seconds/Minutes */
-       0x0000,     /* R21  - Alarm Hours/Day */
-       0x0000,     /* R22  - Alarm Date/Month */
-       0x0320,     /* R23  - RTC Time Control */
-       0x0000,     /* R24  - System Interrupts */
-       0x0000,     /* R25  - Interrupt Status 1 */
-       0x0000,     /* R26  - Interrupt Status 2 */
-       0x0000,     /* R27 */
-       0x0000,     /* R28  - Under Voltage Interrupt status */
-       0x0000,     /* R29  - Over Current Interrupt status */
-       0x0000,     /* R30  - GPIO Interrupt Status */
-       0x0000,     /* R31  - Comparator Interrupt Status */
-       0x3FFF,     /* R32  - System Interrupts Mask */
-       0x0000,     /* R33  - Interrupt Status 1 Mask */
-       0x0000,     /* R34  - Interrupt Status 2 Mask */
-       0x0000,     /* R35 */
-       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
-       0x0000,     /* R37  - Over Current Interrupt status Mask */
-       0x0000,     /* R38  - GPIO Interrupt Status Mask */
-       0x0000,     /* R39  - Comparator Interrupt Status Mask */
-       0x0040,     /* R40  - Clock Control 1 */
-       0x0000,     /* R41  - Clock Control 2 */
-       0x3A00,     /* R42  - FLL Control 1 */
-       0x7086,     /* R43  - FLL Control 2 */
-       0xC226,     /* R44  - FLL Control 3 */
-       0x0000,     /* R45  - FLL Control 4 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47 */
-       0x0000,     /* R48  - DAC Control */
-       0x0000,     /* R49 */
-       0x00C0,     /* R50  - DAC Digital Volume L */
-       0x00C0,     /* R51  - DAC Digital Volume R */
-       0x0000,     /* R52 */
-       0x0040,     /* R53  - DAC LR Rate */
-       0x0000,     /* R54  - DAC Clock Control */
-       0x0000,     /* R55 */
-       0x0000,     /* R56 */
-       0x0000,     /* R57 */
-       0x4000,     /* R58  - DAC Mute */
-       0x0000,     /* R59  - DAC Mute Volume */
-       0x0000,     /* R60  - DAC Side */
-       0x0000,     /* R61 */
-       0x0000,     /* R62 */
-       0x0000,     /* R63 */
-       0x8000,     /* R64  - ADC Control */
-       0x0000,     /* R65 */
-       0x00C0,     /* R66  - ADC Digital Volume L */
-       0x00C0,     /* R67  - ADC Digital Volume R */
-       0x0000,     /* R68  - ADC Divider */
-       0x0000,     /* R69 */
-       0x0040,     /* R70  - ADC LR Rate */
-       0x0000,     /* R71 */
-       0x0303,     /* R72  - Input Control */
-       0x0000,     /* R73  - IN3 Input Control */
-       0x0000,     /* R74  - Mic Bias Control */
-       0x0000,     /* R75 */
-       0x0000,     /* R76  - Output Control */
-       0x0000,     /* R77  - Jack Detect */
-       0x0000,     /* R78  - Anti Pop Control */
-       0x0000,     /* R79 */
-       0x0040,     /* R80  - Left Input Volume */
-       0x0040,     /* R81  - Right Input Volume */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87 */
-       0x0800,     /* R88  - Left Mixer Control */
-       0x1000,     /* R89  - Right Mixer Control */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92  - OUT3 Mixer Control */
-       0x0000,     /* R93  - OUT4 Mixer Control */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96  - Output Left Mixer Volume */
-       0x0000,     /* R97  - Output Right Mixer Volume */
-       0x0000,     /* R98  - Input Mixer Volume L */
-       0x0000,     /* R99  - Input Mixer Volume R */
-       0x0000,     /* R100 - Input Mixer Volume */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x00E4,     /* R104 - OUT1L Volume */
-       0x00E4,     /* R105 - OUT1R Volume */
-       0x00E4,     /* R106 - OUT2L Volume */
-       0x02E4,     /* R107 - OUT2R Volume */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 - BEEP Volume */
-       0x0A00,     /* R112 - AI Formating */
-       0x0000,     /* R113 - ADC DAC COMP */
-       0x0020,     /* R114 - AI ADC Control */
-       0x0020,     /* R115 - AI DAC Control */
-       0x0000,     /* R116 */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x1FFF,     /* R128 - GPIO Debounce */
-       0x0000,     /* R129 - GPIO Pin pull up Control */
-       0x0110,     /* R130 - GPIO Pull down Control */
-       0x0000,     /* R131 - GPIO Interrupt Mode */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 - GPIO Control */
-       0x09DA,     /* R134 - GPIO Configuration (i/o) */
-       0x0DD6,     /* R135 - GPIO Pin Polarity / Type */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x1310,     /* R140 - GPIO Function Select 1 */
-       0x0033,     /* R141 - GPIO Function Select 2 */
-       0x2000,     /* R142 - GPIO Function Select 3 */
-       0x0000,     /* R143 - GPIO Function Select 4 */
-       0x0000,     /* R144 - Digitiser Control (1) */
-       0x0002,     /* R145 - Digitiser Control (2) */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x7000,     /* R152 - AUX1 Readback */
-       0x7000,     /* R153 - AUX2 Readback */
-       0x7000,     /* R154 - AUX3 Readback */
-       0x7000,     /* R155 - AUX4 Readback */
-       0x0000,     /* R156 - USB Voltage Readback */
-       0x0000,     /* R157 - LINE Voltage Readback */
-       0x0000,     /* R158 - BATT Voltage Readback */
-       0x0000,     /* R159 - Chip Temp Readback */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 - Generic Comparator Control */
-       0x0000,     /* R164 - Generic comparator 1 */
-       0x0000,     /* R165 - Generic comparator 2 */
-       0x0000,     /* R166 - Generic comparator 3 */
-       0x0000,     /* R167 - Generic comparator 4 */
-       0xA00F,     /* R168 - Battery Charger Control 1 */
-       0x0B06,     /* R169 - Battery Charger Control 2 */
-       0x0000,     /* R170 - Battery Charger Control 3 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Current Sink Driver A */
-       0x0000,     /* R173 - CSA Flash control */
-       0x0000,     /* R174 - Current Sink Driver B */
-       0x0000,     /* R175 - CSB Flash control */
-       0x0000,     /* R176 - DCDC/LDO requested */
-       0x032D,     /* R177 - DCDC Active options */
-       0x0000,     /* R178 - DCDC Sleep options */
-       0x0025,     /* R179 - Power-check comparator */
-       0x000E,     /* R180 - DCDC1 Control */
-       0x0800,     /* R181 - DCDC1 Timeouts */
-       0x1006,     /* R182 - DCDC1 Low Power */
-       0x0018,     /* R183 - DCDC2 Control */
-       0x0000,     /* R184 - DCDC2 Timeouts */
-       0x0000,     /* R185 */
-       0x0056,     /* R186 - DCDC3 Control */
-       0x1800,     /* R187 - DCDC3 Timeouts */
-       0x0006,     /* R188 - DCDC3 Low Power */
-       0x000E,     /* R189 - DCDC4 Control */
-       0x1000,     /* R190 - DCDC4 Timeouts */
-       0x0006,     /* R191 - DCDC4 Low Power */
-       0x0008,     /* R192 - DCDC5 Control */
-       0x0000,     /* R193 - DCDC5 Timeouts */
-       0x0000,     /* R194 */
-       0x0026,     /* R195 - DCDC6 Control */
-       0x0C00,     /* R196 - DCDC6 Timeouts */
-       0x0006,     /* R197 - DCDC6 Low Power */
-       0x0000,     /* R198 */
-       0x0003,     /* R199 - Limit Switch Control */
-       0x001C,     /* R200 - LDO1 Control */
-       0x0000,     /* R201 - LDO1 Timeouts */
-       0x001C,     /* R202 - LDO1 Low Power */
-       0x0006,     /* R203 - LDO2 Control */
-       0x0400,     /* R204 - LDO2 Timeouts */
-       0x001C,     /* R205 - LDO2 Low Power */
-       0x001C,     /* R206 - LDO3 Control */
-       0x1400,     /* R207 - LDO3 Timeouts */
-       0x001C,     /* R208 - LDO3 Low Power */
-       0x001A,     /* R209 - LDO4 Control */
-       0x0000,     /* R210 - LDO4 Timeouts */
-       0x001C,     /* R211 - LDO4 Low Power */
-       0x0000,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 - VCC_FAULT Masks */
-       0x001F,     /* R216 - Main Bandgap Control */
-       0x0000,     /* R217 - OSC Control */
-       0x9000,     /* R218 - RTC Tick Control */
-       0x0000,     /* R219 - Security1 */
-       0x4000,     /* R220 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0000,     /* R223 */
-       0x0000,     /* R224 - Signal overrides */
-       0x0000,     /* R225 - DCDC/LDO status */
-       0x0000,     /* R226 - Charger Overides/status */
-       0x0000,     /* R227 - misc overrides */
-       0x0000,     /* R228 - Supply overrides/status 1 */
-       0x0000,     /* R229 - Supply overrides/status 2 */
-       0xE000,     /* R230 - GPIO Pin Status */
-       0x0000,     /* R231 - comparotor overrides */
-       0x0000,     /* R232 */
-       0x0000,     /* R233 - State Machine status */
-       0x1200,     /* R234 */
-       0x0000,     /* R235 */
-       0x8000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0000,     /* R238 */
-       0x0000,     /* R239 */
-       0x0003,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0004,     /* R243 */
-       0x0300,     /* R244 */
-       0x0000,     /* R245 */
-       0x0200,     /* R246 */
-       0x0000,     /* R247 */
-       0x1000,     /* R248 - DCDC1 Test Controls */
-       0x5000,     /* R249 */
-       0x1000,     /* R250 - DCDC3 Test Controls */
-       0x1000,     /* R251 - DCDC4 Test Controls */
-       0x5100,     /* R252 */
-       0x1000,     /* R253 - DCDC6 Test Controls */
-};
-#endif
-
-#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_3
-
-#undef WM8350_HAVE_CONFIG_MODE
-#define WM8350_HAVE_CONFIG_MODE
-
-const u16 wm8352_mode3_defaults[] = {
-       0x6143,     /* R0   - Reset/ID */
-       0x0000,     /* R1   - ID */
-       0x0002,     /* R2   - Revision */
-       0x1C02,     /* R3   - System Control 1 */
-       0x0204,     /* R4   - System Control 2 */
-       0x0000,     /* R5   - System Hibernate */
-       0x8A00,     /* R6   - Interface Control */
-       0x0000,     /* R7 */
-       0x8000,     /* R8   - Power mgmt (1) */
-       0x0000,     /* R9   - Power mgmt (2) */
-       0x0000,     /* R10  - Power mgmt (3) */
-       0x2000,     /* R11  - Power mgmt (4) */
-       0x0E00,     /* R12  - Power mgmt (5) */
-       0x0000,     /* R13  - Power mgmt (6) */
-       0x0000,     /* R14  - Power mgmt (7) */
-       0x0000,     /* R15 */
-       0x0000,     /* R16  - RTC Seconds/Minutes */
-       0x0100,     /* R17  - RTC Hours/Day */
-       0x0101,     /* R18  - RTC Date/Month */
-       0x1400,     /* R19  - RTC Year */
-       0x0000,     /* R20  - Alarm Seconds/Minutes */
-       0x0000,     /* R21  - Alarm Hours/Day */
-       0x0000,     /* R22  - Alarm Date/Month */
-       0x0320,     /* R23  - RTC Time Control */
-       0x0000,     /* R24  - System Interrupts */
-       0x0000,     /* R25  - Interrupt Status 1 */
-       0x0000,     /* R26  - Interrupt Status 2 */
-       0x0000,     /* R27 */
-       0x0000,     /* R28  - Under Voltage Interrupt status */
-       0x0000,     /* R29  - Over Current Interrupt status */
-       0x0000,     /* R30  - GPIO Interrupt Status */
-       0x0000,     /* R31  - Comparator Interrupt Status */
-       0x3FFF,     /* R32  - System Interrupts Mask */
-       0x0000,     /* R33  - Interrupt Status 1 Mask */
-       0x0000,     /* R34  - Interrupt Status 2 Mask */
-       0x0000,     /* R35 */
-       0x0000,     /* R36  - Under Voltage Interrupt status Mask */
-       0x0000,     /* R37  - Over Current Interrupt status Mask */
-       0x0000,     /* R38  - GPIO Interrupt Status Mask */
-       0x0000,     /* R39  - Comparator Interrupt Status Mask */
-       0x0040,     /* R40  - Clock Control 1 */
-       0x0000,     /* R41  - Clock Control 2 */
-       0x3A00,     /* R42  - FLL Control 1 */
-       0x7086,     /* R43  - FLL Control 2 */
-       0xC226,     /* R44  - FLL Control 3 */
-       0x0000,     /* R45  - FLL Control 4 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47 */
-       0x0000,     /* R48  - DAC Control */
-       0x0000,     /* R49 */
-       0x00C0,     /* R50  - DAC Digital Volume L */
-       0x00C0,     /* R51  - DAC Digital Volume R */
-       0x0000,     /* R52 */
-       0x0040,     /* R53  - DAC LR Rate */
-       0x0000,     /* R54  - DAC Clock Control */
-       0x0000,     /* R55 */
-       0x0000,     /* R56 */
-       0x0000,     /* R57 */
-       0x4000,     /* R58  - DAC Mute */
-       0x0000,     /* R59  - DAC Mute Volume */
-       0x0000,     /* R60  - DAC Side */
-       0x0000,     /* R61 */
-       0x0000,     /* R62 */
-       0x0000,     /* R63 */
-       0x8000,     /* R64  - ADC Control */
-       0x0000,     /* R65 */
-       0x00C0,     /* R66  - ADC Digital Volume L */
-       0x00C0,     /* R67  - ADC Digital Volume R */
-       0x0000,     /* R68  - ADC Divider */
-       0x0000,     /* R69 */
-       0x0040,     /* R70  - ADC LR Rate */
-       0x0000,     /* R71 */
-       0x0303,     /* R72  - Input Control */
-       0x0000,     /* R73  - IN3 Input Control */
-       0x0000,     /* R74  - Mic Bias Control */
-       0x0000,     /* R75 */
-       0x0000,     /* R76  - Output Control */
-       0x0000,     /* R77  - Jack Detect */
-       0x0000,     /* R78  - Anti Pop Control */
-       0x0000,     /* R79 */
-       0x0040,     /* R80  - Left Input Volume */
-       0x0040,     /* R81  - Right Input Volume */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87 */
-       0x0800,     /* R88  - Left Mixer Control */
-       0x1000,     /* R89  - Right Mixer Control */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92  - OUT3 Mixer Control */
-       0x0000,     /* R93  - OUT4 Mixer Control */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96  - Output Left Mixer Volume */
-       0x0000,     /* R97  - Output Right Mixer Volume */
-       0x0000,     /* R98  - Input Mixer Volume L */
-       0x0000,     /* R99  - Input Mixer Volume R */
-       0x0000,     /* R100 - Input Mixer Volume */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x00E4,     /* R104 - OUT1L Volume */
-       0x00E4,     /* R105 - OUT1R Volume */
-       0x00E4,     /* R106 - OUT2L Volume */
-       0x02E4,     /* R107 - OUT2R Volume */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 - BEEP Volume */
-       0x0A00,     /* R112 - AI Formating */
-       0x0000,     /* R113 - ADC DAC COMP */
-       0x0020,     /* R114 - AI ADC Control */
-       0x0020,     /* R115 - AI DAC Control */
-       0x0000,     /* R116 */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x1FFF,     /* R128 - GPIO Debounce */
-       0x0010,     /* R129 - GPIO Pin pull up Control */
-       0x0000,     /* R130 - GPIO Pull down Control */
-       0x0000,     /* R131 - GPIO Interrupt Mode */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 - GPIO Control */
-       0x0BFB,     /* R134 - GPIO Configuration (i/o) */
-       0x0FFD,     /* R135 - GPIO Pin Polarity / Type */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x0310,     /* R140 - GPIO Function Select 1 */
-       0x0001,     /* R141 - GPIO Function Select 2 */
-       0x2300,     /* R142 - GPIO Function Select 3 */
-       0x0003,     /* R143 - GPIO Function Select 4 */
-       0x0000,     /* R144 - Digitiser Control (1) */
-       0x0002,     /* R145 - Digitiser Control (2) */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x7000,     /* R152 - AUX1 Readback */
-       0x7000,     /* R153 - AUX2 Readback */
-       0x7000,     /* R154 - AUX3 Readback */
-       0x7000,     /* R155 - AUX4 Readback */
-       0x0000,     /* R156 - USB Voltage Readback */
-       0x0000,     /* R157 - LINE Voltage Readback */
-       0x0000,     /* R158 - BATT Voltage Readback */
-       0x0000,     /* R159 - Chip Temp Readback */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 - Generic Comparator Control */
-       0x0000,     /* R164 - Generic comparator 1 */
-       0x0000,     /* R165 - Generic comparator 2 */
-       0x0000,     /* R166 - Generic comparator 3 */
-       0x0000,     /* R167 - Generic comparator 4 */
-       0xA00F,     /* R168 - Battery Charger Control 1 */
-       0x0B06,     /* R169 - Battery Charger Control 2 */
-       0x0000,     /* R170 - Battery Charger Control 3 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Current Sink Driver A */
-       0x0000,     /* R173 - CSA Flash control */
-       0x0000,     /* R174 - Current Sink Driver B */
-       0x0000,     /* R175 - CSB Flash control */
-       0x0000,     /* R176 - DCDC/LDO requested */
-       0x032D,     /* R177 - DCDC Active options */
-       0x0000,     /* R178 - DCDC Sleep options */
-       0x0025,     /* R179 - Power-check comparator */
-       0x0006,     /* R180 - DCDC1 Control */
-       0x0400,     /* R181 - DCDC1 Timeouts */
-       0x1006,     /* R182 - DCDC1 Low Power */
-       0x0018,     /* R183 - DCDC2 Control */
-       0x0000,     /* R184 - DCDC2 Timeouts */
-       0x0000,     /* R185 */
-       0x0050,     /* R186 - DCDC3 Control */
-       0x0C00,     /* R187 - DCDC3 Timeouts */
-       0x0006,     /* R188 - DCDC3 Low Power */
-       0x000E,     /* R189 - DCDC4 Control */
-       0x0400,     /* R190 - DCDC4 Timeouts */
-       0x0006,     /* R191 - DCDC4 Low Power */
-       0x0008,     /* R192 - DCDC5 Control */
-       0x0000,     /* R193 - DCDC5 Timeouts */
-       0x0000,     /* R194 */
-       0x0029,     /* R195 - DCDC6 Control */
-       0x0800,     /* R196 - DCDC6 Timeouts */
-       0x0006,     /* R197 - DCDC6 Low Power */
-       0x0000,     /* R198 */
-       0x0003,     /* R199 - Limit Switch Control */
-       0x001D,     /* R200 - LDO1 Control */
-       0x1000,     /* R201 - LDO1 Timeouts */
-       0x001C,     /* R202 - LDO1 Low Power */
-       0x0017,     /* R203 - LDO2 Control */
-       0x1000,     /* R204 - LDO2 Timeouts */
-       0x001C,     /* R205 - LDO2 Low Power */
-       0x0006,     /* R206 - LDO3 Control */
-       0x1000,     /* R207 - LDO3 Timeouts */
-       0x001C,     /* R208 - LDO3 Low Power */
-       0x0010,     /* R209 - LDO4 Control */
-       0x1000,     /* R210 - LDO4 Timeouts */
-       0x001C,     /* R211 - LDO4 Low Power */
-       0x0000,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 - VCC_FAULT Masks */
-       0x001F,     /* R216 - Main Bandgap Control */
-       0x0000,     /* R217 - OSC Control */
-       0x9000,     /* R218 - RTC Tick Control */
-       0x0000,     /* R219 - Security1 */
-       0x4000,     /* R220 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0000,     /* R223 */
-       0x0000,     /* R224 - Signal overrides */
-       0x0000,     /* R225 - DCDC/LDO status */
-       0x0000,     /* R226 - Charger Overides/status */
-       0x0000,     /* R227 - misc overrides */
-       0x0000,     /* R228 - Supply overrides/status 1 */
-       0x0000,     /* R229 - Supply overrides/status 2 */
-       0xE000,     /* R230 - GPIO Pin Status */
-       0x0000,     /* R231 - comparotor overrides */
-       0x0000,     /* R232 */
-       0x0000,     /* R233 - State Machine status */
-       0x1200,     /* R234 */
-       0x0000,     /* R235 */
-       0x8000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0000,     /* R238 */
-       0x0000,     /* R239 */
-       0x0003,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0004,     /* R243 */
-       0x0300,     /* R244 */
-       0x0000,     /* R245 */
-       0x0200,     /* R246 */
-       0x0000,     /* R247 */
-       0x1000,     /* R248 - DCDC1 Test Controls */
-       0x5000,     /* R249 */
-       0x1000,     /* R250 - DCDC3 Test Controls */
-       0x1000,     /* R251 - DCDC4 Test Controls */
-       0x5100,     /* R252 */
-       0x1000,     /* R253 - DCDC6 Test Controls */
-};
-#endif
-
 /*
  * Access masks.
  */
 
-const struct wm8350_reg_access wm8350_reg_io_map[] = {
+static const struct wm8350_reg_access {
+       u16 readable;           /* Mask of readable bits */
+       u16 writable;           /* Mask of writable bits */
+       u16 vol;                /* Mask of volatile bits */
+} wm8350_reg_io_map[] = {
        /*  read    write volatile */
-       { 0xFFFF, 0xFFFF, 0xFFFF }, /* R0   - Reset/ID */
-       { 0x7CFF, 0x0C00, 0x7FFF }, /* R1   - ID */
+       { 0xFFFF, 0xFFFF, 0x0000 }, /* R0   - Reset/ID */
+       { 0x7CFF, 0x0C00, 0x0000 }, /* R1   - ID */
        { 0x007F, 0x0000, 0x0000 }, /* R2   - ROM Mask ID */
        { 0xBE3B, 0xBE3B, 0x8000 }, /* R3   - System Control 1 */
        { 0xFEF7, 0xFEF7, 0xF800 }, /* R4   - System Control 2 */
@@ -3433,3 +281,59 @@ const struct wm8350_reg_access wm8350_reg_io_map[] = {
        { 0x0000, 0x0000, 0x0000 }, /* R254 */
        { 0x0000, 0x0000, 0x0000 }, /* R255 */
 };
+
+static bool wm8350_readable(struct device *dev, unsigned int reg)
+{
+       return wm8350_reg_io_map[reg].readable;
+}
+
+static bool wm8350_writeable(struct device *dev, unsigned int reg)
+{
+       struct wm8350 *wm8350 = dev_get_drvdata(dev);
+
+       if (!wm8350->unlocked) {
+               if ((reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
+                    reg <= WM8350_GPIO_FUNCTION_SELECT_4) ||
+                   (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 &&
+                    reg <= WM8350_BATTERY_CHARGER_CONTROL_3))
+                       return false;
+       }
+
+       return wm8350_reg_io_map[reg].writable;
+}
+
+static bool wm8350_volatile(struct device *dev, unsigned int reg)
+{
+       return wm8350_reg_io_map[reg].vol;
+}
+
+static bool wm8350_precious(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8350_SYSTEM_INTERRUPTS:
+       case WM8350_INT_STATUS_1:
+       case WM8350_INT_STATUS_2:
+       case WM8350_POWER_UP_INT_STATUS:
+       case WM8350_UNDER_VOLTAGE_INT_STATUS:
+       case WM8350_OVER_CURRENT_INT_STATUS:
+       case WM8350_GPIO_INT_STATUS:
+       case WM8350_COMPARATOR_INT_STATUS:
+               return true;
+
+       default:
+               return false;
+       }
+}
+
+const struct regmap_config wm8350_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+
+       .cache_type = REGCACHE_RBTREE,
+
+       .max_register = WM8350_MAX_REGISTER,
+       .readable_reg = wm8350_readable,
+       .writeable_reg = wm8350_writeable,
+       .volatile_reg = wm8350_volatile,
+       .precious_reg = wm8350_precious,
+};
index 1e321d349777199dad0bdd050288f72af60917a6..eec74aa55fdfe28c46476c3360e1632bfd51cf7f 100644 (file)
@@ -283,9 +283,24 @@ static int wm8994_suspend(struct device *dev)
        wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET,
                         wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET));
 
-       regcache_cache_only(wm8994->regmap, true);
        regcache_mark_dirty(wm8994->regmap);
 
+       /* Restore GPIO registers to prevent problems with mismatched
+        * pin configurations.
+        */
+       ret = regcache_sync_region(wm8994->regmap, WM8994_GPIO_1,
+                                  WM8994_GPIO_11);
+       if (ret != 0)
+               dev_err(dev, "Failed to restore GPIO registers: %d\n", ret);
+
+       /* In case one of the GPIOs is used as a wake input. */
+       ret = regcache_sync_region(wm8994->regmap,
+                                  WM8994_INTERRUPT_STATUS_1_MASK,
+                                  WM8994_INTERRUPT_STATUS_1_MASK);
+       if (ret != 0)
+               dev_err(dev, "Failed to restore interrupt mask: %d\n", ret);
+
+       regcache_cache_only(wm8994->regmap, true);
        wm8994->suspended = true;
 
        ret = regulator_bulk_disable(wm8994->num_supplies,
index f1837f669755d4671615cb7a109e4d69ea827d21..0aac4aff17a5f6cf4d66144883608157a720d7ed 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/regmap.h>
 
 #include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/pdata.h>
 #include <linux/mfd/wm8994/registers.h>
 
 #include <linux/delay.h>
@@ -139,6 +140,8 @@ static struct regmap_irq_chip wm8994_irq_chip = {
 int wm8994_irq_init(struct wm8994 *wm8994)
 {
        int ret;
+       unsigned long irqflags;
+       struct wm8994_pdata *pdata = wm8994->dev->platform_data;
 
        if (!wm8994->irq) {
                dev_warn(wm8994->dev,
@@ -147,8 +150,13 @@ int wm8994_irq_init(struct wm8994 *wm8994)
                return 0;
        }
 
+       /* select user or default irq flags */
+       irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
+       if (pdata->irq_flags)
+               irqflags = pdata->irq_flags;
+
        ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
-                                 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                                 irqflags,
                                  wm8994->irq_base, &wm8994_irq_chip,
                                  &wm8994->irq_data);
        if (ret != 0) {
index 154f3ef076313f44008167eb94267239fda7cbaa..98a442da892a23ae21f19f1ef548b536bac9ede4 100644 (file)
@@ -64,6 +64,7 @@ config AB8500_PWM
        bool "AB8500 PWM support"
        depends on AB8500_CORE && ARCH_U8500
        select HAVE_PWM
+       depends on !PWM
        help
          This driver exports functions to enable/disble/config/free Pulse
          Width Modulation in the Analog Baseband Chip AB8500.
index 042a8fe4efaabd2ab57db4299275c19750cad23d..d7a9aa14e5d5aafd8c0efc907b127147a202d197 100644 (file)
@@ -142,16 +142,10 @@ static int __devexit ab8500_pwm_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id ab8500_pwm_match[] = {
-       { .compatible = "stericsson,ab8500-pwm", },
-       {}
-};
-
 static struct platform_driver ab8500_pwm_driver = {
        .driver = {
                .name = "ab8500-pwm",
                .owner = THIS_MODULE,
-               .of_match_table = ab8500_pwm_match,
        },
        .probe = ab8500_pwm_probe,
        .remove = __devexit_p(ab8500_pwm_remove),
index 28adefe70f96274c93198ee50acc9ee65adec1ae..08aad69c8da4e3f4d8572d52eadd46c00bb65941 100644 (file)
@@ -477,6 +477,8 @@ static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf,
        int i, n, out;
 
        buf = (char *)__get_free_page(GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
 
        n = snprintf(buf, PAGE_SIZE, "Available crash types:\n");
        for (i = 0; i < ARRAY_SIZE(cp_type); i++)
index 2b62232c2c6a3476551f11f86253dcf545234d07..acfaeeb9e01a98e7f296d5c2081f35ef4d53b325 100644 (file)
@@ -349,6 +349,11 @@ void st_int_recv(void *disc_data,
                        st_gdata->rx_skb = alloc_skb(
                                        st_gdata->list[type]->max_frame_size,
                                        GFP_ATOMIC);
+                       if (st_gdata->rx_skb == NULL) {
+                               pr_err("out of memory: dropping\n");
+                               goto done;
+                       }
+
                        skb_reserve(st_gdata->rx_skb,
                                        st_gdata->list[type]->reserve);
                        /* next 2 required for BT only */
index a6fa884ae49bb08deba807ae6aeca7f0fcbabff7..100b6775e175f9bafb62b868de4710b07c338637 100644 (file)
 
 #define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1)
 #define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1)
+#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa
 
-#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
 #define JZ_NAND_MEM_CMD_OFFSET 0x08000
+#define JZ_NAND_MEM_ADDR_OFFSET 0x10000
 
 struct jz_nand {
        struct mtd_info mtd;
@@ -62,8 +63,11 @@ struct jz_nand {
        void __iomem *base;
        struct resource *mem;
 
-       void __iomem *bank_base;
-       struct resource *bank_mem;
+       unsigned char banks[JZ_NAND_NUM_BANKS];
+       void __iomem *bank_base[JZ_NAND_NUM_BANKS];
+       struct resource *bank_mem[JZ_NAND_NUM_BANKS];
+
+       int selected_bank;
 
        struct jz_nand_platform_data *pdata;
        bool is_reading;
@@ -74,26 +78,50 @@ static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
        return container_of(mtd, struct jz_nand, mtd);
 }
 
+static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr)
+{
+       struct jz_nand *nand = mtd_to_jz_nand(mtd);
+       struct nand_chip *chip = mtd->priv;
+       uint32_t ctrl;
+       int banknr;
+
+       ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
+       ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK;
+
+       if (chipnr == -1) {
+               banknr = -1;
+       } else {
+               banknr = nand->banks[chipnr] - 1;
+               chip->IO_ADDR_R = nand->bank_base[banknr];
+               chip->IO_ADDR_W = nand->bank_base[banknr];
+       }
+       writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+
+       nand->selected_bank = banknr;
+}
+
 static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
 {
        struct jz_nand *nand = mtd_to_jz_nand(mtd);
        struct nand_chip *chip = mtd->priv;
        uint32_t reg;
+       void __iomem *bank_base = nand->bank_base[nand->selected_bank];
+
+       BUG_ON(nand->selected_bank < 0);
 
        if (ctrl & NAND_CTRL_CHANGE) {
                BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
                if (ctrl & NAND_ALE)
-                       chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_ADDR_OFFSET;
+                       bank_base += JZ_NAND_MEM_ADDR_OFFSET;
                else if (ctrl & NAND_CLE)
-                       chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_CMD_OFFSET;
-               else
-                       chip->IO_ADDR_W = nand->bank_base;
+                       bank_base += JZ_NAND_MEM_CMD_OFFSET;
+               chip->IO_ADDR_W = bank_base;
 
                reg = readl(nand->base + JZ_REG_NAND_CTRL);
                if (ctrl & NAND_NCE)
-                       reg |= JZ_NAND_CTRL_ASSERT_CHIP(0);
+                       reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
                else
-                       reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0);
+                       reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank);
                writel(reg, nand->base + JZ_REG_NAND_CTRL);
        }
        if (dat != NAND_CMD_NONE)
@@ -252,7 +280,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
 }
 
 static int jz_nand_ioremap_resource(struct platform_device *pdev,
-       const char *name, struct resource **res, void __iomem **base)
+       const char *name, struct resource **res, void *__iomem *base)
 {
        int ret;
 
@@ -288,6 +316,90 @@ err:
        return ret;
 }
 
+static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base)
+{
+       iounmap(base);
+       release_mem_region(res->start, resource_size(res));
+}
+
+static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) {
+       int ret;
+       int gpio;
+       char gpio_name[9];
+       char res_name[6];
+       uint32_t ctrl;
+       struct mtd_info *mtd = &nand->mtd;
+       struct nand_chip *chip = &nand->chip;
+
+       /* Request GPIO port. */
+       gpio = JZ_GPIO_MEM_CS0 + bank - 1;
+       sprintf(gpio_name, "NAND CS%d", bank);
+       ret = gpio_request(gpio, gpio_name);
+       if (ret) {
+               dev_warn(&pdev->dev,
+                       "Failed to request %s gpio %d: %d\n",
+                       gpio_name, gpio, ret);
+               goto notfound_gpio;
+       }
+
+       /* Request I/O resource. */
+       sprintf(res_name, "bank%d", bank);
+       ret = jz_nand_ioremap_resource(pdev, res_name,
+                                       &nand->bank_mem[bank - 1],
+                                       &nand->bank_base[bank - 1]);
+       if (ret)
+               goto notfound_resource;
+
+       /* Enable chip in bank. */
+       jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0);
+       ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
+       ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
+       writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+
+       if (chipnr == 0) {
+               /* Detect first chip. */
+               ret = nand_scan_ident(mtd, 1, NULL);
+               if (ret)
+                       goto notfound_id;
+
+               /* Retrieve the IDs from the first chip. */
+               chip->select_chip(mtd, 0);
+               chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+               chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+               *nand_maf_id = chip->read_byte(mtd);
+               *nand_dev_id = chip->read_byte(mtd);
+       } else {
+               /* Detect additional chip. */
+               chip->select_chip(mtd, chipnr);
+               chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+               chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+               if (*nand_maf_id != chip->read_byte(mtd)
+                || *nand_dev_id != chip->read_byte(mtd)) {
+                       ret = -ENODEV;
+                       goto notfound_id;
+               }
+
+               /* Update size of the MTD. */
+               chip->numchips++;
+               mtd->size += chip->chipsize;
+       }
+
+       dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank);
+       return 0;
+
+notfound_id:
+       dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
+       ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
+       writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
+       jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
+       jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+                                nand->bank_base[bank - 1]);
+notfound_resource:
+       gpio_free(gpio);
+notfound_gpio:
+       return ret;
+}
+
 static int __devinit jz_nand_probe(struct platform_device *pdev)
 {
        int ret;
@@ -295,6 +407,8 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
        struct nand_chip *chip;
        struct mtd_info *mtd;
        struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
+       size_t chipnr, bank_idx;
+       uint8_t nand_maf_id = 0, nand_dev_id = 0;
 
        nand = kzalloc(sizeof(*nand), GFP_KERNEL);
        if (!nand) {
@@ -305,10 +419,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
        ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
        if (ret)
                goto err_free;
-       ret = jz_nand_ioremap_resource(pdev, "bank", &nand->bank_mem,
-                       &nand->bank_base);
-       if (ret)
-               goto err_iounmap_mmio;
 
        if (pdata && gpio_is_valid(pdata->busy_gpio)) {
                ret = gpio_request(pdata->busy_gpio, "NAND busy pin");
@@ -316,7 +426,7 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev,
                                "Failed to request busy gpio %d: %d\n",
                                pdata->busy_gpio, ret);
-                       goto err_iounmap_mem;
+                       goto err_iounmap_mmio;
                }
        }
 
@@ -339,22 +449,51 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
 
        chip->chip_delay = 50;
        chip->cmd_ctrl = jz_nand_cmd_ctrl;
+       chip->select_chip = jz_nand_select_chip;
 
        if (pdata && gpio_is_valid(pdata->busy_gpio))
                chip->dev_ready = jz_nand_dev_ready;
 
-       chip->IO_ADDR_R = nand->bank_base;
-       chip->IO_ADDR_W = nand->bank_base;
-
        nand->pdata = pdata;
        platform_set_drvdata(pdev, nand);
 
-       writel(JZ_NAND_CTRL_ENABLE_CHIP(0), nand->base + JZ_REG_NAND_CTRL);
-
-       ret = nand_scan_ident(mtd, 1, NULL);
-       if (ret) {
-               dev_err(&pdev->dev,  "Failed to scan nand\n");
-               goto err_gpio_free;
+       /* We are going to autodetect NAND chips in the banks specified in the
+        * platform data. Although nand_scan_ident() can detect multiple chips,
+        * it requires those chips to be numbered consecuitively, which is not
+        * always the case for external memory banks. And a fixed chip-to-bank
+        * mapping is not practical either, since for example Dingoo units
+        * produced at different times have NAND chips in different banks.
+        */
+       chipnr = 0;
+       for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) {
+               unsigned char bank;
+
+               /* If there is no platform data, look for NAND in bank 1,
+                * which is the most likely bank since it is the only one
+                * that can be booted from.
+                */
+               bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1;
+               if (bank == 0)
+                       break;
+               if (bank > JZ_NAND_NUM_BANKS) {
+                       dev_warn(&pdev->dev,
+                               "Skipping non-existing bank: %d\n", bank);
+                       continue;
+               }
+               /* The detection routine will directly or indirectly call
+                * jz_nand_select_chip(), so nand->banks has to contain the
+                * bank we're checking.
+                */
+               nand->banks[chipnr] = bank;
+               if (jz_nand_detect_bank(pdev, nand, bank, chipnr,
+                                       &nand_maf_id, &nand_dev_id) == 0)
+                       chipnr++;
+               else
+                       nand->banks[chipnr] = 0;
+       }
+       if (chipnr == 0) {
+               dev_err(&pdev->dev, "No NAND chips found\n");
+               goto err_gpio_busy;
        }
 
        if (pdata && pdata->ident_callback) {
@@ -364,8 +503,8 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
 
        ret = nand_scan_tail(mtd);
        if (ret) {
-               dev_err(&pdev->dev,  "Failed to scan nand\n");
-               goto err_gpio_free;
+               dev_err(&pdev->dev,  "Failed to scan NAND\n");
+               goto err_unclaim_banks;
        }
 
        ret = mtd_device_parse_register(mtd, NULL, NULL,
@@ -382,14 +521,21 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
        return 0;
 
 err_nand_release:
-       nand_release(&nand->mtd);
-err_gpio_free:
+       nand_release(mtd);
+err_unclaim_banks:
+       while (chipnr--) {
+               unsigned char bank = nand->banks[chipnr];
+               gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
+               jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+                                        nand->bank_base[bank - 1]);
+       }
+       writel(0, nand->base + JZ_REG_NAND_CTRL);
+err_gpio_busy:
+       if (pdata && gpio_is_valid(pdata->busy_gpio))
+               gpio_free(pdata->busy_gpio);
        platform_set_drvdata(pdev, NULL);
-       gpio_free(pdata->busy_gpio);
-err_iounmap_mem:
-       iounmap(nand->bank_base);
 err_iounmap_mmio:
-       iounmap(nand->base);
+       jz_nand_iounmap_resource(nand->mem, nand->base);
 err_free:
        kfree(nand);
        return ret;
@@ -398,16 +544,26 @@ err_free:
 static int __devexit jz_nand_remove(struct platform_device *pdev)
 {
        struct jz_nand *nand = platform_get_drvdata(pdev);
+       struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
+       size_t i;
 
        nand_release(&nand->mtd);
 
        /* Deassert and disable all chips */
        writel(0, nand->base + JZ_REG_NAND_CTRL);
 
-       iounmap(nand->bank_base);
-       release_mem_region(nand->bank_mem->start, resource_size(nand->bank_mem));
-       iounmap(nand->base);
-       release_mem_region(nand->mem->start, resource_size(nand->mem));
+       for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) {
+               unsigned char bank = nand->banks[i];
+               if (bank != 0) {
+                       jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
+                                                nand->bank_base[bank - 1]);
+                       gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
+               }
+       }
+       if (pdata && gpio_is_valid(pdata->busy_gpio))
+               gpio_free(pdata->busy_gpio);
+
+       jz_nand_iounmap_resource(nand->mem, nand->base);
 
        platform_set_drvdata(pdev, NULL);
        kfree(nand);
index f0921d16f0a941ff5049fd8ce18dff6c379b76f9..6ff7ad006c300b5a9c499e6bf3465e4cb8b7f2bc 100644 (file)
@@ -74,7 +74,6 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
        const struct platform_device_id *id;
        struct resource *mem;
        int irq;
-#ifdef CONFIG_HAVE_CLK
        struct clk *clk;
 
        /* get the appropriate clk */
@@ -84,7 +83,6 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
                ret = -ENODEV;
                goto exit;
        }
-#endif
 
        /* get the platform data */
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -145,10 +143,8 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
 
        dev->irq = irq;
        priv->base = addr;
-#ifdef CONFIG_HAVE_CLK
        priv->can.clock.freq = clk_get_rate(clk);
        priv->priv = clk;
-#endif
 
        platform_set_drvdata(pdev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
@@ -172,10 +168,8 @@ exit_iounmap:
 exit_release_mem:
        release_mem_region(mem->start, resource_size(mem));
 exit_free_clk:
-#ifdef CONFIG_HAVE_CLK
        clk_put(clk);
 exit:
-#endif
        dev_err(&pdev->dev, "probe failed\n");
 
        return ret;
@@ -196,9 +190,7 @@ static int __devexit c_can_plat_remove(struct platform_device *pdev)
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(mem->start, resource_size(mem));
 
-#ifdef CONFIG_HAVE_CLK
        clk_put(priv->priv);
-#endif
 
        return 0;
 }
index cd827ff4a021f74284574f75cc27de97b4c3e7fe..c42bbb16cdaebdeb7147dc887705abcfe91e86e0 100644 (file)
@@ -6,19 +6,21 @@
  * Copyright (C) 2009 Cavium Networks
  */
 
-#include <linux/capability.h>
+#include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/capability.h>
 #include <linux/interrupt.h>
-#include <linux/platform_device.h>
 #include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if.h>
+#include <linux/spinlock.h>
 #include <linux/if_vlan.h>
+#include <linux/of_mdio.h>
+#include <linux/module.h>
+#include <linux/of_net.h>
+#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/phy.h>
-#include <linux/spinlock.h>
+#include <linux/io.h>
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-mixx-defs.h>
@@ -58,8 +60,56 @@ union mgmt_port_ring_entry {
        } s;
 };
 
+#define MIX_ORING1     0x0
+#define MIX_ORING2     0x8
+#define MIX_IRING1     0x10
+#define MIX_IRING2     0x18
+#define MIX_CTL                0x20
+#define MIX_IRHWM      0x28
+#define MIX_IRCNT      0x30
+#define MIX_ORHWM      0x38
+#define MIX_ORCNT      0x40
+#define MIX_ISR                0x48
+#define MIX_INTENA     0x50
+#define MIX_REMCNT     0x58
+#define MIX_BIST       0x78
+
+#define AGL_GMX_PRT_CFG                        0x10
+#define AGL_GMX_RX_FRM_CTL             0x18
+#define AGL_GMX_RX_FRM_MAX             0x30
+#define AGL_GMX_RX_JABBER              0x38
+#define AGL_GMX_RX_STATS_CTL           0x50
+
+#define AGL_GMX_RX_STATS_PKTS_DRP      0xb0
+#define AGL_GMX_RX_STATS_OCTS_DRP      0xb8
+#define AGL_GMX_RX_STATS_PKTS_BAD      0xc0
+
+#define AGL_GMX_RX_ADR_CTL             0x100
+#define AGL_GMX_RX_ADR_CAM_EN          0x108
+#define AGL_GMX_RX_ADR_CAM0            0x180
+#define AGL_GMX_RX_ADR_CAM1            0x188
+#define AGL_GMX_RX_ADR_CAM2            0x190
+#define AGL_GMX_RX_ADR_CAM3            0x198
+#define AGL_GMX_RX_ADR_CAM4            0x1a0
+#define AGL_GMX_RX_ADR_CAM5            0x1a8
+
+#define AGL_GMX_TX_STATS_CTL           0x268
+#define AGL_GMX_TX_CTL                 0x270
+#define AGL_GMX_TX_STAT0               0x280
+#define AGL_GMX_TX_STAT1               0x288
+#define AGL_GMX_TX_STAT2               0x290
+#define AGL_GMX_TX_STAT3               0x298
+#define AGL_GMX_TX_STAT4               0x2a0
+#define AGL_GMX_TX_STAT5               0x2a8
+#define AGL_GMX_TX_STAT6               0x2b0
+#define AGL_GMX_TX_STAT7               0x2b8
+#define AGL_GMX_TX_STAT8               0x2c0
+#define AGL_GMX_TX_STAT9               0x2c8
+
 struct octeon_mgmt {
        struct net_device *netdev;
+       u64 mix;
+       u64 agl;
        int port;
        int irq;
        u64 *tx_ring;
@@ -85,31 +135,34 @@ struct octeon_mgmt {
        struct napi_struct napi;
        struct tasklet_struct tx_clean_tasklet;
        struct phy_device *phydev;
+       struct device_node *phy_np;
+       resource_size_t mix_phys;
+       resource_size_t mix_size;
+       resource_size_t agl_phys;
+       resource_size_t agl_size;
 };
 
 static void octeon_mgmt_set_rx_irq(struct octeon_mgmt *p, int enable)
 {
-       int port = p->port;
        union cvmx_mixx_intena mix_intena;
        unsigned long flags;
 
        spin_lock_irqsave(&p->lock, flags);
-       mix_intena.u64 = cvmx_read_csr(CVMX_MIXX_INTENA(port));
+       mix_intena.u64 = cvmx_read_csr(p->mix + MIX_INTENA);
        mix_intena.s.ithena = enable ? 1 : 0;
-       cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64);
+       cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64);
        spin_unlock_irqrestore(&p->lock, flags);
 }
 
 static void octeon_mgmt_set_tx_irq(struct octeon_mgmt *p, int enable)
 {
-       int port = p->port;
        union cvmx_mixx_intena mix_intena;
        unsigned long flags;
 
        spin_lock_irqsave(&p->lock, flags);
-       mix_intena.u64 = cvmx_read_csr(CVMX_MIXX_INTENA(port));
+       mix_intena.u64 = cvmx_read_csr(p->mix + MIX_INTENA);
        mix_intena.s.othena = enable ? 1 : 0;
-       cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64);
+       cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64);
        spin_unlock_irqrestore(&p->lock, flags);
 }
 
@@ -146,7 +199,6 @@ static unsigned int ring_size_to_bytes(unsigned int ring_size)
 static void octeon_mgmt_rx_fill_ring(struct net_device *netdev)
 {
        struct octeon_mgmt *p = netdev_priv(netdev);
-       int port = p->port;
 
        while (p->rx_current_fill < ring_max_fill(OCTEON_MGMT_RX_RING_SIZE)) {
                unsigned int size;
@@ -177,24 +229,23 @@ static void octeon_mgmt_rx_fill_ring(struct net_device *netdev)
                        (p->rx_next_fill + 1) % OCTEON_MGMT_RX_RING_SIZE;
                p->rx_current_fill++;
                /* Ring the bell.  */
-               cvmx_write_csr(CVMX_MIXX_IRING2(port), 1);
+               cvmx_write_csr(p->mix + MIX_IRING2, 1);
        }
 }
 
 static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p)
 {
-       int port = p->port;
        union cvmx_mixx_orcnt mix_orcnt;
        union mgmt_port_ring_entry re;
        struct sk_buff *skb;
        int cleaned = 0;
        unsigned long flags;
 
-       mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
+       mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT);
        while (mix_orcnt.s.orcnt) {
                spin_lock_irqsave(&p->tx_list.lock, flags);
 
-               mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
+               mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT);
 
                if (mix_orcnt.s.orcnt == 0) {
                        spin_unlock_irqrestore(&p->tx_list.lock, flags);
@@ -214,7 +265,7 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p)
                mix_orcnt.s.orcnt = 1;
 
                /* Acknowledge to hardware that we have the buffer.  */
-               cvmx_write_csr(CVMX_MIXX_ORCNT(port), mix_orcnt.u64);
+               cvmx_write_csr(p->mix + MIX_ORCNT, mix_orcnt.u64);
                p->tx_current_fill--;
 
                spin_unlock_irqrestore(&p->tx_list.lock, flags);
@@ -224,7 +275,7 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p)
                dev_kfree_skb_any(skb);
                cleaned++;
 
-               mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
+               mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT);
        }
 
        if (cleaned && netif_queue_stopped(p->netdev))
@@ -241,13 +292,12 @@ static void octeon_mgmt_clean_tx_tasklet(unsigned long arg)
 static void octeon_mgmt_update_rx_stats(struct net_device *netdev)
 {
        struct octeon_mgmt *p = netdev_priv(netdev);
-       int port = p->port;
        unsigned long flags;
        u64 drop, bad;
 
        /* These reads also clear the count registers.  */
-       drop = cvmx_read_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(port));
-       bad = cvmx_read_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(port));
+       drop = cvmx_read_csr(p->agl + AGL_GMX_RX_STATS_PKTS_DRP);
+       bad = cvmx_read_csr(p->agl + AGL_GMX_RX_STATS_PKTS_BAD);
 
        if (drop || bad) {
                /* Do an atomic update. */
@@ -261,15 +311,14 @@ static void octeon_mgmt_update_rx_stats(struct net_device *netdev)
 static void octeon_mgmt_update_tx_stats(struct net_device *netdev)
 {
        struct octeon_mgmt *p = netdev_priv(netdev);
-       int port = p->port;
        unsigned long flags;
 
        union cvmx_agl_gmx_txx_stat0 s0;
        union cvmx_agl_gmx_txx_stat1 s1;
 
        /* These reads also clear the count registers.  */
-       s0.u64 = cvmx_read_csr(CVMX_AGL_GMX_TXX_STAT0(port));
-       s1.u64 = cvmx_read_csr(CVMX_AGL_GMX_TXX_STAT1(port));
+       s0.u64 = cvmx_read_csr(p->agl + AGL_GMX_TX_STAT0);
+       s1.u64 = cvmx_read_csr(p->agl + AGL_GMX_TX_STAT1);
 
        if (s0.s.xsdef || s0.s.xscol || s1.s.scol || s1.s.mcol) {
                /* Do an atomic update. */
@@ -308,7 +357,6 @@ static u64 octeon_mgmt_dequeue_rx_buffer(struct octeon_mgmt *p,
 
 static int octeon_mgmt_receive_one(struct octeon_mgmt *p)
 {
-       int port = p->port;
        struct net_device *netdev = p->netdev;
        union cvmx_mixx_ircnt mix_ircnt;
        union mgmt_port_ring_entry re;
@@ -381,18 +429,17 @@ done:
        /* Tell the hardware we processed a packet.  */
        mix_ircnt.u64 = 0;
        mix_ircnt.s.ircnt = 1;
-       cvmx_write_csr(CVMX_MIXX_IRCNT(port), mix_ircnt.u64);
+       cvmx_write_csr(p->mix + MIX_IRCNT, mix_ircnt.u64);
        return rc;
 }
 
 static int octeon_mgmt_receive_packets(struct octeon_mgmt *p, int budget)
 {
-       int port = p->port;
        unsigned int work_done = 0;
        union cvmx_mixx_ircnt mix_ircnt;
        int rc;
 
-       mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port));
+       mix_ircnt.u64 = cvmx_read_csr(p->mix + MIX_IRCNT);
        while (work_done < budget && mix_ircnt.s.ircnt) {
 
                rc = octeon_mgmt_receive_one(p);
@@ -400,7 +447,7 @@ static int octeon_mgmt_receive_packets(struct octeon_mgmt *p, int budget)
                        work_done++;
 
                /* Check for more packets. */
-               mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port));
+               mix_ircnt.u64 = cvmx_read_csr(p->mix + MIX_IRCNT);
        }
 
        octeon_mgmt_rx_fill_ring(p->netdev);
@@ -434,16 +481,16 @@ static void octeon_mgmt_reset_hw(struct octeon_mgmt *p)
        union cvmx_agl_gmx_bist agl_gmx_bist;
 
        mix_ctl.u64 = 0;
-       cvmx_write_csr(CVMX_MIXX_CTL(p->port), mix_ctl.u64);
+       cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64);
        do {
-               mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(p->port));
+               mix_ctl.u64 = cvmx_read_csr(p->mix + MIX_CTL);
        } while (mix_ctl.s.busy);
        mix_ctl.s.reset = 1;
-       cvmx_write_csr(CVMX_MIXX_CTL(p->port), mix_ctl.u64);
-       cvmx_read_csr(CVMX_MIXX_CTL(p->port));
+       cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64);
+       cvmx_read_csr(p->mix + MIX_CTL);
        cvmx_wait(64);
 
-       mix_bist.u64 = cvmx_read_csr(CVMX_MIXX_BIST(p->port));
+       mix_bist.u64 = cvmx_read_csr(p->mix + MIX_BIST);
        if (mix_bist.u64)
                dev_warn(p->dev, "MIX failed BIST (0x%016llx)\n",
                        (unsigned long long)mix_bist.u64);
@@ -474,7 +521,6 @@ static void octeon_mgmt_cam_state_add(struct octeon_mgmt_cam_state *cs,
 static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
 {
        struct octeon_mgmt *p = netdev_priv(netdev);
-       int port = p->port;
        union cvmx_agl_gmx_rxx_adr_ctl adr_ctl;
        union cvmx_agl_gmx_prtx_cfg agl_gmx_prtx;
        unsigned long flags;
@@ -520,29 +566,29 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
        spin_lock_irqsave(&p->lock, flags);
 
        /* Disable packet I/O. */
-       agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+       agl_gmx_prtx.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
        prev_packet_enable = agl_gmx_prtx.s.en;
        agl_gmx_prtx.s.en = 0;
-       cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64);
+       cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, agl_gmx_prtx.u64);
 
        adr_ctl.u64 = 0;
        adr_ctl.s.cam_mode = cam_mode;
        adr_ctl.s.mcst = multicast_mode;
        adr_ctl.s.bcst = 1;     /* Allow broadcast */
 
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port), adr_ctl.u64);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CTL, adr_ctl.u64);
 
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM0(port), cam_state.cam[0]);
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM1(port), cam_state.cam[1]);
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM2(port), cam_state.cam[2]);
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM3(port), cam_state.cam[3]);
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM4(port), cam_state.cam[4]);
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM5(port), cam_state.cam[5]);
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), cam_state.cam_mask);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM0, cam_state.cam[0]);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM1, cam_state.cam[1]);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM2, cam_state.cam[2]);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM3, cam_state.cam[3]);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM4, cam_state.cam[4]);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM5, cam_state.cam[5]);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_ADR_CAM_EN, cam_state.cam_mask);
 
        /* Restore packet I/O. */
        agl_gmx_prtx.s.en = prev_packet_enable;
-       cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64);
+       cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, agl_gmx_prtx.u64);
 
        spin_unlock_irqrestore(&p->lock, flags);
 }
@@ -564,7 +610,6 @@ static int octeon_mgmt_set_mac_address(struct net_device *netdev, void *addr)
 static int octeon_mgmt_change_mtu(struct net_device *netdev, int new_mtu)
 {
        struct octeon_mgmt *p = netdev_priv(netdev);
-       int port = p->port;
        int size_without_fcs = new_mtu + OCTEON_MGMT_RX_HEADROOM;
 
        /*
@@ -580,8 +625,8 @@ static int octeon_mgmt_change_mtu(struct net_device *netdev, int new_mtu)
 
        netdev->mtu = new_mtu;
 
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_MAX(port), size_without_fcs);
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_JABBER(port),
+       cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_MAX, size_without_fcs);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_JABBER,
                       (size_without_fcs + 7) & 0xfff8);
 
        return 0;
@@ -591,14 +636,13 @@ static irqreturn_t octeon_mgmt_interrupt(int cpl, void *dev_id)
 {
        struct net_device *netdev = dev_id;
        struct octeon_mgmt *p = netdev_priv(netdev);
-       int port = p->port;
        union cvmx_mixx_isr mixx_isr;
 
-       mixx_isr.u64 = cvmx_read_csr(CVMX_MIXX_ISR(port));
+       mixx_isr.u64 = cvmx_read_csr(p->mix + MIX_ISR);
 
        /* Clear any pending interrupts */
-       cvmx_write_csr(CVMX_MIXX_ISR(port), mixx_isr.u64);
-       cvmx_read_csr(CVMX_MIXX_ISR(port));
+       cvmx_write_csr(p->mix + MIX_ISR, mixx_isr.u64);
+       cvmx_read_csr(p->mix + MIX_ISR);
 
        if (mixx_isr.s.irthresh) {
                octeon_mgmt_disable_rx_irq(p);
@@ -629,7 +673,6 @@ static int octeon_mgmt_ioctl(struct net_device *netdev,
 static void octeon_mgmt_adjust_link(struct net_device *netdev)
 {
        struct octeon_mgmt *p = netdev_priv(netdev);
-       int port = p->port;
        union cvmx_agl_gmx_prtx_cfg prtx_cfg;
        unsigned long flags;
        int link_changed = 0;
@@ -640,11 +683,9 @@ static void octeon_mgmt_adjust_link(struct net_device *netdev)
                        link_changed = 1;
                if (p->last_duplex != p->phydev->duplex) {
                        p->last_duplex = p->phydev->duplex;
-                       prtx_cfg.u64 =
-                               cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+                       prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
                        prtx_cfg.s.duplex = p->phydev->duplex;
-                       cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port),
-                                      prtx_cfg.u64);
+                       cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64);
                }
        } else {
                if (p->last_link)
@@ -670,18 +711,16 @@ static void octeon_mgmt_adjust_link(struct net_device *netdev)
 static int octeon_mgmt_init_phy(struct net_device *netdev)
 {
        struct octeon_mgmt *p = netdev_priv(netdev);
-       char phy_id[MII_BUS_ID_SIZE + 3];
 
-       if (octeon_is_simulation()) {
+       if (octeon_is_simulation() || p->phy_np == NULL) {
                /* No PHYs in the simulator. */
                netif_carrier_on(netdev);
                return 0;
        }
 
-       snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "mdio-octeon-0", p->port);
-
-       p->phydev = phy_connect(netdev, phy_id, octeon_mgmt_adjust_link, 0,
-                               PHY_INTERFACE_MODE_MII);
+       p->phydev = of_phy_connect(netdev, p->phy_np,
+                                  octeon_mgmt_adjust_link, 0,
+                                  PHY_INTERFACE_MODE_MII);
 
        if (IS_ERR(p->phydev)) {
                p->phydev = NULL;
@@ -737,14 +776,14 @@ static int octeon_mgmt_open(struct net_device *netdev)
 
        octeon_mgmt_reset_hw(p);
 
-       mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port));
+       mix_ctl.u64 = cvmx_read_csr(p->mix + MIX_CTL);
 
        /* Bring it out of reset if needed. */
        if (mix_ctl.s.reset) {
                mix_ctl.s.reset = 0;
-               cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64);
+               cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64);
                do {
-                       mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port));
+                       mix_ctl.u64 = cvmx_read_csr(p->mix + MIX_CTL);
                } while (mix_ctl.s.reset);
        }
 
@@ -755,17 +794,17 @@ static int octeon_mgmt_open(struct net_device *netdev)
        oring1.u64 = 0;
        oring1.s.obase = p->tx_ring_handle >> 3;
        oring1.s.osize = OCTEON_MGMT_TX_RING_SIZE;
-       cvmx_write_csr(CVMX_MIXX_ORING1(port), oring1.u64);
+       cvmx_write_csr(p->mix + MIX_ORING1, oring1.u64);
 
        iring1.u64 = 0;
        iring1.s.ibase = p->rx_ring_handle >> 3;
        iring1.s.isize = OCTEON_MGMT_RX_RING_SIZE;
-       cvmx_write_csr(CVMX_MIXX_IRING1(port), iring1.u64);
+       cvmx_write_csr(p->mix + MIX_IRING1, iring1.u64);
 
        /* Disable packet I/O. */
-       prtx_cfg.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+       prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
        prtx_cfg.s.en = 0;
-       cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), prtx_cfg.u64);
+       cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64);
 
        memcpy(sa.sa_data, netdev->dev_addr, ETH_ALEN);
        octeon_mgmt_set_mac_address(netdev, &sa);
@@ -782,7 +821,7 @@ static int octeon_mgmt_open(struct net_device *netdev)
        mix_ctl.s.nbtarb = 0;       /* Arbitration mode */
        /* MII CB-request FIFO programmable high watermark */
        mix_ctl.s.mrq_hwm = 1;
-       cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64);
+       cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64);
 
        if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
            || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
@@ -809,16 +848,16 @@ static int octeon_mgmt_open(struct net_device *netdev)
 
        /* Clear statistics. */
        /* Clear on read. */
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_CTL(port), 1);
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(port), 0);
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(port), 0);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_STATS_CTL, 1);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_STATS_PKTS_DRP, 0);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_STATS_PKTS_BAD, 0);
 
-       cvmx_write_csr(CVMX_AGL_GMX_TXX_STATS_CTL(port), 1);
-       cvmx_write_csr(CVMX_AGL_GMX_TXX_STAT0(port), 0);
-       cvmx_write_csr(CVMX_AGL_GMX_TXX_STAT1(port), 0);
+       cvmx_write_csr(p->agl + AGL_GMX_TX_STATS_CTL, 1);
+       cvmx_write_csr(p->agl + AGL_GMX_TX_STAT0, 0);
+       cvmx_write_csr(p->agl + AGL_GMX_TX_STAT1, 0);
 
        /* Clear any pending interrupts */
-       cvmx_write_csr(CVMX_MIXX_ISR(port), cvmx_read_csr(CVMX_MIXX_ISR(port)));
+       cvmx_write_csr(p->mix + MIX_ISR, cvmx_read_csr(p->mix + MIX_ISR));
 
        if (request_irq(p->irq, octeon_mgmt_interrupt, 0, netdev->name,
                        netdev)) {
@@ -829,18 +868,18 @@ static int octeon_mgmt_open(struct net_device *netdev)
        /* Interrupt every single RX packet */
        mix_irhwm.u64 = 0;
        mix_irhwm.s.irhwm = 0;
-       cvmx_write_csr(CVMX_MIXX_IRHWM(port), mix_irhwm.u64);
+       cvmx_write_csr(p->mix + MIX_IRHWM, mix_irhwm.u64);
 
        /* Interrupt when we have 1 or more packets to clean.  */
        mix_orhwm.u64 = 0;
        mix_orhwm.s.orhwm = 1;
-       cvmx_write_csr(CVMX_MIXX_ORHWM(port), mix_orhwm.u64);
+       cvmx_write_csr(p->mix + MIX_ORHWM, mix_orhwm.u64);
 
        /* Enable receive and transmit interrupts */
        mix_intena.u64 = 0;
        mix_intena.s.ithena = 1;
        mix_intena.s.othena = 1;
-       cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64);
+       cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64);
 
 
        /* Enable packet I/O. */
@@ -871,7 +910,7 @@ static int octeon_mgmt_open(struct net_device *netdev)
         * frame.  GMX checks that the PREAMBLE is sent correctly.
         */
        rxx_frm_ctl.s.pre_chk = 1;
-       cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_CTL(port), rxx_frm_ctl.u64);
+       cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64);
 
        /* Enable the AGL block */
        agl_gmx_inf_mode.u64 = 0;
@@ -879,13 +918,13 @@ static int octeon_mgmt_open(struct net_device *netdev)
        cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64);
 
        /* Configure the port duplex and enables */
-       prtx_cfg.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+       prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG);
        prtx_cfg.s.tx_en = 1;
        prtx_cfg.s.rx_en = 1;
        prtx_cfg.s.en = 1;
        p->last_duplex = 1;
        prtx_cfg.s.duplex = p->last_duplex;
-       cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), prtx_cfg.u64);
+       cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64);
 
        p->last_link = 0;
        netif_carrier_off(netdev);
@@ -949,7 +988,6 @@ static int octeon_mgmt_stop(struct net_device *netdev)
 static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        struct octeon_mgmt *p = netdev_priv(netdev);
-       int port = p->port;
        union mgmt_port_ring_entry re;
        unsigned long flags;
        int rv = NETDEV_TX_BUSY;
@@ -993,7 +1031,7 @@ static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
        netdev->stats.tx_bytes += skb->len;
 
        /* Ring the bell.  */
-       cvmx_write_csr(CVMX_MIXX_ORING2(port), 1);
+       cvmx_write_csr(p->mix + MIX_ORING2, 1);
 
        rv = NETDEV_TX_OK;
 out:
@@ -1071,10 +1109,14 @@ static const struct net_device_ops octeon_mgmt_ops = {
 
 static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
 {
-       struct resource *res_irq;
        struct net_device *netdev;
        struct octeon_mgmt *p;
-       int i;
+       const __be32 *data;
+       const u8 *mac;
+       struct resource *res_mix;
+       struct resource *res_agl;
+       int len;
+       int result;
 
        netdev = alloc_etherdev(sizeof(struct octeon_mgmt));
        if (netdev == NULL)
@@ -1088,14 +1130,63 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
        p->netdev = netdev;
        p->dev = &pdev->dev;
 
-       p->port = pdev->id;
+       data = of_get_property(pdev->dev.of_node, "cell-index", &len);
+       if (data && len == sizeof(*data)) {
+               p->port = be32_to_cpup(data);
+       } else {
+               dev_err(&pdev->dev, "no 'cell-index' property\n");
+               result = -ENXIO;
+               goto err;
+       }
+
        snprintf(netdev->name, IFNAMSIZ, "mgmt%d", p->port);
 
-       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res_irq)
+       result = platform_get_irq(pdev, 0);
+       if (result < 0)
+               goto err;
+
+       p->irq = result;
+
+       res_mix = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res_mix == NULL) {
+               dev_err(&pdev->dev, "no 'reg' resource\n");
+               result = -ENXIO;
+               goto err;
+       }
+
+       res_agl = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res_agl == NULL) {
+               dev_err(&pdev->dev, "no 'reg' resource\n");
+               result = -ENXIO;
+               goto err;
+       }
+
+       p->mix_phys = res_mix->start;
+       p->mix_size = resource_size(res_mix);
+       p->agl_phys = res_agl->start;
+       p->agl_size = resource_size(res_agl);
+
+
+       if (!devm_request_mem_region(&pdev->dev, p->mix_phys, p->mix_size,
+                                    res_mix->name)) {
+               dev_err(&pdev->dev, "request_mem_region (%s) failed\n",
+                       res_mix->name);
+               result = -ENXIO;
+               goto err;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev, p->agl_phys, p->agl_size,
+                                    res_agl->name)) {
+               result = -ENXIO;
+               dev_err(&pdev->dev, "request_mem_region (%s) failed\n",
+                       res_agl->name);
                goto err;
+       }
+
+
+       p->mix = (u64)devm_ioremap(&pdev->dev, p->mix_phys, p->mix_size);
+       p->agl = (u64)devm_ioremap(&pdev->dev, p->agl_phys, p->agl_size);
 
-       p->irq = res_irq->start;
        spin_lock_init(&p->lock);
 
        skb_queue_head_init(&p->tx_list);
@@ -1108,24 +1199,26 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev)
        netdev->netdev_ops = &octeon_mgmt_ops;
        netdev->ethtool_ops = &octeon_mgmt_ethtool_ops;
 
-       /* The mgmt ports get the first N MACs.  */
-       for (i = 0; i < 6; i++)
-               netdev->dev_addr[i] = octeon_bootinfo->mac_addr_base[i];
-       netdev->dev_addr[5] += p->port;
+       mac = of_get_mac_address(pdev->dev.of_node);
+
+       if (mac)
+               memcpy(netdev->dev_addr, mac, 6);
 
-       if (p->port >= octeon_bootinfo->mac_addr_count)
-               dev_err(&pdev->dev,
-                       "Error %s: Using MAC outside of the assigned range: %pM\n",
-                       netdev->name, netdev->dev_addr);
+       p->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
 
-       if (register_netdev(netdev))
+       pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64);
+       pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+       result = register_netdev(netdev);
+       if (result)
                goto err;
 
        dev_info(&pdev->dev, "Version " DRV_VERSION "\n");
        return 0;
+
 err:
        free_netdev(netdev);
-       return -ENOENT;
+       return result;
 }
 
 static int __devexit octeon_mgmt_remove(struct platform_device *pdev)
@@ -1137,10 +1230,19 @@ static int __devexit octeon_mgmt_remove(struct platform_device *pdev)
        return 0;
 }
 
+static struct of_device_id octeon_mgmt_match[] = {
+       {
+               .compatible = "cavium,octeon-5750-mix",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, octeon_mgmt_match);
+
 static struct platform_driver octeon_mgmt_driver = {
        .driver = {
                .name           = "octeon_mgmt",
                .owner          = THIS_MODULE,
+               .of_match_table = octeon_mgmt_match,
        },
        .probe          = octeon_mgmt_probe,
        .remove         = __devexit_p(octeon_mgmt_remove),
index ab4c376cb2763bf8c98ceac42d3e290b16ec341b..f2d3665430ad455b82552d975d9f91066a5fc913 100644 (file)
@@ -82,9 +82,7 @@ struct stmmac_priv {
        struct stmmac_counters mmc;
        struct dma_features dma_cap;
        int hw_cap_support;
-#ifdef CONFIG_HAVE_CLK
        struct clk *stmmac_clk;
-#endif
        int clk_csr;
        int synopsys_id;
        struct timer_list eee_ctrl_timer;
@@ -113,46 +111,6 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
 void stmmac_disable_eee_mode(struct stmmac_priv *priv);
 bool stmmac_eee_init(struct stmmac_priv *priv);
 
-#ifdef CONFIG_HAVE_CLK
-static inline int stmmac_clk_enable(struct stmmac_priv *priv)
-{
-       if (!IS_ERR(priv->stmmac_clk))
-               return clk_prepare_enable(priv->stmmac_clk);
-
-       return 0;
-}
-
-static inline void stmmac_clk_disable(struct stmmac_priv *priv)
-{
-       if (IS_ERR(priv->stmmac_clk))
-               return;
-
-       clk_disable_unprepare(priv->stmmac_clk);
-}
-static inline int stmmac_clk_get(struct stmmac_priv *priv)
-{
-       priv->stmmac_clk = clk_get(priv->device, NULL);
-
-       if (IS_ERR(priv->stmmac_clk))
-               return PTR_ERR(priv->stmmac_clk);
-
-       return 0;
-}
-#else
-static inline int stmmac_clk_enable(struct stmmac_priv *priv)
-{
-       return 0;
-}
-static inline void stmmac_clk_disable(struct stmmac_priv *priv)
-{
-}
-static inline int stmmac_clk_get(struct stmmac_priv *priv)
-{
-       return 0;
-}
-#endif /* CONFIG_HAVE_CLK */
-
-
 #ifdef CONFIG_STMMAC_PLATFORM
 extern struct platform_driver stmmac_pltfr_driver;
 static inline int stmmac_register_platform(void)
index f6b04c1a3672ea2c556f249c75f36f72c3721c68..fd8882f9602afc43b6fe6ecd79a14defb5ac8dbe 100644 (file)
@@ -28,6 +28,7 @@
        https://bugzilla.stlinux.com/
 *******************************************************************************/
 
+#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/ip.h>
@@ -173,12 +174,8 @@ static void stmmac_verify_args(void)
 
 static void stmmac_clk_csr_set(struct stmmac_priv *priv)
 {
-#ifdef CONFIG_HAVE_CLK
        u32 clk_rate;
 
-       if (IS_ERR(priv->stmmac_clk))
-               return;
-
        clk_rate = clk_get_rate(priv->stmmac_clk);
 
        /* Platform provided default clk_csr would be assumed valid
@@ -200,7 +197,6 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)
           * we can not estimate the proper divider as it is not known
           * the frequency of clk_csr_i. So we do not change the default
           * divider. */
-#endif
 }
 
 #if defined(STMMAC_XMIT_DEBUG) || defined(STMMAC_RX_DEBUG)
@@ -1070,7 +1066,7 @@ static int stmmac_open(struct net_device *dev)
        } else
                priv->tm->enable = 1;
 #endif
-       stmmac_clk_enable(priv);
+       clk_enable(priv->stmmac_clk);
 
        stmmac_check_ether_addr(priv);
 
@@ -1192,7 +1188,7 @@ open_error:
        if (priv->phydev)
                phy_disconnect(priv->phydev);
 
-       stmmac_clk_disable(priv);
+       clk_disable(priv->stmmac_clk);
 
        return ret;
 }
@@ -1250,7 +1246,7 @@ static int stmmac_release(struct net_device *dev)
 #ifdef CONFIG_STMMAC_DEBUG_FS
        stmmac_exit_fs();
 #endif
-       stmmac_clk_disable(priv);
+       clk_disable(priv->stmmac_clk);
 
        return 0;
 }
@@ -2078,11 +2074,14 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
        ret = register_netdev(ndev);
        if (ret) {
                pr_err("%s: ERROR %i registering the device\n", __func__, ret);
-               goto error;
+               goto error_netdev_register;
        }
 
-       if (stmmac_clk_get(priv))
+       priv->stmmac_clk = clk_get(priv->device, NULL);
+       if (IS_ERR(priv->stmmac_clk)) {
                pr_warning("%s: warning: cannot get CSR clock\n", __func__);
+               goto error_clk_get;
+       }
 
        /* If a specific clk_csr value is passed from the platform
         * this means that the CSR Clock Range selection cannot be
@@ -2100,15 +2099,17 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
        if (ret < 0) {
                pr_debug("%s: MDIO bus (id: %d) registration failed",
                         __func__, priv->plat->bus_id);
-               goto error;
+               goto error_mdio_register;
        }
 
        return priv;
 
-error:
-       netif_napi_del(&priv->napi);
-
+error_mdio_register:
+       clk_put(priv->stmmac_clk);
+error_clk_get:
        unregister_netdev(ndev);
+error_netdev_register:
+       netif_napi_del(&priv->napi);
        free_netdev(ndev);
 
        return NULL;
@@ -2177,7 +2178,7 @@ int stmmac_suspend(struct net_device *ndev)
        else {
                stmmac_set_mac(priv->ioaddr, false);
                /* Disable clock in case of PWM is off */
-               stmmac_clk_disable(priv);
+               clk_disable(priv->stmmac_clk);
        }
        spin_unlock_irqrestore(&priv->lock, flags);
        return 0;
@@ -2202,7 +2203,7 @@ int stmmac_resume(struct net_device *ndev)
                priv->hw->mac->pmt(priv->ioaddr, 0);
        else
                /* enable the clk prevously disabled */
-               stmmac_clk_enable(priv);
+               clk_enable(priv->stmmac_clk);
 
        netif_device_attach(ndev);
 
index 826d961f39f74ff7bbd2a9c839f36f3c5b2ed851..d4015aa663e6422f7be98e6d8f7f07f1561592de 100644 (file)
@@ -3,14 +3,17 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2009 Cavium Networks
+ * Copyright (C) 2009,2011 Cavium, Inc.
  */
 
-#include <linux/gfp.h>
-#include <linux/init.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/of_mdio.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gfp.h>
 #include <linux/phy.h>
+#include <linux/io.h>
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-smix-defs.h>
 #define DRV_VERSION "1.0"
 #define DRV_DESCRIPTION "Cavium Networks Octeon SMI/MDIO driver"
 
+#define SMI_CMD                0x0
+#define SMI_WR_DAT     0x8
+#define SMI_RD_DAT     0x10
+#define SMI_CLK                0x18
+#define SMI_EN         0x20
+
 struct octeon_mdiobus {
        struct mii_bus *mii_bus;
-       int unit;
+       u64 register_base;
+       resource_size_t mdio_phys;
+       resource_size_t regsize;
        int phy_irq[PHY_MAX_ADDR];
 };
 
@@ -35,15 +46,15 @@ static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
        smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */
        smi_cmd.s.phy_adr = phy_id;
        smi_cmd.s.reg_adr = regnum;
-       cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
+       cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64);
 
        do {
                /*
                 * Wait 1000 clocks so we don't saturate the RSL bus
                 * doing reads.
                 */
-               cvmx_wait(1000);
-               smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(p->unit));
+               __delay(1000);
+               smi_rd.u64 = cvmx_read_csr(p->register_base + SMI_RD_DAT);
        } while (smi_rd.s.pending && --timeout);
 
        if (smi_rd.s.val)
@@ -62,21 +73,21 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
 
        smi_wr.u64 = 0;
        smi_wr.s.dat = val;
-       cvmx_write_csr(CVMX_SMIX_WR_DAT(p->unit), smi_wr.u64);
+       cvmx_write_csr(p->register_base + SMI_WR_DAT, smi_wr.u64);
 
        smi_cmd.u64 = 0;
        smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */
        smi_cmd.s.phy_adr = phy_id;
        smi_cmd.s.reg_adr = regnum;
-       cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
+       cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64);
 
        do {
                /*
                 * Wait 1000 clocks so we don't saturate the RSL bus
                 * doing reads.
                 */
-               cvmx_wait(1000);
-               smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(p->unit));
+               __delay(1000);
+               smi_wr.u64 = cvmx_read_csr(p->register_base + SMI_WR_DAT);
        } while (smi_wr.s.pending && --timeout);
 
        if (timeout <= 0)
@@ -88,38 +99,44 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
 static int __devinit octeon_mdiobus_probe(struct platform_device *pdev)
 {
        struct octeon_mdiobus *bus;
+       struct resource *res_mem;
        union cvmx_smix_en smi_en;
-       int i;
        int err = -ENOENT;
 
        bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
        if (!bus)
                return -ENOMEM;
 
-       /* The platform_device id is our unit number.  */
-       bus->unit = pdev->id;
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (res_mem == NULL) {
+               dev_err(&pdev->dev, "found no memory resource\n");
+               err = -ENXIO;
+               goto fail;
+       }
+       bus->mdio_phys = res_mem->start;
+       bus->regsize = resource_size(res_mem);
+       if (!devm_request_mem_region(&pdev->dev, bus->mdio_phys, bus->regsize,
+                                    res_mem->name)) {
+               dev_err(&pdev->dev, "request_mem_region failed\n");
+               goto fail;
+       }
+       bus->register_base =
+               (u64)devm_ioremap(&pdev->dev, bus->mdio_phys, bus->regsize);
 
        bus->mii_bus = mdiobus_alloc();
 
        if (!bus->mii_bus)
-               goto err;
+               goto fail;
 
        smi_en.u64 = 0;
        smi_en.s.en = 1;
-       cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64);
-
-       /*
-        * Standard Octeon evaluation boards don't support phy
-        * interrupts, we need to poll.
-        */
-       for (i = 0; i < PHY_MAX_ADDR; i++)
-               bus->phy_irq[i] = PHY_POLL;
+       cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64);
 
        bus->mii_bus->priv = bus;
        bus->mii_bus->irq = bus->phy_irq;
        bus->mii_bus->name = "mdio-octeon";
-       snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
-               bus->mii_bus->name, bus->unit);
+       snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", bus->register_base);
        bus->mii_bus->parent = &pdev->dev;
 
        bus->mii_bus->read = octeon_mdiobus_read;
@@ -127,20 +144,18 @@ static int __devinit octeon_mdiobus_probe(struct platform_device *pdev)
 
        dev_set_drvdata(&pdev->dev, bus);
 
-       err = mdiobus_register(bus->mii_bus);
+       err = of_mdiobus_register(bus->mii_bus, pdev->dev.of_node);
        if (err)
-               goto err_register;
+               goto fail_register;
 
        dev_info(&pdev->dev, "Version " DRV_VERSION "\n");
 
        return 0;
-err_register:
+fail_register:
        mdiobus_free(bus->mii_bus);
-
-err:
-       devm_kfree(&pdev->dev, bus);
+fail:
        smi_en.u64 = 0;
-       cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64);
+       cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64);
        return err;
 }
 
@@ -154,14 +169,23 @@ static int __devexit octeon_mdiobus_remove(struct platform_device *pdev)
        mdiobus_unregister(bus->mii_bus);
        mdiobus_free(bus->mii_bus);
        smi_en.u64 = 0;
-       cvmx_write_csr(CVMX_SMIX_EN(bus->unit), smi_en.u64);
+       cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64);
        return 0;
 }
 
+static struct of_device_id octeon_mdiobus_match[] = {
+       {
+               .compatible = "cavium,octeon-3860-mdio",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, octeon_mdiobus_match);
+
 static struct platform_driver octeon_mdiobus_driver = {
        .driver = {
                .name           = "mdio-octeon",
                .owner          = THIS_MODULE,
+               .of_match_table = octeon_mdiobus_match,
        },
        .probe          = octeon_mdiobus_probe,
        .remove         = __devexit_p(octeon_mdiobus_remove),
index c8f40c9c0428310c8dcf7db2110c73a119dc3150..3782e1cd3697020219d34b81aa039a8c767be486 100644 (file)
@@ -95,6 +95,7 @@ MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
 
 enum acer_wmi_event_ids {
        WMID_HOTKEY_EVENT = 0x1,
+       WMID_ACCEL_EVENT = 0x5,
 };
 
 static const struct key_entry acer_wmi_keymap[] = {
@@ -130,6 +131,7 @@ static const struct key_entry acer_wmi_keymap[] = {
 };
 
 static struct input_dev *acer_wmi_input_dev;
+static struct input_dev *acer_wmi_accel_dev;
 
 struct event_return_value {
        u8 function;
@@ -200,6 +202,7 @@ struct hotkey_function_type_aa {
 #define ACER_CAP_BLUETOOTH             (1<<2)
 #define ACER_CAP_BRIGHTNESS            (1<<3)
 #define ACER_CAP_THREEG                        (1<<4)
+#define ACER_CAP_ACCEL                 (1<<5)
 #define ACER_CAP_ANY                   (0xFFFFFFFF)
 
 /*
@@ -1398,6 +1401,60 @@ static void acer_backlight_exit(void)
        backlight_device_unregister(acer_backlight_device);
 }
 
+/*
+ * Accelerometer device
+ */
+static acpi_handle gsensor_handle;
+
+static int acer_gsensor_init(void)
+{
+       acpi_status status;
+       struct acpi_buffer output;
+       union acpi_object out_obj;
+
+       output.length = sizeof(out_obj);
+       output.pointer = &out_obj;
+       status = acpi_evaluate_object(gsensor_handle, "_INI", NULL, &output);
+       if (ACPI_FAILURE(status))
+               return -1;
+
+       return 0;
+}
+
+static int acer_gsensor_open(struct input_dev *input)
+{
+       return acer_gsensor_init();
+}
+
+static int acer_gsensor_event(void)
+{
+       acpi_status status;
+       struct acpi_buffer output;
+       union acpi_object out_obj[5];
+
+       if (!has_cap(ACER_CAP_ACCEL))
+               return -1;
+
+       output.length = sizeof(out_obj);
+       output.pointer = out_obj;
+
+       status = acpi_evaluate_object(gsensor_handle, "RDVL", NULL, &output);
+       if (ACPI_FAILURE(status))
+               return -1;
+
+       if (out_obj->package.count != 4)
+               return -1;
+
+       input_report_abs(acer_wmi_accel_dev, ABS_X,
+               (s16)out_obj->package.elements[0].integer.value);
+       input_report_abs(acer_wmi_accel_dev, ABS_Y,
+               (s16)out_obj->package.elements[1].integer.value);
+       input_report_abs(acer_wmi_accel_dev, ABS_Z,
+               (s16)out_obj->package.elements[2].integer.value);
+       input_sync(acer_wmi_accel_dev);
+       return 0;
+}
+
 /*
  * Rfkill devices
  */
@@ -1673,6 +1730,9 @@ static void acer_wmi_notify(u32 value, void *context)
                                                   1, true);
                }
                break;
+       case WMID_ACCEL_EVENT:
+               acer_gsensor_event();
+               break;
        default:
                pr_warn("Unknown function number - %d - %d\n",
                        return_value.function, return_value.key_num);
@@ -1758,6 +1818,73 @@ static int acer_wmi_enable_lm(void)
        return status;
 }
 
+static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level,
+                                               void *ctx, void **retval)
+{
+       *(acpi_handle *)retval = ah;
+       return AE_OK;
+}
+
+static int __init acer_wmi_get_handle(const char *name, const char *prop,
+                                       acpi_handle *ah)
+{
+       acpi_status status;
+       acpi_handle handle;
+
+       BUG_ON(!name || !ah);
+
+       handle = NULL;
+       status = acpi_get_devices(prop, acer_wmi_get_handle_cb,
+                                       (void *)name, &handle);
+
+       if (ACPI_SUCCESS(status)) {
+               *ah = handle;
+               return 0;
+       } else {
+               return -ENODEV;
+       }
+}
+
+static int __init acer_wmi_accel_setup(void)
+{
+       int err;
+
+       err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle);
+       if (err)
+               return err;
+
+       interface->capability |= ACER_CAP_ACCEL;
+
+       acer_wmi_accel_dev = input_allocate_device();
+       if (!acer_wmi_accel_dev)
+               return -ENOMEM;
+
+       acer_wmi_accel_dev->open = acer_gsensor_open;
+
+       acer_wmi_accel_dev->name = "Acer BMA150 accelerometer";
+       acer_wmi_accel_dev->phys = "wmi/input1";
+       acer_wmi_accel_dev->id.bustype = BUS_HOST;
+       acer_wmi_accel_dev->evbit[0] = BIT_MASK(EV_ABS);
+       input_set_abs_params(acer_wmi_accel_dev, ABS_X, -16384, 16384, 0, 0);
+       input_set_abs_params(acer_wmi_accel_dev, ABS_Y, -16384, 16384, 0, 0);
+       input_set_abs_params(acer_wmi_accel_dev, ABS_Z, -16384, 16384, 0, 0);
+
+       err = input_register_device(acer_wmi_accel_dev);
+       if (err)
+               goto err_free_dev;
+
+       return 0;
+
+err_free_dev:
+       input_free_device(acer_wmi_accel_dev);
+       return err;
+}
+
+static void acer_wmi_accel_destroy(void)
+{
+       input_unregister_device(acer_wmi_accel_dev);
+}
+
 static int __init acer_wmi_input_setup(void)
 {
        acpi_status status;
@@ -1912,6 +2039,9 @@ static int acer_resume(struct device *dev)
        if (has_cap(ACER_CAP_BRIGHTNESS))
                set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
 
+       if (has_cap(ACER_CAP_ACCEL))
+               acer_gsensor_init();
+
        return 0;
 }
 
@@ -2060,14 +2190,16 @@ static int __init acer_wmi_init(void)
 
        set_quirks();
 
+       if (dmi_check_system(video_vendor_dmi_table))
+               acpi_video_dmi_promote_vendor();
        if (acpi_video_backlight_support()) {
-               if (dmi_check_system(video_vendor_dmi_table)) {
-                       acpi_video_unregister();
-               } else {
-                       interface->capability &= ~ACER_CAP_BRIGHTNESS;
-                       pr_info("Brightness must be controlled by "
-                               "acpi video driver\n");
-               }
+               interface->capability &= ~ACER_CAP_BRIGHTNESS;
+               pr_info("Brightness must be controlled by acpi video driver\n");
+       } else {
+#ifdef CONFIG_ACPI_VIDEO
+               pr_info("Disabling ACPI video driver\n");
+               acpi_video_unregister();
+#endif
        }
 
        if (wmi_has_guid(WMID_GUID3)) {
@@ -2090,6 +2222,8 @@ static int __init acer_wmi_init(void)
                        return err;
        }
 
+       acer_wmi_accel_setup();
+
        err = platform_driver_register(&acer_platform_driver);
        if (err) {
                pr_err("Unable to register platform driver\n");
@@ -2133,6 +2267,8 @@ error_device_alloc:
 error_platform_register:
        if (wmi_has_guid(ACERWMID_EVENT_GUID))
                acer_wmi_input_destroy();
+       if (has_cap(ACER_CAP_ACCEL))
+               acer_wmi_accel_destroy();
 
        return err;
 }
@@ -2142,6 +2278,9 @@ static void __exit acer_wmi_exit(void)
        if (wmi_has_guid(ACERWMID_EVENT_GUID))
                acer_wmi_input_destroy();
 
+       if (has_cap(ACER_CAP_ACCEL))
+               acer_wmi_accel_destroy();
+
        remove_sysfs(acer_platform_device);
        remove_debugfs();
        platform_device_unregister(acer_platform_device);
index 694a15a56230668c4eee12c7f5e7bc421a09cb0a..905fa01ac8df7abe86893964fd50c15a96b3b5d6 100644 (file)
@@ -193,7 +193,10 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
         * backlight control and supports more levels than other options.
         * Disable the other backlight choices.
         */
+       acpi_video_dmi_promote_vendor();
+#ifdef CONFIG_ACPI_VIDEO
        acpi_video_unregister();
+#endif
        apple_bl_unregister();
 
        return 0;
@@ -213,7 +216,10 @@ static void __devexit gmux_remove(struct pnp_dev *pnp)
        release_region(gmux_data->iostart, gmux_data->iolen);
        kfree(gmux_data);
 
+       acpi_video_dmi_demote_vendor();
+#ifdef CONFIG_ACPI_VIDEO
        acpi_video_register();
+#endif
        apple_bl_register();
 }
 
index 99a30b513137c50fe5224318c55d5d081fdf8973..6b0ebdeae916c727393aab1472e431bfd13e715a 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
 #include <linux/fb.h>
+#include <linux/dmi.h>
 
 #include "asus-wmi.h"
 
@@ -48,18 +49,115 @@ MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID);
  *  1  | Hardware  | Software
  *  4  | Software  | Software
  */
-static uint wapf;
+static int wapf = -1;
 module_param(wapf, uint, 0444);
 MODULE_PARM_DESC(wapf, "WAPF value");
 
+static struct quirk_entry *quirks;
+
 static struct quirk_entry quirk_asus_unknown = {
+       .wapf = 0,
+};
+
+static struct quirk_entry quirk_asus_x401u = {
+       .wapf = 4,
+};
+
+static int dmi_matched(const struct dmi_system_id *dmi)
+{
+       quirks = dmi->driver_data;
+       return 1;
+}
+
+static struct dmi_system_id asus_quirks[] = {
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X401U",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X401U"),
+               },
+               .driver_data = &quirk_asus_x401u,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X401A1",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X401A1"),
+               },
+               .driver_data = &quirk_asus_x401u,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X501U",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X501U"),
+               },
+               .driver_data = &quirk_asus_x401u,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X501A1",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X501A1"),
+               },
+               .driver_data = &quirk_asus_x401u,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X55A",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X55A"),
+               },
+               .driver_data = &quirk_asus_x401u,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X55C",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X55C"),
+               },
+               .driver_data = &quirk_asus_x401u,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X55U",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X55U"),
+               },
+               .driver_data = &quirk_asus_x401u,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X55VD",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X55VD"),
+               },
+               .driver_data = &quirk_asus_x401u,
+       },
+       {},
 };
 
 static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
 {
-       driver->quirks = &quirk_asus_unknown;
-       driver->quirks->wapf = wapf;
+       quirks = &quirk_asus_unknown;
+       dmi_check_system(asus_quirks);
+
+       driver->quirks = quirks;
        driver->panel_power = FB_BLANK_UNBLANK;
+
+       /* overwrite the wapf setting if the wapf paramater is specified */
+       if (wapf != -1)
+               quirks->wapf = wapf;
+       else
+               wapf = quirks->wapf;
 }
 
 static const struct key_entry asus_nb_wmi_keymap[] = {
@@ -94,6 +192,10 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0x8A, { KEY_PROG1 } },
        { KE_KEY, 0x95, { KEY_MEDIA } },
        { KE_KEY, 0x99, { KEY_PHONE } },
+       { KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */
+       { KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */
+       { KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */
+       { KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */
        { KE_KEY, 0xb5, { KEY_CALC } },
        { KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
        { KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
index 77aadde5281c97ae423e35f5255c7e9b63d36b70..c7a36f6b058048eb092717eff06a9e413a6a2546 100644 (file)
@@ -47,6 +47,9 @@
 #include <linux/thermal.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
+#ifdef CONFIG_ACPI_VIDEO
+#include <acpi/video.h>
+#endif
 
 #include "asus-wmi.h"
 
@@ -136,6 +139,9 @@ MODULE_LICENSE("GPL");
 /* Power */
 #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
 
+/* Deep S3 / Resume on LID open */
+#define ASUS_WMI_DEVID_LID_RESUME      0x00120031
+
 /* DSTS masks */
 #define ASUS_WMI_DSTS_STATUS_BIT       0x00000001
 #define ASUS_WMI_DSTS_UNKNOWN_BIT      0x00000002
@@ -1365,6 +1371,7 @@ static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf)
 ASUS_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, ASUS_WMI_DEVID_TOUCHPAD);
 ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA);
 ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER);
+ASUS_WMI_CREATE_DEVICE_ATTR(lid_resume, 0644, ASUS_WMI_DEVID_LID_RESUME);
 
 static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
                           const char *buf, size_t count)
@@ -1390,6 +1397,7 @@ static struct attribute *platform_attributes[] = {
        &dev_attr_camera.attr,
        &dev_attr_cardr.attr,
        &dev_attr_touchpad.attr,
+       &dev_attr_lid_resume.attr,
        NULL
 };
 
@@ -1408,6 +1416,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
                devid = ASUS_WMI_DEVID_CARDREADER;
        else if (attr == &dev_attr_touchpad.attr)
                devid = ASUS_WMI_DEVID_TOUCHPAD;
+       else if (attr == &dev_attr_lid_resume.attr)
+               devid = ASUS_WMI_DEVID_LID_RESUME;
 
        if (devid != -1)
                ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
@@ -1467,14 +1477,9 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
         */
        if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL))
                asus->dsts_id = ASUS_WMI_METHODID_DSTS;
-       else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL))
+       else
                asus->dsts_id = ASUS_WMI_METHODID_DSTS2;
 
-       if (!asus->dsts_id) {
-               pr_err("Can't find DSTS");
-               return -ENODEV;
-       }
-
        /* CWAP allow to define the behavior of the Fn+F2 key,
         * this method doesn't seems to be present on Eee PCs */
        if (asus->driver->quirks->wapf >= 0)
@@ -1681,7 +1686,13 @@ static int asus_wmi_add(struct platform_device *pdev)
        if (err)
                goto fail_rfkill;
 
+       if (asus->driver->quirks->wmi_backlight_power)
+               acpi_video_dmi_promote_vendor();
        if (!acpi_video_backlight_support()) {
+#ifdef CONFIG_ACPI_VIDEO
+               pr_info("Disabling ACPI video driver\n");
+               acpi_video_unregister();
+#endif
                err = asus_wmi_backlight_init(asus);
                if (err && err != -ENODEV)
                        goto fail_backlight;
index d43b66742004bae8cc0a819ca082a5e1065ef51f..9c1da8b81bea50f9007eac48f82da8f0bb29a73d 100644 (file)
@@ -39,6 +39,7 @@ struct quirk_entry {
        bool hotplug_wireless;
        bool scalar_panel_brightness;
        bool store_backlight_power;
+       bool wmi_backlight_power;
        int wapf;
 };
 
index e2230a2b2f8e3e82056ef7d197eb877999f337e9..2ca7dd1ab3e452e49eb0c25561274cea435acbcf 100644 (file)
@@ -31,15 +31,21 @@ MODULE_LICENSE("GPL");
 
 struct cmpc_accel {
        int sensitivity;
+       int g_select;
+       int inputdev_state;
 };
 
-#define CMPC_ACCEL_SENSITIVITY_DEFAULT         5
+#define CMPC_ACCEL_DEV_STATE_CLOSED    0
+#define CMPC_ACCEL_DEV_STATE_OPEN      1
 
+#define CMPC_ACCEL_SENSITIVITY_DEFAULT         5
+#define CMPC_ACCEL_G_SELECT_DEFAULT            0
 
 #define CMPC_ACCEL_HID         "ACCE0000"
+#define CMPC_ACCEL_HID_V4      "ACCE0001"
 #define CMPC_TABLET_HID                "TBLT0000"
 #define CMPC_IPML_HID  "IPML200"
-#define CMPC_KEYS_HID          "FnBT0000"
+#define CMPC_KEYS_HID          "FNBT0000"
 
 /*
  * Generic input device code.
@@ -76,7 +82,391 @@ static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi)
 }
 
 /*
- * Accelerometer code.
+ * Accelerometer code for Classmate V4
+ */
+static acpi_status cmpc_start_accel_v4(acpi_handle handle)
+{
+       union acpi_object param[4];
+       struct acpi_object_list input;
+       acpi_status status;
+
+       param[0].type = ACPI_TYPE_INTEGER;
+       param[0].integer.value = 0x3;
+       param[1].type = ACPI_TYPE_INTEGER;
+       param[1].integer.value = 0;
+       param[2].type = ACPI_TYPE_INTEGER;
+       param[2].integer.value = 0;
+       param[3].type = ACPI_TYPE_INTEGER;
+       param[3].integer.value = 0;
+       input.count = 4;
+       input.pointer = param;
+       status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
+       return status;
+}
+
+static acpi_status cmpc_stop_accel_v4(acpi_handle handle)
+{
+       union acpi_object param[4];
+       struct acpi_object_list input;
+       acpi_status status;
+
+       param[0].type = ACPI_TYPE_INTEGER;
+       param[0].integer.value = 0x4;
+       param[1].type = ACPI_TYPE_INTEGER;
+       param[1].integer.value = 0;
+       param[2].type = ACPI_TYPE_INTEGER;
+       param[2].integer.value = 0;
+       param[3].type = ACPI_TYPE_INTEGER;
+       param[3].integer.value = 0;
+       input.count = 4;
+       input.pointer = param;
+       status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
+       return status;
+}
+
+static acpi_status cmpc_accel_set_sensitivity_v4(acpi_handle handle, int val)
+{
+       union acpi_object param[4];
+       struct acpi_object_list input;
+
+       param[0].type = ACPI_TYPE_INTEGER;
+       param[0].integer.value = 0x02;
+       param[1].type = ACPI_TYPE_INTEGER;
+       param[1].integer.value = val;
+       param[2].type = ACPI_TYPE_INTEGER;
+       param[2].integer.value = 0;
+       param[3].type = ACPI_TYPE_INTEGER;
+       param[3].integer.value = 0;
+       input.count = 4;
+       input.pointer = param;
+       return acpi_evaluate_object(handle, "ACMD", &input, NULL);
+}
+
+static acpi_status cmpc_accel_set_g_select_v4(acpi_handle handle, int val)
+{
+       union acpi_object param[4];
+       struct acpi_object_list input;
+
+       param[0].type = ACPI_TYPE_INTEGER;
+       param[0].integer.value = 0x05;
+       param[1].type = ACPI_TYPE_INTEGER;
+       param[1].integer.value = val;
+       param[2].type = ACPI_TYPE_INTEGER;
+       param[2].integer.value = 0;
+       param[3].type = ACPI_TYPE_INTEGER;
+       param[3].integer.value = 0;
+       input.count = 4;
+       input.pointer = param;
+       return acpi_evaluate_object(handle, "ACMD", &input, NULL);
+}
+
+static acpi_status cmpc_get_accel_v4(acpi_handle handle,
+                                    int16_t *x,
+                                    int16_t *y,
+                                    int16_t *z)
+{
+       union acpi_object param[4];
+       struct acpi_object_list input;
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       int16_t *locs;
+       acpi_status status;
+
+       param[0].type = ACPI_TYPE_INTEGER;
+       param[0].integer.value = 0x01;
+       param[1].type = ACPI_TYPE_INTEGER;
+       param[1].integer.value = 0;
+       param[2].type = ACPI_TYPE_INTEGER;
+       param[2].integer.value = 0;
+       param[3].type = ACPI_TYPE_INTEGER;
+       param[3].integer.value = 0;
+       input.count = 4;
+       input.pointer = param;
+       status = acpi_evaluate_object(handle, "ACMD", &input, &output);
+       if (ACPI_SUCCESS(status)) {
+               union acpi_object *obj;
+               obj = output.pointer;
+               locs = (int16_t *) obj->buffer.pointer;
+               *x = locs[0];
+               *y = locs[1];
+               *z = locs[2];
+               kfree(output.pointer);
+       }
+       return status;
+}
+
+static void cmpc_accel_handler_v4(struct acpi_device *dev, u32 event)
+{
+       if (event == 0x81) {
+               int16_t x, y, z;
+               acpi_status status;
+
+               status = cmpc_get_accel_v4(dev->handle, &x, &y, &z);
+               if (ACPI_SUCCESS(status)) {
+                       struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
+
+                       input_report_abs(inputdev, ABS_X, x);
+                       input_report_abs(inputdev, ABS_Y, y);
+                       input_report_abs(inputdev, ABS_Z, z);
+                       input_sync(inputdev);
+               }
+       }
+}
+
+static ssize_t cmpc_accel_sensitivity_show_v4(struct device *dev,
+                                             struct device_attribute *attr,
+                                             char *buf)
+{
+       struct acpi_device *acpi;
+       struct input_dev *inputdev;
+       struct cmpc_accel *accel;
+
+       acpi = to_acpi_device(dev);
+       inputdev = dev_get_drvdata(&acpi->dev);
+       accel = dev_get_drvdata(&inputdev->dev);
+
+       return sprintf(buf, "%d\n", accel->sensitivity);
+}
+
+static ssize_t cmpc_accel_sensitivity_store_v4(struct device *dev,
+                                              struct device_attribute *attr,
+                                              const char *buf, size_t count)
+{
+       struct acpi_device *acpi;
+       struct input_dev *inputdev;
+       struct cmpc_accel *accel;
+       unsigned long sensitivity;
+       int r;
+
+       acpi = to_acpi_device(dev);
+       inputdev = dev_get_drvdata(&acpi->dev);
+       accel = dev_get_drvdata(&inputdev->dev);
+
+       r = kstrtoul(buf, 0, &sensitivity);
+       if (r)
+               return r;
+
+       /* sensitivity must be between 1 and 127 */
+       if (sensitivity < 1 || sensitivity > 127)
+               return -EINVAL;
+
+       accel->sensitivity = sensitivity;
+       cmpc_accel_set_sensitivity_v4(acpi->handle, sensitivity);
+
+       return strnlen(buf, count);
+}
+
+static struct device_attribute cmpc_accel_sensitivity_attr_v4 = {
+       .attr = { .name = "sensitivity", .mode = 0660 },
+       .show = cmpc_accel_sensitivity_show_v4,
+       .store = cmpc_accel_sensitivity_store_v4
+};
+
+static ssize_t cmpc_accel_g_select_show_v4(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       struct acpi_device *acpi;
+       struct input_dev *inputdev;
+       struct cmpc_accel *accel;
+
+       acpi = to_acpi_device(dev);
+       inputdev = dev_get_drvdata(&acpi->dev);
+       accel = dev_get_drvdata(&inputdev->dev);
+
+       return sprintf(buf, "%d\n", accel->g_select);
+}
+
+static ssize_t cmpc_accel_g_select_store_v4(struct device *dev,
+                                           struct device_attribute *attr,
+                                           const char *buf, size_t count)
+{
+       struct acpi_device *acpi;
+       struct input_dev *inputdev;
+       struct cmpc_accel *accel;
+       unsigned long g_select;
+       int r;
+
+       acpi = to_acpi_device(dev);
+       inputdev = dev_get_drvdata(&acpi->dev);
+       accel = dev_get_drvdata(&inputdev->dev);
+
+       r = kstrtoul(buf, 0, &g_select);
+       if (r)
+               return r;
+
+       /* 0 means 1.5g, 1 means 6g, everything else is wrong */
+       if (g_select != 0 && g_select != 1)
+               return -EINVAL;
+
+       accel->g_select = g_select;
+       cmpc_accel_set_g_select_v4(acpi->handle, g_select);
+
+       return strnlen(buf, count);
+}
+
+static struct device_attribute cmpc_accel_g_select_attr_v4 = {
+       .attr = { .name = "g_select", .mode = 0660 },
+       .show = cmpc_accel_g_select_show_v4,
+       .store = cmpc_accel_g_select_store_v4
+};
+
+static int cmpc_accel_open_v4(struct input_dev *input)
+{
+       struct acpi_device *acpi;
+       struct cmpc_accel *accel;
+
+       acpi = to_acpi_device(input->dev.parent);
+       accel = dev_get_drvdata(&input->dev);
+
+       cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
+       cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
+
+       if (ACPI_SUCCESS(cmpc_start_accel_v4(acpi->handle))) {
+               accel->inputdev_state = CMPC_ACCEL_DEV_STATE_OPEN;
+               return 0;
+       }
+       return -EIO;
+}
+
+static void cmpc_accel_close_v4(struct input_dev *input)
+{
+       struct acpi_device *acpi;
+       struct cmpc_accel *accel;
+
+       acpi = to_acpi_device(input->dev.parent);
+       accel = dev_get_drvdata(&input->dev);
+
+       cmpc_stop_accel_v4(acpi->handle);
+       accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
+}
+
+static void cmpc_accel_idev_init_v4(struct input_dev *inputdev)
+{
+       set_bit(EV_ABS, inputdev->evbit);
+       input_set_abs_params(inputdev, ABS_X, -255, 255, 16, 0);
+       input_set_abs_params(inputdev, ABS_Y, -255, 255, 16, 0);
+       input_set_abs_params(inputdev, ABS_Z, -255, 255, 16, 0);
+       inputdev->open = cmpc_accel_open_v4;
+       inputdev->close = cmpc_accel_close_v4;
+}
+
+static int cmpc_accel_suspend_v4(struct device *dev)
+{
+       struct input_dev *inputdev;
+       struct cmpc_accel *accel;
+
+       inputdev = dev_get_drvdata(dev);
+       accel = dev_get_drvdata(&inputdev->dev);
+
+       if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN)
+               return cmpc_stop_accel_v4(to_acpi_device(dev)->handle);
+
+       return 0;
+}
+
+static int cmpc_accel_resume_v4(struct device *dev)
+{
+       struct input_dev *inputdev;
+       struct cmpc_accel *accel;
+
+       inputdev = dev_get_drvdata(dev);
+       accel = dev_get_drvdata(&inputdev->dev);
+
+       if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) {
+               cmpc_accel_set_sensitivity_v4(to_acpi_device(dev)->handle,
+                                             accel->sensitivity);
+               cmpc_accel_set_g_select_v4(to_acpi_device(dev)->handle,
+                                          accel->g_select);
+
+               if (ACPI_FAILURE(cmpc_start_accel_v4(to_acpi_device(dev)->handle)))
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static int cmpc_accel_add_v4(struct acpi_device *acpi)
+{
+       int error;
+       struct input_dev *inputdev;
+       struct cmpc_accel *accel;
+
+       accel = kmalloc(sizeof(*accel), GFP_KERNEL);
+       if (!accel)
+               return -ENOMEM;
+
+       accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
+
+       accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
+       cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
+
+       error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
+       if (error)
+               goto failed_sensitivity;
+
+       accel->g_select = CMPC_ACCEL_G_SELECT_DEFAULT;
+       cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
+
+       error = device_create_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
+       if (error)
+               goto failed_g_select;
+
+       error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel_v4",
+                                           cmpc_accel_idev_init_v4);
+       if (error)
+               goto failed_input;
+
+       inputdev = dev_get_drvdata(&acpi->dev);
+       dev_set_drvdata(&inputdev->dev, accel);
+
+       return 0;
+
+failed_input:
+       device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
+failed_g_select:
+       device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
+failed_sensitivity:
+       kfree(accel);
+       return error;
+}
+
+static int cmpc_accel_remove_v4(struct acpi_device *acpi, int type)
+{
+       struct input_dev *inputdev;
+       struct cmpc_accel *accel;
+
+       inputdev = dev_get_drvdata(&acpi->dev);
+       accel = dev_get_drvdata(&inputdev->dev);
+
+       device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
+       device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
+       return cmpc_remove_acpi_notify_device(acpi);
+}
+
+static SIMPLE_DEV_PM_OPS(cmpc_accel_pm, cmpc_accel_suspend_v4,
+                        cmpc_accel_resume_v4);
+
+static const struct acpi_device_id cmpc_accel_device_ids_v4[] = {
+       {CMPC_ACCEL_HID_V4, 0},
+       {"", 0}
+};
+
+static struct acpi_driver cmpc_accel_acpi_driver_v4 = {
+       .owner = THIS_MODULE,
+       .name = "cmpc_accel_v4",
+       .class = "cmpc_accel_v4",
+       .ids = cmpc_accel_device_ids_v4,
+       .ops = {
+               .add = cmpc_accel_add_v4,
+               .remove = cmpc_accel_remove_v4,
+               .notify = cmpc_accel_handler_v4,
+       },
+       .drv.pm = &cmpc_accel_pm,
+};
+
+
+/*
+ * Accelerometer code for Classmate versions prior to V4
  */
 static acpi_status cmpc_start_accel(acpi_handle handle)
 {
@@ -726,8 +1116,15 @@ static int cmpc_init(void)
        if (r)
                goto failed_accel;
 
+       r = acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4);
+       if (r)
+               goto failed_accel_v4;
+
        return r;
 
+failed_accel_v4:
+       acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
+
 failed_accel:
        acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
 
@@ -743,6 +1140,7 @@ failed_keys:
 
 static void cmpc_exit(void)
 {
+       acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4);
        acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
        acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
        acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
@@ -754,6 +1152,7 @@ module_exit(cmpc_exit);
 
 static const struct acpi_device_id cmpc_device_ids[] = {
        {CMPC_ACCEL_HID, 0},
+       {CMPC_ACCEL_HID_V4, 0},
        {CMPC_TABLET_HID, 0},
        {CMPC_IPML_HID, 0},
        {CMPC_KEYS_HID, 0},
index 5f78aac9b163bf21c957f0beccbdff80d095228a..4e96e8c0b60f83dfb04e835fe0ec4ed40fddb6a6 100644 (file)
@@ -206,6 +206,60 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
                },
                .driver_data = &quirk_dell_vostro_v130,
        },
+       {
+               .callback = dmi_matched,
+               .ident = "Dell Inspiron 5420",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 5420"),
+               },
+               .driver_data = &quirk_dell_vostro_v130,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Dell Inspiron 5520",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 5520"),
+               },
+               .driver_data = &quirk_dell_vostro_v130,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Dell Inspiron 5720",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 5720"),
+               },
+               .driver_data = &quirk_dell_vostro_v130,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Dell Inspiron 7420",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 7420"),
+               },
+               .driver_data = &quirk_dell_vostro_v130,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Dell Inspiron 7520",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 7520"),
+               },
+               .driver_data = &quirk_dell_vostro_v130,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Dell Inspiron 7720",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 7720"),
+               },
+               .driver_data = &quirk_dell_vostro_v130,
+       },
        { }
 };
 
index 656761380342006d8b13ad344610b8e70f9822d2..5838332ea5bd2f67c6e0f5c875a459027b8032e9 100644 (file)
@@ -79,7 +79,7 @@ static const struct key_entry eeepc_wmi_keymap[] = {
        { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */
        { KE_KEY, HOME_PRESS, { KEY_CONFIG } }, /* Home/Express gate key */
        { KE_KEY, 0xe8, { KEY_SCREENLOCK } },
-       { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } },
+       { KE_KEY, 0xe9, { KEY_DISPLAYTOGGLE } },
        { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } },
        { KE_KEY, 0xec, { KEY_CAMERA_UP } },
        { KE_KEY, 0xed, { KEY_CAMERA_DOWN } },
@@ -107,6 +107,11 @@ static struct quirk_entry quirk_asus_et2012_type3 = {
        .store_backlight_power = true,
 };
 
+static struct quirk_entry quirk_asus_x101ch = {
+       /* We need this when ACPI function doesn't do this well */
+       .wmi_backlight_power = true,
+};
+
 static struct quirk_entry *quirks;
 
 static void et2012_quirks(void)
@@ -157,6 +162,24 @@ static struct dmi_system_id asus_quirks[] = {
                },
                .driver_data = &quirk_asus_unknown,
        },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK Computer INC. X101CH",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"),
+               },
+               .driver_data = &quirk_asus_x101ch,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK Computer INC. 1015CX",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"),
+               },
+               .driver_data = &quirk_asus_x101ch,
+       },
        {},
 };
 
index e2a34b42ddc1d584b5333fe9921d0d2c2b12dda4..c1ca7bcebb66b52bfb033fc24cc0bc2856bd313d 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
 #include <linux/ctype.h>
-#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
+#ifdef CONFIG_ACPI_VIDEO
 #include <acpi/video.h>
 #endif
 
@@ -1465,6 +1465,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
                        DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
                },
        },
+       /* DMI ids for laptops with bad Chassis Type */
+       {
+         .ident = "R40/R41",
+         .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "R40/R41"),
+               DMI_MATCH(DMI_BOARD_NAME, "R40/R41"),
+               },
+       },
        /* Specific DMI ids for laptop with quirks */
        {
         .callback = samsung_dmi_matched,
@@ -1506,6 +1515,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
                },
         .driver_data = &samsung_broken_acpi_video,
        },
+       {
+        .callback = samsung_dmi_matched,
+        .ident = "X360",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
+               DMI_MATCH(DMI_BOARD_NAME, "X360"),
+               },
+        .driver_data = &samsung_broken_acpi_video,
+       },
        { },
 };
 MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
@@ -1530,15 +1549,18 @@ static int __init samsung_init(void)
        samsung->quirks = quirks;
 
 
-#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
+#ifdef CONFIG_ACPI
+       if (samsung->quirks->broken_acpi_video)
+               acpi_video_dmi_promote_vendor();
+
        /* Don't handle backlight here if the acpi video already handle it */
        if (acpi_video_backlight_support()) {
-               if (samsung->quirks->broken_acpi_video) {
-                       pr_info("Disabling ACPI video driver\n");
-                       acpi_video_unregister();
-               } else {
-                       samsung->handle_backlight = false;
-               }
+               samsung->handle_backlight = false;
+       } else if (samsung->quirks->broken_acpi_video) {
+               pr_info("Disabling ACPI video driver\n");
+#ifdef CONFIG_ACPI_VIDEO
+               acpi_video_unregister();
+#endif
        }
 #endif
 
@@ -1552,8 +1574,7 @@ static int __init samsung_init(void)
 
 #ifdef CONFIG_ACPI
        /* Only log that if we are really on a sabi platform */
-       if (acpi_video_backlight_support() &&
-           !samsung->quirks->broken_acpi_video)
+       if (acpi_video_backlight_support())
                pr_info("Backlight controlled by ACPI video driver\n");
 #endif
 
index d5fd4a1193f84e9fd3db93835962a86bd8aefbac..e7f73287636cd9bdabb3f0b32104d4b7257e5e69 100644 (file)
@@ -3015,8 +3015,6 @@ static void hotkey_exit(void)
        if (hotkey_dev_attributes)
                delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
 
-       kfree(hotkey_keycode_map);
-
        dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY,
                   "restoring original HKEY status and mask\n");
        /* yes, there is a bitwise or below, we want the
@@ -5217,6 +5215,7 @@ static void led_exit(void)
                        led_classdev_unregister(&tpacpi_leds[i].led_classdev);
        }
 
+       flush_workqueue(tpacpi_wq);
        kfree(tpacpi_leds);
 }
 
@@ -8936,6 +8935,7 @@ static void thinkpad_acpi_module_exit(void)
                        input_unregister_device(tpacpi_inputdev);
                else
                        input_free_device(tpacpi_inputdev);
+               kfree(hotkey_keycode_map);
        }
 
        if (tpacpi_hwmon)
@@ -8969,6 +8969,7 @@ static void thinkpad_acpi_module_exit(void)
        kfree(thinkpad_id.bios_version_str);
        kfree(thinkpad_id.ec_version_str);
        kfree(thinkpad_id.model_str);
+       kfree(thinkpad_id.nummodel_str);
 }
 
 
index aa764ecc4e608373ce43590825ab7ee7c5530b0a..c1892f321c4636c09d9136b5736c78c13844f262 100644 (file)
@@ -268,6 +268,7 @@ config CHARGER_GPIO
 config CHARGER_MANAGER
        bool "Battery charger manager for multiple chargers"
        depends on REGULATOR && RTC_CLASS
+       select EXTCON
        help
           Say Y to enable charger-manager support, which allows multiple
           chargers attached to a battery and multiple batteries attached to a
index f5d6d379f2fb2f4c95ade1f73c4b4678900ee575..181ddece5181afceb5d025fbdcf9bfb7f641f007 100644 (file)
@@ -22,6 +22,7 @@
  * Datasheets:
  * http://focus.ti.com/docs/prod/folders/print/bq27000.html
  * http://focus.ti.com/docs/prod/folders/print/bq27500.html
+ * http://www.ti.com/product/bq27425-g1
  */
 
 #include <linux/module.h>
@@ -51,6 +52,7 @@
 #define BQ27x00_REG_LMD                        0x12 /* Last measured discharge */
 #define BQ27x00_REG_CYCT               0x2A /* Cycle count total */
 #define BQ27x00_REG_AE                 0x22 /* Available energy */
+#define BQ27x00_POWER_AVG              0x24
 
 #define BQ27000_REG_RSOC               0x0B /* Relative State-of-Charge */
 #define BQ27000_REG_ILMD               0x76 /* Initial last measured discharge */
 #define BQ27500_FLAG_SOCF              BIT(1) /* State-of-Charge threshold final */
 #define BQ27500_FLAG_SOC1              BIT(2) /* State-of-Charge threshold 1 */
 #define BQ27500_FLAG_FC                        BIT(9)
+#define BQ27500_FLAG_OTC               BIT(15)
+
+/* bq27425 register addresses are same as bq27x00 addresses minus 4 */
+#define BQ27425_REG_OFFSET             0x04
+#define BQ27425_REG_SOC                        0x18 /* Register address plus offset */
 
 #define BQ27000_RS                     20 /* Resistor sense */
+#define BQ27x00_POWER_CONSTANT         (256 * 29200 / 1000)
 
 struct bq27x00_device_info;
 struct bq27x00_access_methods {
        int (*read)(struct bq27x00_device_info *di, u8 reg, bool single);
 };
 
-enum bq27x00_chip { BQ27000, BQ27500 };
+enum bq27x00_chip { BQ27000, BQ27500, BQ27425};
 
 struct bq27x00_reg_cache {
        int temperature;
@@ -86,6 +94,8 @@ struct bq27x00_reg_cache {
        int capacity;
        int energy;
        int flags;
+       int power_avg;
+       int health;
 };
 
 struct bq27x00_device_info {
@@ -123,6 +133,22 @@ static enum power_supply_property bq27x00_battery_props[] = {
        POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
        POWER_SUPPLY_PROP_CYCLE_COUNT,
        POWER_SUPPLY_PROP_ENERGY_NOW,
+       POWER_SUPPLY_PROP_POWER_AVG,
+       POWER_SUPPLY_PROP_HEALTH,
+};
+
+static enum power_supply_property bq27425_battery_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+       POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_CHARGE_FULL,
+       POWER_SUPPLY_PROP_CHARGE_NOW,
+       POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 };
 
 static unsigned int poll_interval = 360;
@@ -137,9 +163,23 @@ MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \
 static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg,
                bool single)
 {
+       if (di->chip == BQ27425)
+               return di->bus.read(di, reg - BQ27425_REG_OFFSET, single);
        return di->bus.read(di, reg, single);
 }
 
+/*
+ * Higher versions of the chip like BQ27425 and BQ27500
+ * differ from BQ27000 and BQ27200 in calculation of certain
+ * parameters. Hence we need to check for the chip type.
+ */
+static bool bq27xxx_is_chip_version_higher(struct bq27x00_device_info *di)
+{
+       if (di->chip == BQ27425 || di->chip == BQ27500)
+               return true;
+       return false;
+}
+
 /*
  * Return the battery Relative State-of-Charge
  * Or < 0 if something fails.
@@ -150,6 +190,8 @@ static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di)
 
        if (di->chip == BQ27500)
                rsoc = bq27x00_read(di, BQ27500_REG_SOC, false);
+       else if (di->chip == BQ27425)
+               rsoc = bq27x00_read(di, BQ27425_REG_SOC, false);
        else
                rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true);
 
@@ -174,7 +216,7 @@ static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg)
                return charge;
        }
 
-       if (di->chip == BQ27500)
+       if (bq27xxx_is_chip_version_higher(di))
                charge *= 1000;
        else
                charge = charge * 3570 / BQ27000_RS;
@@ -208,7 +250,7 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di)
 {
        int ilmd;
 
-       if (di->chip == BQ27500)
+       if (bq27xxx_is_chip_version_higher(di))
                ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false);
        else
                ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true);
@@ -218,7 +260,7 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di)
                return ilmd;
        }
 
-       if (di->chip == BQ27500)
+       if (bq27xxx_is_chip_version_higher(di))
                ilmd *= 1000;
        else
                ilmd = ilmd * 256 * 3570 / BQ27000_RS;
@@ -262,7 +304,7 @@ static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di)
                return temp;
        }
 
-       if (di->chip == BQ27500)
+       if (bq27xxx_is_chip_version_higher(di))
                temp -= 2731;
        else
                temp = ((temp * 5) - 5463) / 2;
@@ -306,14 +348,70 @@ static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg)
        return tval * 60;
 }
 
+/*
+ * Read a power avg register.
+ * Return < 0 if something fails.
+ */
+static int bq27x00_battery_read_pwr_avg(struct bq27x00_device_info *di, u8 reg)
+{
+       int tval;
+
+       tval = bq27x00_read(di, reg, false);
+       if (tval < 0) {
+               dev_err(di->dev, "error reading power avg rgister  %02x: %d\n",
+                       reg, tval);
+               return tval;
+       }
+
+       if (di->chip == BQ27500)
+               return tval;
+       else
+               return (tval * BQ27x00_POWER_CONSTANT) / BQ27000_RS;
+}
+
+/*
+ * Read flag register.
+ * Return < 0 if something fails.
+ */
+static int bq27x00_battery_read_health(struct bq27x00_device_info *di)
+{
+       int tval;
+
+       tval = bq27x00_read(di, BQ27x00_REG_FLAGS, false);
+       if (tval < 0) {
+               dev_err(di->dev, "error reading flag register:%d\n", tval);
+               return tval;
+       }
+
+       if ((di->chip == BQ27500)) {
+               if (tval & BQ27500_FLAG_SOCF)
+                       tval = POWER_SUPPLY_HEALTH_DEAD;
+               else if (tval & BQ27500_FLAG_OTC)
+                       tval = POWER_SUPPLY_HEALTH_OVERHEAT;
+               else
+                       tval = POWER_SUPPLY_HEALTH_GOOD;
+               return tval;
+       } else {
+               if (tval & BQ27000_FLAG_EDV1)
+                       tval = POWER_SUPPLY_HEALTH_DEAD;
+               else
+                       tval = POWER_SUPPLY_HEALTH_GOOD;
+               return tval;
+       }
+
+       return -1;
+}
+
 static void bq27x00_update(struct bq27x00_device_info *di)
 {
        struct bq27x00_reg_cache cache = {0, };
        bool is_bq27500 = di->chip == BQ27500;
+       bool is_bq27425 = di->chip == BQ27425;
 
        cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500);
        if (cache.flags >= 0) {
-               if (!is_bq27500 && (cache.flags & BQ27000_FLAG_CI)) {
+               if (!is_bq27500 && !is_bq27425
+                               && (cache.flags & BQ27000_FLAG_CI)) {
                        dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n");
                        cache.capacity = -ENODATA;
                        cache.energy = -ENODATA;
@@ -321,16 +419,30 @@ static void bq27x00_update(struct bq27x00_device_info *di)
                        cache.time_to_empty_avg = -ENODATA;
                        cache.time_to_full = -ENODATA;
                        cache.charge_full = -ENODATA;
+                       cache.health = -ENODATA;
                } else {
                        cache.capacity = bq27x00_battery_read_rsoc(di);
-                       cache.energy = bq27x00_battery_read_energy(di);
-                       cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE);
-                       cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP);
-                       cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF);
+                       if (!is_bq27425) {
+                               cache.energy = bq27x00_battery_read_energy(di);
+                               cache.time_to_empty =
+                                       bq27x00_battery_read_time(di,
+                                                       BQ27x00_REG_TTE);
+                               cache.time_to_empty_avg =
+                                       bq27x00_battery_read_time(di,
+                                                       BQ27x00_REG_TTECP);
+                               cache.time_to_full =
+                                       bq27x00_battery_read_time(di,
+                                                       BQ27x00_REG_TTF);
+                       }
                        cache.charge_full = bq27x00_battery_read_lmd(di);
+                       cache.health = bq27x00_battery_read_health(di);
                }
                cache.temperature = bq27x00_battery_read_temperature(di);
+               if (!is_bq27425)
+                       cache.cycle_count = bq27x00_battery_read_cyct(di);
                cache.cycle_count = bq27x00_battery_read_cyct(di);
+               cache.power_avg =
+                       bq27x00_battery_read_pwr_avg(di, BQ27x00_POWER_AVG);
 
                /* We only have to read charge design full once */
                if (di->charge_design_full <= 0)
@@ -376,7 +488,7 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di,
                return curr;
        }
 
-       if (di->chip == BQ27500) {
+       if (bq27xxx_is_chip_version_higher(di)) {
                /* bq27500 returns signed value */
                val->intval = (int)((s16)curr) * 1000;
        } else {
@@ -397,7 +509,7 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di,
 {
        int status;
 
-       if (di->chip == BQ27500) {
+       if (bq27xxx_is_chip_version_higher(di)) {
                if (di->cache.flags & BQ27500_FLAG_FC)
                        status = POWER_SUPPLY_STATUS_FULL;
                else if (di->cache.flags & BQ27500_FLAG_DSC)
@@ -425,7 +537,7 @@ static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di,
 {
        int level;
 
-       if (di->chip == BQ27500) {
+       if (bq27xxx_is_chip_version_higher(di)) {
                if (di->cache.flags & BQ27500_FLAG_FC)
                        level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
                else if (di->cache.flags & BQ27500_FLAG_SOC1)
@@ -550,6 +662,12 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_ENERGY_NOW:
                ret = bq27x00_simple_value(di->cache.energy, val);
                break;
+       case POWER_SUPPLY_PROP_POWER_AVG:
+               ret = bq27x00_simple_value(di->cache.power_avg, val);
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               ret = bq27x00_simple_value(di->cache.health, val);
+               break;
        default:
                return -EINVAL;
        }
@@ -570,8 +688,14 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di)
        int ret;
 
        di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
-       di->bat.properties = bq27x00_battery_props;
-       di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
+       di->chip = BQ27425;
+       if (di->chip == BQ27425) {
+               di->bat.properties = bq27425_battery_props;
+               di->bat.num_properties = ARRAY_SIZE(bq27425_battery_props);
+       } else {
+               di->bat.properties = bq27x00_battery_props;
+               di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
+       }
        di->bat.get_property = bq27x00_battery_get_property;
        di->bat.external_power_changed = bq27x00_external_power_changed;
 
@@ -729,6 +853,7 @@ static int bq27x00_battery_remove(struct i2c_client *client)
 static const struct i2c_device_id bq27x00_id[] = {
        { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */
        { "bq27500", BQ27500 },
+       { "bq27425", BQ27425 },
        {},
 };
 MODULE_DEVICE_TABLE(i2c, bq27x00_id);
index 86935ec1895431aac77c47de1860711ae26e21eb..526e5c9312945bdf480f57a4673b478d22250be8 100644 (file)
@@ -271,16 +271,13 @@ static int try_charger_enable(struct charger_manager *cm, bool enable)
        if (enable) {
                if (cm->emergency_stop)
                        return -EAGAIN;
-               err = regulator_bulk_enable(desc->num_charger_regulators,
-                                       desc->charger_regulators);
+               for (i = 0 ; i < desc->num_charger_regulators ; i++)
+                       regulator_enable(desc->charger_regulators[i].consumer);
        } else {
                /*
                 * Abnormal battery state - Stop charging forcibly,
                 * even if charger was enabled at the other places
                 */
-               err = regulator_bulk_disable(desc->num_charger_regulators,
-                                       desc->charger_regulators);
-
                for (i = 0; i < desc->num_charger_regulators; i++) {
                        if (regulator_is_enabled(
                                    desc->charger_regulators[i].consumer)) {
@@ -288,7 +285,7 @@ static int try_charger_enable(struct charger_manager *cm, bool enable)
                                        desc->charger_regulators[i].consumer);
                                dev_warn(cm->dev,
                                        "Disable regulator(%s) forcibly.\n",
-                                       desc->charger_regulators[i].supply);
+                                       desc->charger_regulators[i].regulator_name);
                        }
                }
        }
@@ -994,11 +991,92 @@ int setup_charger_manager(struct charger_global_desc *gd)
 }
 EXPORT_SYMBOL_GPL(setup_charger_manager);
 
+/**
+ * charger_extcon_work - enable/diable charger according to the state
+ *                     of charger cable
+ *
+ * @work: work_struct of the function charger_extcon_work.
+ */
+static void charger_extcon_work(struct work_struct *work)
+{
+       struct charger_cable *cable =
+                       container_of(work, struct charger_cable, wq);
+       int ret;
+
+       if (cable->attached && cable->min_uA != 0 && cable->max_uA != 0) {
+               ret = regulator_set_current_limit(cable->charger->consumer,
+                                       cable->min_uA, cable->max_uA);
+               if (ret < 0) {
+                       pr_err("Cannot set current limit of %s (%s)\n",
+                               cable->charger->regulator_name, cable->name);
+                       return;
+               }
+
+               pr_info("Set current limit of %s : %duA ~ %duA\n",
+                                       cable->charger->regulator_name,
+                                       cable->min_uA, cable->max_uA);
+       }
+
+       try_charger_enable(cable->cm, cable->attached);
+}
+
+/**
+ * charger_extcon_notifier - receive the state of charger cable
+ *                     when registered cable is attached or detached.
+ *
+ * @self: the notifier block of the charger_extcon_notifier.
+ * @event: the cable state.
+ * @ptr: the data pointer of notifier block.
+ */
+static int charger_extcon_notifier(struct notifier_block *self,
+                       unsigned long event, void *ptr)
+{
+       struct charger_cable *cable =
+               container_of(self, struct charger_cable, nb);
+
+       cable->attached = event;
+       schedule_work(&cable->wq);
+
+       return NOTIFY_DONE;
+}
+
+/**
+ * charger_extcon_init - register external connector to use it
+ *                     as the charger cable
+ *
+ * @cm: the Charger Manager representing the battery.
+ * @cable: the Charger cable representing the external connector.
+ */
+static int charger_extcon_init(struct charger_manager *cm,
+               struct charger_cable *cable)
+{
+       int ret = 0;
+
+       /*
+        * Charger manager use Extcon framework to identify
+        * the charger cable among various external connector
+        * cable (e.g., TA, USB, MHL, Dock).
+        */
+       INIT_WORK(&cable->wq, charger_extcon_work);
+       cable->nb.notifier_call = charger_extcon_notifier;
+       ret = extcon_register_interest(&cable->extcon_dev,
+                       cable->extcon_name, cable->name, &cable->nb);
+       if (ret < 0) {
+               pr_info("Cannot register extcon_dev for %s(cable: %s).\n",
+                               cable->extcon_name,
+                               cable->name);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
 static int charger_manager_probe(struct platform_device *pdev)
 {
        struct charger_desc *desc = dev_get_platdata(&pdev->dev);
        struct charger_manager *cm;
        int ret = 0, i = 0;
+       int j = 0;
        union power_supply_propval val;
 
        if (g_desc && !rtc_dev && g_desc->rtc_name) {
@@ -1167,11 +1245,31 @@ static int charger_manager_probe(struct platform_device *pdev)
                goto err_register;
        }
 
-       ret = regulator_bulk_get(&pdev->dev, desc->num_charger_regulators,
-                                desc->charger_regulators);
-       if (ret) {
-               dev_err(&pdev->dev, "Cannot get charger regulators.\n");
-               goto err_bulk_get;
+       for (i = 0 ; i < desc->num_charger_regulators ; i++) {
+               struct charger_regulator *charger
+                                       = &desc->charger_regulators[i];
+
+               charger->consumer = regulator_get(&pdev->dev,
+                                       charger->regulator_name);
+               if (charger->consumer == NULL) {
+                       dev_err(&pdev->dev, "Cannot find charger(%s)n",
+                                               charger->regulator_name);
+                       ret = -EINVAL;
+                       goto err_chg_get;
+               }
+
+               for (j = 0 ; j < charger->num_cables ; j++) {
+                       struct charger_cable *cable = &charger->cables[j];
+
+                       ret = charger_extcon_init(cm, cable);
+                       if (ret < 0) {
+                               dev_err(&pdev->dev, "Cannot find charger(%s)n",
+                                               charger->regulator_name);
+                               goto err_extcon;
+                       }
+                       cable->charger = charger;
+                       cable->cm = cm;
+               }
        }
 
        ret = try_charger_enable(cm, true);
@@ -1197,9 +1295,19 @@ static int charger_manager_probe(struct platform_device *pdev)
        return 0;
 
 err_chg_enable:
-       regulator_bulk_free(desc->num_charger_regulators,
-                           desc->charger_regulators);
-err_bulk_get:
+err_extcon:
+       for (i = 0 ; i < desc->num_charger_regulators ; i++) {
+               struct charger_regulator *charger
+                               = &desc->charger_regulators[i];
+               for (j = 0 ; j < charger->num_cables ; j++) {
+                       struct charger_cable *cable = &charger->cables[j];
+                       extcon_unregister_interest(&cable->extcon_dev);
+               }
+       }
+err_chg_get:
+       for (i = 0 ; i < desc->num_charger_regulators ; i++)
+               regulator_put(desc->charger_regulators[i].consumer);
+
        power_supply_unregister(&cm->charger_psy);
 err_register:
        kfree(cm->charger_psy.properties);
@@ -1218,6 +1326,8 @@ static int __devexit charger_manager_remove(struct platform_device *pdev)
 {
        struct charger_manager *cm = platform_get_drvdata(pdev);
        struct charger_desc *desc = cm->desc;
+       int i = 0;
+       int j = 0;
 
        /* Remove from the list */
        mutex_lock(&cm_list_mtx);
@@ -1229,8 +1339,18 @@ static int __devexit charger_manager_remove(struct platform_device *pdev)
        if (delayed_work_pending(&cm_monitor_work))
                cancel_delayed_work_sync(&cm_monitor_work);
 
-       regulator_bulk_free(desc->num_charger_regulators,
-                           desc->charger_regulators);
+       for (i = 0 ; i < desc->num_charger_regulators ; i++) {
+               struct charger_regulator *charger
+                               = &desc->charger_regulators[i];
+               for (j = 0 ; j < charger->num_cables ; j++) {
+                       struct charger_cable *cable = &charger->cables[j];
+                       extcon_unregister_interest(&cable->extcon_dev);
+               }
+       }
+
+       for (i = 0 ; i < desc->num_charger_regulators ; i++)
+               regulator_put(desc->charger_regulators[i].consumer);
+
        power_supply_unregister(&cm->charger_psy);
 
        try_charger_enable(cm, false);
index 5f92a4bb33f95aaafe772c3aeea1b2bc54a00186..7a1ff4e4cf9a6452f1b58b2074638aac105cdc93 100644 (file)
@@ -64,7 +64,7 @@ static inline int ds2781_battery_io(struct ds2781_device_info *dev_info,
        return w1_ds2781_io(dev_info->w1_dev, buf, addr, count, io);
 }
 
-int w1_ds2781_read(struct ds2781_device_info *dev_info, char *buf,
+static int w1_ds2781_read(struct ds2781_device_info *dev_info, char *buf,
                int addr, size_t count)
 {
        return ds2781_battery_io(dev_info, buf, addr, count, 0);
index 8672c9177dd70f481937233fcd5fe0083bd8796c..cb2aa3195687b909d456f9058bbca605331795b2 100644 (file)
@@ -54,7 +54,7 @@ static int gpio_charger_get_property(struct power_supply *psy,
 
        switch (psp) {
        case POWER_SUPPLY_PROP_ONLINE:
-               val->intval = gpio_get_value(pdata->gpio);
+               val->intval = gpio_get_value_cansleep(pdata->gpio);
                val->intval ^= pdata->gpio_active_low;
                break;
        default:
index d8b75780bfef15718e9f578618381eeb4bc69560..6a364f4798f78765b40298451474a876e10f71da 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/power_supply.h>
-#include <linux/lp8727.h>
+#include <linux/platform_data/lp8727.h>
 
 #define DEBOUNCE_MSEC  270
 
index 140788b309f84fe26056e77636eff26b954d8cb8..74abc6c755b498bf023fcd540b9232743f1cd744 100644 (file)
@@ -113,6 +113,7 @@ static enum power_supply_property max17042_battery_props[] = {
        POWER_SUPPLY_PROP_VOLTAGE_OCV,
        POWER_SUPPLY_PROP_CAPACITY,
        POWER_SUPPLY_PROP_CHARGE_FULL,
+       POWER_SUPPLY_PROP_CHARGE_COUNTER,
        POWER_SUPPLY_PROP_TEMP,
        POWER_SUPPLY_PROP_CURRENT_NOW,
        POWER_SUPPLY_PROP_CURRENT_AVG,
@@ -199,6 +200,13 @@ static int max17042_get_property(struct power_supply *psy,
                if (ret < 0)
                        return ret;
 
+               val->intval = ret * 1000 / 2;
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+               ret = max17042_read_reg(chip->client, MAX17042_QH);
+               if (ret < 0)
+                       return ret;
+
                val->intval = ret * 1000 / 2;
                break;
        case POWER_SUPPLY_PROP_TEMP:
index 7385092f9bc8a98a8dc09155238d6ee924ab6034..55b10b81335384f203c3fb91304a86679b93f868 100644 (file)
@@ -231,11 +231,9 @@ static int olpc_bat_get_charge_full_design(union power_supply_propval *val)
 
        case POWER_SUPPLY_TECHNOLOGY_LiFe:
                switch (mfr) {
-               case 1: /* Gold Peak */
-                       val->intval = 2800000;
-                       break;
+               case 1: /* Gold Peak, fall through */
                case 2: /* BYD */
-                       val->intval = 3100000;
+                       val->intval = 2800000;
                        break;
                default:
                        return -EIO;
@@ -267,6 +265,55 @@ static int olpc_bat_get_charge_now(union power_supply_propval *val)
        return 0;
 }
 
+static int olpc_bat_get_voltage_max_design(union power_supply_propval *val)
+{
+       uint8_t ec_byte;
+       union power_supply_propval tech;
+       int mfr;
+       int ret;
+
+       ret = olpc_bat_get_tech(&tech);
+       if (ret)
+               return ret;
+
+       ec_byte = BAT_ADDR_MFR_TYPE;
+       ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
+       if (ret)
+               return ret;
+
+       mfr = ec_byte >> 4;
+
+       switch (tech.intval) {
+       case POWER_SUPPLY_TECHNOLOGY_NiMH:
+               switch (mfr) {
+               case 1: /* Gold Peak */
+                       val->intval = 6000000;
+                       break;
+               default:
+                       return -EIO;
+               }
+               break;
+
+       case POWER_SUPPLY_TECHNOLOGY_LiFe:
+               switch (mfr) {
+               case 1: /* Gold Peak */
+                       val->intval = 6400000;
+                       break;
+               case 2: /* BYD */
+                       val->intval = 6500000;
+                       break;
+               default:
+                       return -EIO;
+               }
+               break;
+
+       default:
+               return -EIO;
+       }
+
+       return ret;
+}
+
 /*********************************************************************
  *             Battery properties
  *********************************************************************/
@@ -401,6 +448,11 @@ static int olpc_bat_get_property(struct power_supply *psy,
                sprintf(bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf));
                val->strval = bat_serial;
                break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+               ret = olpc_bat_get_voltage_max_design(val);
+               if (ret)
+                       return ret;
+               break;
        default:
                ret = -EINVAL;
                break;
@@ -428,6 +480,7 @@ static enum power_supply_property olpc_xo1_bat_props[] = {
        POWER_SUPPLY_PROP_MANUFACTURER,
        POWER_SUPPLY_PROP_SERIAL_NUMBER,
        POWER_SUPPLY_PROP_CHARGE_COUNTER,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
 };
 
 /* XO-1.5 does not have ambient temperature property */
@@ -449,6 +502,7 @@ static enum power_supply_property olpc_xo15_bat_props[] = {
        POWER_SUPPLY_PROP_MANUFACTURER,
        POWER_SUPPLY_PROP_SERIAL_NUMBER,
        POWER_SUPPLY_PROP_CHARGE_COUNTER,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
 };
 
 /* EEPROM reading goes completely around the power_supply API, sadly */
index 8dbcd53c5e67b2a8868de2028169139e0472a74e..6a1ca735e93582b062d5b5e3e61d451427bef279 100644 (file)
@@ -134,13 +134,13 @@ static void update_charger(void)
                        regulator_set_current_limit(ac_draw, max_uA, max_uA);
                        if (!regulator_enabled) {
                                dev_dbg(dev, "charger on (AC)\n");
-                               regulator_enable(ac_draw);
+                               WARN_ON(regulator_enable(ac_draw));
                                regulator_enabled = 1;
                        }
                } else {
                        if (regulator_enabled) {
                                dev_dbg(dev, "charger off\n");
-                               regulator_disable(ac_draw);
+                               WARN_ON(regulator_disable(ac_draw));
                                regulator_enabled = 0;
                        }
                }
index 6ad612726785f48cdd8dbcc2785de8e211aae873..08cc8a3c15afb29b8147c1184c3477e543fdc01e 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/power_supply.h>
+#include <linux/thermal.h>
 #include "power_supply.h"
 
 /* exported for the APM Power driver, APM emulation */
@@ -169,6 +170,63 @@ static void power_supply_dev_release(struct device *dev)
        kfree(dev);
 }
 
+#ifdef CONFIG_THERMAL
+static int power_supply_read_temp(struct thermal_zone_device *tzd,
+               unsigned long *temp)
+{
+       struct power_supply *psy;
+       union power_supply_propval val;
+       int ret;
+
+       WARN_ON(tzd == NULL);
+       psy = tzd->devdata;
+       ret = psy->get_property(psy, POWER_SUPPLY_PROP_TEMP, &val);
+
+       /* Convert tenths of degree Celsius to milli degree Celsius. */
+       if (!ret)
+               *temp = val.intval * 100;
+
+       return ret;
+}
+
+static struct thermal_zone_device_ops psy_tzd_ops = {
+       .get_temp = power_supply_read_temp,
+};
+
+static int psy_register_thermal(struct power_supply *psy)
+{
+       int i;
+
+       /* Register battery zone device psy reports temperature */
+       for (i = 0; i < psy->num_properties; i++) {
+               if (psy->properties[i] == POWER_SUPPLY_PROP_TEMP) {
+                       psy->tzd = thermal_zone_device_register(psy->name, 0, 0,
+                                       psy, &psy_tzd_ops, 0, 0, 0, 0);
+                       if (IS_ERR(psy->tzd))
+                               return PTR_ERR(psy->tzd);
+                       break;
+               }
+       }
+       return 0;
+}
+
+static void psy_unregister_thermal(struct power_supply *psy)
+{
+       if (IS_ERR_OR_NULL(psy->tzd))
+               return;
+       thermal_zone_device_unregister(psy->tzd);
+}
+#else
+static int psy_register_thermal(struct power_supply *psy)
+{
+       return 0;
+}
+
+static void psy_unregister_thermal(struct power_supply *psy)
+{
+}
+#endif
+
 int power_supply_register(struct device *parent, struct power_supply *psy)
 {
        struct device *dev;
@@ -197,6 +255,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
        if (rc)
                goto device_add_failed;
 
+       rc = psy_register_thermal(psy);
+       if (rc)
+               goto register_thermal_failed;
+
        rc = power_supply_create_triggers(psy);
        if (rc)
                goto create_triggers_failed;
@@ -206,6 +268,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
        goto success;
 
 create_triggers_failed:
+       psy_unregister_thermal(psy);
+register_thermal_failed:
        device_del(dev);
 kobject_set_name_failed:
 device_add_failed:
@@ -220,6 +284,7 @@ void power_supply_unregister(struct power_supply *psy)
        cancel_work_sync(&psy->changed_work);
        sysfs_remove_link(&psy->dev->kobj, "powers");
        power_supply_remove_triggers(psy);
+       psy_unregister_thermal(psy);
        device_unregister(psy->dev);
 }
 EXPORT_SYMBOL_GPL(power_supply_unregister);
index 4150747f9186f8dfaff9faf81bf03a7ade8cb9fa..1d96614a17a42d7e8c48d4bb0421301c6ea997ea 100644 (file)
@@ -159,6 +159,8 @@ static struct device_attribute power_supply_attrs[] = {
        POWER_SUPPLY_ATTR(charge_now),
        POWER_SUPPLY_ATTR(charge_avg),
        POWER_SUPPLY_ATTR(charge_counter),
+       POWER_SUPPLY_ATTR(constant_charge_current),
+       POWER_SUPPLY_ATTR(constant_charge_voltage),
        POWER_SUPPLY_ATTR(energy_full_design),
        POWER_SUPPLY_ATTR(energy_empty_design),
        POWER_SUPPLY_ATTR(energy_full),
@@ -166,9 +168,15 @@ static struct device_attribute power_supply_attrs[] = {
        POWER_SUPPLY_ATTR(energy_now),
        POWER_SUPPLY_ATTR(energy_avg),
        POWER_SUPPLY_ATTR(capacity),
+       POWER_SUPPLY_ATTR(capacity_alert_min),
+       POWER_SUPPLY_ATTR(capacity_alert_max),
        POWER_SUPPLY_ATTR(capacity_level),
        POWER_SUPPLY_ATTR(temp),
+       POWER_SUPPLY_ATTR(temp_alert_min),
+       POWER_SUPPLY_ATTR(temp_alert_max),
        POWER_SUPPLY_ATTR(temp_ambient),
+       POWER_SUPPLY_ATTR(temp_ambient_alert_min),
+       POWER_SUPPLY_ATTR(temp_ambient_alert_max),
        POWER_SUPPLY_ATTR(time_to_empty_now),
        POWER_SUPPLY_ATTR(time_to_empty_avg),
        POWER_SUPPLY_ATTR(time_to_full_now),
index a5b6849d4123b51b60d2431bbcd72cc9f13c86f4..a65e8f54157efe4fe046367e6a28d10fefe0c141 100644 (file)
@@ -469,7 +469,7 @@ static int sbs_get_property(struct power_supply *psy,
 
        case POWER_SUPPLY_PROP_TECHNOLOGY:
                val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
-               break;
+               goto done; /* don't trigger power_supply_changed()! */
 
        case POWER_SUPPLY_PROP_ENERGY_NOW:
        case POWER_SUPPLY_PROP_ENERGY_FULL:
index f8eedd8a676fc68ad21f45b8bfa4ddec55add723..332dd0110bda36e6c7c09a60c98d5bed23d5d3cd 100644 (file)
@@ -196,6 +196,14 @@ static const unsigned int ccc_tbl[] = {
        1200000,
 };
 
+/* Convert register value to current using lookup table */
+static int hw_to_current(const unsigned int *tbl, size_t size, unsigned int val)
+{
+       if (val >= size)
+               return -EINVAL;
+       return tbl[val];
+}
+
 /* Convert current to register value using lookup table */
 static int current_to_hw(const unsigned int *tbl, size_t size, unsigned int val)
 {
@@ -841,22 +849,101 @@ fail:
        return ret;
 }
 
+/*
+ * Returns the constant charge current programmed
+ * into the charger in uA.
+ */
+static int get_const_charge_current(struct smb347_charger *smb)
+{
+       int ret, intval;
+       unsigned int v;
+
+       if (!smb347_is_ps_online(smb))
+               return -ENODATA;
+
+       ret = regmap_read(smb->regmap, STAT_B, &v);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * The current value is composition of FCC and PCC values
+        * and we can detect which table to use from bit 5.
+        */
+       if (v & 0x20) {
+               intval = hw_to_current(fcc_tbl, ARRAY_SIZE(fcc_tbl), v & 7);
+       } else {
+               v >>= 3;
+               intval = hw_to_current(pcc_tbl, ARRAY_SIZE(pcc_tbl), v & 7);
+       }
+
+       return intval;
+}
+
+/*
+ * Returns the constant charge voltage programmed
+ * into the charger in uV.
+ */
+static int get_const_charge_voltage(struct smb347_charger *smb)
+{
+       int ret, intval;
+       unsigned int v;
+
+       if (!smb347_is_ps_online(smb))
+               return -ENODATA;
+
+       ret = regmap_read(smb->regmap, STAT_A, &v);
+       if (ret < 0)
+               return ret;
+
+       v &= STAT_A_FLOAT_VOLTAGE_MASK;
+       if (v > 0x3d)
+               v = 0x3d;
+
+       intval = 3500000 + v * 20000;
+
+       return intval;
+}
+
 static int smb347_mains_get_property(struct power_supply *psy,
                                     enum power_supply_property prop,
                                     union power_supply_propval *val)
 {
        struct smb347_charger *smb =
                container_of(psy, struct smb347_charger, mains);
+       int ret;
 
-       if (prop == POWER_SUPPLY_PROP_ONLINE) {
+       switch (prop) {
+       case POWER_SUPPLY_PROP_ONLINE:
                val->intval = smb->mains_online;
-               return 0;
+               break;
+
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+               ret = get_const_charge_voltage(smb);
+               if (ret < 0)
+                       return ret;
+               else
+                       val->intval = ret;
+               break;
+
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+               ret = get_const_charge_current(smb);
+               if (ret < 0)
+                       return ret;
+               else
+                       val->intval = ret;
+               break;
+
+       default:
+               return -EINVAL;
        }
-       return -EINVAL;
+
+       return 0;
 }
 
 static enum power_supply_property smb347_mains_properties[] = {
        POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
 };
 
 static int smb347_usb_get_property(struct power_supply *psy,
@@ -865,16 +952,40 @@ static int smb347_usb_get_property(struct power_supply *psy,
 {
        struct smb347_charger *smb =
                container_of(psy, struct smb347_charger, usb);
+       int ret;
 
-       if (prop == POWER_SUPPLY_PROP_ONLINE) {
+       switch (prop) {
+       case POWER_SUPPLY_PROP_ONLINE:
                val->intval = smb->usb_online;
-               return 0;
+               break;
+
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+               ret = get_const_charge_voltage(smb);
+               if (ret < 0)
+                       return ret;
+               else
+                       val->intval = ret;
+               break;
+
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+               ret = get_const_charge_current(smb);
+               if (ret < 0)
+                       return ret;
+               else
+                       val->intval = ret;
+               break;
+
+       default:
+               return -EINVAL;
        }
-       return -EINVAL;
+
+       return 0;
 }
 
 static enum power_supply_property smb347_usb_properties[] = {
        POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
 };
 
 static int smb347_battery_get_property(struct power_supply *psy,
index b527c93bf2f3fbb11869333aa0cb36cad22ffea5..b99a452a4fda40165493a1c3640dbbc23084f18f 100644 (file)
 #include <linux/vermagic.h>
 
 static int ac_online                   = 1;
+static int usb_online                  = 1;
 static int battery_status              = POWER_SUPPLY_STATUS_DISCHARGING;
 static int battery_health              = POWER_SUPPLY_HEALTH_GOOD;
 static int battery_present             = 1; /* true */
 static int battery_technology          = POWER_SUPPLY_TECHNOLOGY_LION;
 static int battery_capacity            = 50;
+static int battery_voltage             = 3300;
 
 static int test_power_get_ac_property(struct power_supply *psy,
                                      enum power_supply_property psp,
@@ -42,6 +44,20 @@ static int test_power_get_ac_property(struct power_supply *psy,
        return 0;
 }
 
+static int test_power_get_usb_property(struct power_supply *psy,
+                                     enum power_supply_property psp,
+                                     union power_supply_propval *val)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = usb_online;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static int test_power_get_battery_property(struct power_supply *psy,
                                           enum power_supply_property psp,
                                           union power_supply_propval *val)
@@ -86,6 +102,12 @@ static int test_power_get_battery_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
                val->intval = 3600;
                break;
+       case POWER_SUPPLY_PROP_TEMP:
+               val->intval = 26;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = battery_voltage;
+               break;
        default:
                pr_info("%s: some properties deliberately report errors.\n",
                        __func__);
@@ -114,6 +136,8 @@ static enum power_supply_property test_power_battery_props[] = {
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_MANUFACTURER,
        POWER_SUPPLY_PROP_SERIAL_NUMBER,
+       POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
 };
 
 static char *test_power_ac_supplied_to[] = {
@@ -135,6 +159,14 @@ static struct power_supply test_power_supplies[] = {
                .properties = test_power_battery_props,
                .num_properties = ARRAY_SIZE(test_power_battery_props),
                .get_property = test_power_get_battery_property,
+       }, {
+               .name = "test_usb",
+               .type = POWER_SUPPLY_TYPE_USB,
+               .supplied_to = test_power_ac_supplied_to,
+               .num_supplicants = ARRAY_SIZE(test_power_ac_supplied_to),
+               .properties = test_power_ac_props,
+               .num_properties = ARRAY_SIZE(test_power_ac_props),
+               .get_property = test_power_get_usb_property,
        },
 };
 
@@ -167,6 +199,7 @@ static void __exit test_power_exit(void)
 
        /* Let's see how we handle changes... */
        ac_online = 0;
+       usb_online = 0;
        battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
        for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)
                power_supply_changed(&test_power_supplies[i]);
@@ -275,6 +308,19 @@ static int param_get_ac_online(char *buffer, const struct kernel_param *kp)
        return strlen(buffer);
 }
 
+static int param_set_usb_online(const char *key, const struct kernel_param *kp)
+{
+       usb_online = map_get_value(map_ac_online, key, usb_online);
+       power_supply_changed(&test_power_supplies[2]);
+       return 0;
+}
+
+static int param_get_usb_online(char *buffer, const struct kernel_param *kp)
+{
+       strcpy(buffer, map_get_key(map_ac_online, usb_online, "unknown"));
+       return strlen(buffer);
+}
+
 static int param_set_battery_status(const char *key,
                                        const struct kernel_param *kp)
 {
@@ -350,13 +396,31 @@ static int param_set_battery_capacity(const char *key,
 
 #define param_get_battery_capacity param_get_int
 
+static int param_set_battery_voltage(const char *key,
+                                       const struct kernel_param *kp)
+{
+       int tmp;
+
+       if (1 != sscanf(key, "%d", &tmp))
+               return -EINVAL;
+
+       battery_voltage = tmp;
+       power_supply_changed(&test_power_supplies[1]);
+       return 0;
+}
 
+#define param_get_battery_voltage param_get_int
 
 static struct kernel_param_ops param_ops_ac_online = {
        .set = param_set_ac_online,
        .get = param_get_ac_online,
 };
 
+static struct kernel_param_ops param_ops_usb_online = {
+       .set = param_set_usb_online,
+       .get = param_get_usb_online,
+};
+
 static struct kernel_param_ops param_ops_battery_status = {
        .set = param_set_battery_status,
        .get = param_get_battery_status,
@@ -382,18 +446,27 @@ static struct kernel_param_ops param_ops_battery_capacity = {
        .get = param_get_battery_capacity,
 };
 
+static struct kernel_param_ops param_ops_battery_voltage = {
+       .set = param_set_battery_voltage,
+       .get = param_get_battery_voltage,
+};
 
 #define param_check_ac_online(name, p) __param_check(name, p, void);
+#define param_check_usb_online(name, p) __param_check(name, p, void);
 #define param_check_battery_status(name, p) __param_check(name, p, void);
 #define param_check_battery_present(name, p) __param_check(name, p, void);
 #define param_check_battery_technology(name, p) __param_check(name, p, void);
 #define param_check_battery_health(name, p) __param_check(name, p, void);
 #define param_check_battery_capacity(name, p) __param_check(name, p, void);
+#define param_check_battery_voltage(name, p) __param_check(name, p, void);
 
 
 module_param(ac_online, ac_online, 0644);
 MODULE_PARM_DESC(ac_online, "AC charging state <on|off>");
 
+module_param(usb_online, usb_online, 0644);
+MODULE_PARM_DESC(usb_online, "USB charging state <on|off>");
+
 module_param(battery_status, battery_status, 0644);
 MODULE_PARM_DESC(battery_status,
        "battery status <charging|discharging|not-charging|full>");
@@ -413,6 +486,8 @@ MODULE_PARM_DESC(battery_health,
 module_param(battery_capacity, battery_capacity, 0644);
 MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)");
 
+module_param(battery_voltage, battery_voltage, 0644);
+MODULE_PARM_DESC(battery_voltage, "battery voltage (millivolts)");
 
 MODULE_DESCRIPTION("Power supply driver for testing");
 MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
index 7cacbaa68efe410902c64bb04c3a68619c4cd689..15f4d5d8611b554b5750b77a7fee430ba3448ead 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/power_supply.h>
 #include <linux/notifier.h>
 #include <linux/usb/otg.h>
+#include <linux/regulator/machine.h>
 
 #define TWL4030_BCIMSTATEC     0x02
 #define TWL4030_BCIICHG                0x08
@@ -29,6 +30,7 @@
 #define TWL4030_BCIVBUS                0x0c
 #define TWL4030_BCIMFSTS4      0x10
 #define TWL4030_BCICTL1                0x23
+#define TWL4030_BB_CFG         0x12
 
 #define TWL4030_BCIAUTOWEN     BIT(5)
 #define TWL4030_CONFIG_DONE    BIT(4)
 #define TWL4030_USBFASTMCHG    BIT(2)
 #define TWL4030_STS_VBUS       BIT(7)
 #define TWL4030_STS_USB_ID     BIT(2)
+#define TWL4030_BBCHEN         BIT(4)
+#define TWL4030_BBSEL_MASK     0b1100
+#define TWL4030_BBSEL_2V5      0b0000
+#define TWL4030_BBSEL_3V0      0b0100
+#define TWL4030_BBSEL_3V1      0b1000
+#define TWL4030_BBSEL_3V2      0b1100
+#define TWL4030_BBISEL_MASK    0b11
+#define TWL4030_BBISEL_25uA    0b00
+#define TWL4030_BBISEL_150uA   0b01
+#define TWL4030_BBISEL_500uA   0b10
+#define TWL4030_BBISEL_1000uA  0b11
 
 /* BCI interrupts */
 #define TWL4030_WOVF           BIT(0) /* Watchdog overflow */
@@ -75,6 +88,8 @@ struct twl4030_bci {
        struct work_struct      work;
        int                     irq_chg;
        int                     irq_bci;
+       struct regulator        *usb_reg;
+       int                     usb_enabled;
 
        unsigned long           event;
 };
@@ -104,7 +119,7 @@ static int twl4030_bci_read(u8 reg, u8 *val)
 
 static int twl4030_clear_set_boot_bci(u8 clear, u8 set)
 {
-       return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, 0,
+       return twl4030_clear_set(TWL4030_MODULE_PM_MASTER, clear,
                        TWL4030_CONFIG_DONE | TWL4030_BCIAUTOWEN | set,
                        TWL4030_PM_MASTER_BOOT_BCI);
 }
@@ -152,14 +167,14 @@ static int twl4030_bci_have_vbus(struct twl4030_bci *bci)
 }
 
 /*
- * Enable/Disable USB Charge funtionality.
+ * Enable/Disable USB Charge functionality.
  */
 static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
 {
        int ret;
 
        if (enable) {
-               /* Check for USB charger conneted */
+               /* Check for USB charger connected */
                if (!twl4030_bci_have_vbus(bci))
                        return -ENODEV;
 
@@ -172,6 +187,12 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
                        return -EACCES;
                }
 
+               /* Need to keep regulator on */
+               if (!bci->usb_enabled) {
+                       regulator_enable(bci->usb_reg);
+                       bci->usb_enabled = 1;
+               }
+
                /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
                ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB);
                if (ret < 0)
@@ -182,6 +203,10 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
                        TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4);
        } else {
                ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0);
+               if (bci->usb_enabled) {
+                       regulator_disable(bci->usb_reg);
+                       bci->usb_enabled = 0;
+               }
        }
 
        return ret;
@@ -202,6 +227,49 @@ static int twl4030_charger_enable_ac(bool enable)
        return ret;
 }
 
+/*
+ * Enable/Disable charging of Backup Battery.
+ */
+static int twl4030_charger_enable_backup(int uvolt, int uamp)
+{
+       int ret;
+       u8 flags;
+
+       if (uvolt < 2500000 ||
+           uamp < 25) {
+               /* disable charging of backup battery */
+               ret = twl4030_clear_set(TWL4030_MODULE_PM_RECEIVER,
+                                       TWL4030_BBCHEN, 0, TWL4030_BB_CFG);
+               return ret;
+       }
+
+       flags = TWL4030_BBCHEN;
+       if (uvolt >= 3200000)
+               flags |= TWL4030_BBSEL_3V2;
+       else if (uvolt >= 3100000)
+               flags |= TWL4030_BBSEL_3V1;
+       else if (uvolt >= 3000000)
+               flags |= TWL4030_BBSEL_3V0;
+       else
+               flags |= TWL4030_BBSEL_2V5;
+
+       if (uamp >= 1000)
+               flags |= TWL4030_BBISEL_1000uA;
+       else if (uamp >= 500)
+               flags |= TWL4030_BBISEL_500uA;
+       else if (uamp >= 150)
+               flags |= TWL4030_BBISEL_150uA;
+       else
+               flags |= TWL4030_BBISEL_25uA;
+
+       ret = twl4030_clear_set(TWL4030_MODULE_PM_RECEIVER,
+                               TWL4030_BBSEL_MASK | TWL4030_BBISEL_MASK,
+                               flags,
+                               TWL4030_BB_CFG);
+
+       return ret;
+}
+
 /*
  * TWL4030 CHG_PRES (AC charger presence) events
  */
@@ -425,6 +493,7 @@ static enum power_supply_property twl4030_charger_props[] = {
 static int __init twl4030_bci_probe(struct platform_device *pdev)
 {
        struct twl4030_bci *bci;
+       struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data;
        int ret;
        u32 reg;
 
@@ -456,6 +525,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
        bci->usb.num_properties = ARRAY_SIZE(twl4030_charger_props);
        bci->usb.get_property = twl4030_bci_get_property;
 
+       bci->usb_reg = regulator_get(bci->dev, "bci3v1");
+
        ret = power_supply_register(&pdev->dev, &bci->usb);
        if (ret) {
                dev_err(&pdev->dev, "failed to register usb: %d\n", ret);
@@ -504,6 +575,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
 
        twl4030_charger_enable_ac(true);
        twl4030_charger_enable_usb(bci, true);
+       twl4030_charger_enable_backup(pdata->bb_uvolt,
+                                     pdata->bb_uamp);
 
        return 0;
 
@@ -532,6 +605,7 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
 
        twl4030_charger_enable_ac(false);
        twl4030_charger_enable_usb(bci, false);
+       twl4030_charger_enable_backup(0, 0);
 
        /* mask interrupts */
        twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
index 98fbe62694d4eddbead50fde0de22fe834ce67a4..e771487132f7542123a0e8a669cd8582481ab051 100644 (file)
@@ -327,8 +327,10 @@ int pps_register_cdev(struct pps_device *pps)
        }
        pps->dev = device_create(pps_class, pps->info.dev, devt, pps,
                                                        "pps%d", pps->id);
-       if (IS_ERR(pps->dev))
+       if (IS_ERR(pps->dev)) {
+               err = PTR_ERR(pps->dev);
                goto del_cdev;
+       }
 
        pps->dev->release = pps_device_destruct;
 
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
new file mode 100644 (file)
index 0000000..8fc3808
--- /dev/null
@@ -0,0 +1,108 @@
+menuconfig PWM
+       bool "PWM Support"
+       depends on !MACH_JZ4740 && !PUV3_PWM
+       help
+         This enables PWM support through the generic PWM framework.
+         You only need to enable this, if you also want to enable
+         one or more of the PWM drivers below.
+
+         If unsure, say N.
+
+if PWM
+
+config PWM_BFIN
+       tristate "Blackfin PWM support"
+       depends on BFIN_GPTIMERS
+       help
+         Generic PWM framework driver for Blackfin.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-bfin.
+
+config PWM_IMX
+       tristate "i.MX pwm support"
+       depends on ARCH_MXC
+       help
+         Generic PWM framework driver for i.MX.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-imx.
+
+config PWM_LPC32XX
+       tristate "LPC32XX PWM support"
+       depends on ARCH_LPC32XX
+       help
+         Generic PWM framework driver for LPC32XX. The LPC32XX SOC has two
+         PWM controllers.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-lpc32xx.
+
+config PWM_MXS
+       tristate "Freescale MXS PWM support"
+       depends on ARCH_MXS && OF
+       select STMP_DEVICE
+       help
+         Generic PWM framework driver for Freescale MXS.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-mxs.
+
+config PWM_PXA
+       tristate "PXA PWM support"
+       depends on ARCH_PXA
+       help
+         Generic PWM framework driver for PXA.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-pxa.
+
+config PWM_SAMSUNG
+       tristate "Samsung pwm support"
+       depends on PLAT_SAMSUNG
+       help
+         Generic PWM framework driver for Samsung.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-samsung.
+
+config PWM_TEGRA
+       tristate "NVIDIA Tegra PWM support"
+       depends on ARCH_TEGRA
+       help
+         Generic PWM framework driver for the PWFM controller found on NVIDIA
+         Tegra SoCs.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-tegra.
+
+config  PWM_TIECAP
+       tristate "ECAP PWM support"
+       depends on SOC_AM33XX
+       help
+         PWM driver support for the ECAP APWM controller found on AM33XX
+         TI SOC
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-tiecap.
+
+config  PWM_TIEHRPWM
+       tristate "EHRPWM PWM support"
+       depends on SOC_AM33XX
+       help
+         PWM driver support for the EHRPWM controller found on AM33XX
+         TI SOC
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-tiehrpwm.
+
+config PWM_VT8500
+       tristate "vt8500 pwm support"
+       depends on ARCH_VT8500
+       help
+         Generic PWM framework driver for vt8500.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-vt8500.
+
+endif
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
new file mode 100644 (file)
index 0000000..e4b2c89
--- /dev/null
@@ -0,0 +1,11 @@
+obj-$(CONFIG_PWM)              += core.o
+obj-$(CONFIG_PWM_BFIN)         += pwm-bfin.o
+obj-$(CONFIG_PWM_IMX)          += pwm-imx.o
+obj-$(CONFIG_PWM_LPC32XX)      += pwm-lpc32xx.o
+obj-$(CONFIG_PWM_MXS)          += pwm-mxs.o
+obj-$(CONFIG_PWM_PXA)          += pwm-pxa.o
+obj-$(CONFIG_PWM_SAMSUNG)      += pwm-samsung.o
+obj-$(CONFIG_PWM_TEGRA)                += pwm-tegra.o
+obj-$(CONFIG_PWM_TIECAP)       += pwm-tiecap.o
+obj-$(CONFIG_PWM_TIEHRPWM)     += pwm-tiehrpwm.o
+obj-$(CONFIG_PWM_VT8500)       += pwm-vt8500.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
new file mode 100644 (file)
index 0000000..ecb7690
--- /dev/null
@@ -0,0 +1,713 @@
+/*
+ * Generic pwmlib implementation
+ *
+ * Copyright (C) 2011 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2011-2012 Avionic Design GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/pwm.h>
+#include <linux/radix-tree.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#define MAX_PWMS 1024
+
+static DEFINE_MUTEX(pwm_lookup_lock);
+static LIST_HEAD(pwm_lookup_list);
+static DEFINE_MUTEX(pwm_lock);
+static LIST_HEAD(pwm_chips);
+static DECLARE_BITMAP(allocated_pwms, MAX_PWMS);
+static RADIX_TREE(pwm_tree, GFP_KERNEL);
+
+static struct pwm_device *pwm_to_device(unsigned int pwm)
+{
+       return radix_tree_lookup(&pwm_tree, pwm);
+}
+
+static int alloc_pwms(int pwm, unsigned int count)
+{
+       unsigned int from = 0;
+       unsigned int start;
+
+       if (pwm >= MAX_PWMS)
+               return -EINVAL;
+
+       if (pwm >= 0)
+               from = pwm;
+
+       start = bitmap_find_next_zero_area(allocated_pwms, MAX_PWMS, from,
+                                          count, 0);
+
+       if (pwm >= 0 && start != pwm)
+               return -EEXIST;
+
+       if (start + count > MAX_PWMS)
+               return -ENOSPC;
+
+       return start;
+}
+
+static void free_pwms(struct pwm_chip *chip)
+{
+       unsigned int i;
+
+       for (i = 0; i < chip->npwm; i++) {
+               struct pwm_device *pwm = &chip->pwms[i];
+               radix_tree_delete(&pwm_tree, pwm->pwm);
+       }
+
+       bitmap_clear(allocated_pwms, chip->base, chip->npwm);
+
+       kfree(chip->pwms);
+       chip->pwms = NULL;
+}
+
+static struct pwm_chip *pwmchip_find_by_name(const char *name)
+{
+       struct pwm_chip *chip;
+
+       if (!name)
+               return NULL;
+
+       mutex_lock(&pwm_lock);
+
+       list_for_each_entry(chip, &pwm_chips, list) {
+               const char *chip_name = dev_name(chip->dev);
+
+               if (chip_name && strcmp(chip_name, name) == 0) {
+                       mutex_unlock(&pwm_lock);
+                       return chip;
+               }
+       }
+
+       mutex_unlock(&pwm_lock);
+
+       return NULL;
+}
+
+static int pwm_device_request(struct pwm_device *pwm, const char *label)
+{
+       int err;
+
+       if (test_bit(PWMF_REQUESTED, &pwm->flags))
+               return -EBUSY;
+
+       if (!try_module_get(pwm->chip->ops->owner))
+               return -ENODEV;
+
+       if (pwm->chip->ops->request) {
+               err = pwm->chip->ops->request(pwm->chip, pwm);
+               if (err) {
+                       module_put(pwm->chip->ops->owner);
+                       return err;
+               }
+       }
+
+       set_bit(PWMF_REQUESTED, &pwm->flags);
+       pwm->label = label;
+
+       return 0;
+}
+
+static struct pwm_device *of_pwm_simple_xlate(struct pwm_chip *pc,
+                                             const struct of_phandle_args *args)
+{
+       struct pwm_device *pwm;
+
+       if (pc->of_pwm_n_cells < 2)
+               return ERR_PTR(-EINVAL);
+
+       if (args->args[0] >= pc->npwm)
+               return ERR_PTR(-EINVAL);
+
+       pwm = pwm_request_from_chip(pc, args->args[0], NULL);
+       if (IS_ERR(pwm))
+               return pwm;
+
+       pwm_set_period(pwm, args->args[1]);
+
+       return pwm;
+}
+
+void of_pwmchip_add(struct pwm_chip *chip)
+{
+       if (!chip->dev || !chip->dev->of_node)
+               return;
+
+       if (!chip->of_xlate) {
+               chip->of_xlate = of_pwm_simple_xlate;
+               chip->of_pwm_n_cells = 2;
+       }
+
+       of_node_get(chip->dev->of_node);
+}
+
+void of_pwmchip_remove(struct pwm_chip *chip)
+{
+       if (chip->dev && chip->dev->of_node)
+               of_node_put(chip->dev->of_node);
+}
+
+/**
+ * pwm_set_chip_data() - set private chip data for a PWM
+ * @pwm: PWM device
+ * @data: pointer to chip-specific data
+ */
+int pwm_set_chip_data(struct pwm_device *pwm, void *data)
+{
+       if (!pwm)
+               return -EINVAL;
+
+       pwm->chip_data = data;
+
+       return 0;
+}
+
+/**
+ * pwm_get_chip_data() - get private chip data for a PWM
+ * @pwm: PWM device
+ */
+void *pwm_get_chip_data(struct pwm_device *pwm)
+{
+       return pwm ? pwm->chip_data : NULL;
+}
+
+/**
+ * pwmchip_add() - register a new PWM chip
+ * @chip: the PWM chip to add
+ *
+ * Register a new PWM chip. If chip->base < 0 then a dynamically assigned base
+ * will be used.
+ */
+int pwmchip_add(struct pwm_chip *chip)
+{
+       struct pwm_device *pwm;
+       unsigned int i;
+       int ret;
+
+       if (!chip || !chip->dev || !chip->ops || !chip->ops->config ||
+           !chip->ops->enable || !chip->ops->disable)
+               return -EINVAL;
+
+       mutex_lock(&pwm_lock);
+
+       ret = alloc_pwms(chip->base, chip->npwm);
+       if (ret < 0)
+               goto out;
+
+       chip->pwms = kzalloc(chip->npwm * sizeof(*pwm), GFP_KERNEL);
+       if (!chip->pwms) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       chip->base = ret;
+
+       for (i = 0; i < chip->npwm; i++) {
+               pwm = &chip->pwms[i];
+
+               pwm->chip = chip;
+               pwm->pwm = chip->base + i;
+               pwm->hwpwm = i;
+
+               radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
+       }
+
+       bitmap_set(allocated_pwms, chip->base, chip->npwm);
+
+       INIT_LIST_HEAD(&chip->list);
+       list_add(&chip->list, &pwm_chips);
+
+       ret = 0;
+
+       if (IS_ENABLED(CONFIG_OF))
+               of_pwmchip_add(chip);
+
+out:
+       mutex_unlock(&pwm_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pwmchip_add);
+
+/**
+ * pwmchip_remove() - remove a PWM chip
+ * @chip: the PWM chip to remove
+ *
+ * Removes a PWM chip. This function may return busy if the PWM chip provides
+ * a PWM device that is still requested.
+ */
+int pwmchip_remove(struct pwm_chip *chip)
+{
+       unsigned int i;
+       int ret = 0;
+
+       mutex_lock(&pwm_lock);
+
+       for (i = 0; i < chip->npwm; i++) {
+               struct pwm_device *pwm = &chip->pwms[i];
+
+               if (test_bit(PWMF_REQUESTED, &pwm->flags)) {
+                       ret = -EBUSY;
+                       goto out;
+               }
+       }
+
+       list_del_init(&chip->list);
+
+       if (IS_ENABLED(CONFIG_OF))
+               of_pwmchip_remove(chip);
+
+       free_pwms(chip);
+
+out:
+       mutex_unlock(&pwm_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pwmchip_remove);
+
+/**
+ * pwm_request() - request a PWM device
+ * @pwm_id: global PWM device index
+ * @label: PWM device label
+ *
+ * This function is deprecated, use pwm_get() instead.
+ */
+struct pwm_device *pwm_request(int pwm, const char *label)
+{
+       struct pwm_device *dev;
+       int err;
+
+       if (pwm < 0 || pwm >= MAX_PWMS)
+               return ERR_PTR(-EINVAL);
+
+       mutex_lock(&pwm_lock);
+
+       dev = pwm_to_device(pwm);
+       if (!dev) {
+               dev = ERR_PTR(-EPROBE_DEFER);
+               goto out;
+       }
+
+       err = pwm_device_request(dev, label);
+       if (err < 0)
+               dev = ERR_PTR(err);
+
+out:
+       mutex_unlock(&pwm_lock);
+
+       return dev;
+}
+EXPORT_SYMBOL_GPL(pwm_request);
+
+/**
+ * pwm_request_from_chip() - request a PWM device relative to a PWM chip
+ * @chip: PWM chip
+ * @index: per-chip index of the PWM to request
+ * @label: a literal description string of this PWM
+ *
+ * Returns the PWM at the given index of the given PWM chip. A negative error
+ * code is returned if the index is not valid for the specified PWM chip or
+ * if the PWM device cannot be requested.
+ */
+struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
+                                        unsigned int index,
+                                        const char *label)
+{
+       struct pwm_device *pwm;
+       int err;
+
+       if (!chip || index >= chip->npwm)
+               return ERR_PTR(-EINVAL);
+
+       mutex_lock(&pwm_lock);
+       pwm = &chip->pwms[index];
+
+       err = pwm_device_request(pwm, label);
+       if (err < 0)
+               pwm = ERR_PTR(err);
+
+       mutex_unlock(&pwm_lock);
+       return pwm;
+}
+EXPORT_SYMBOL_GPL(pwm_request_from_chip);
+
+/**
+ * pwm_free() - free a PWM device
+ * @pwm: PWM device
+ *
+ * This function is deprecated, use pwm_put() instead.
+ */
+void pwm_free(struct pwm_device *pwm)
+{
+       pwm_put(pwm);
+}
+EXPORT_SYMBOL_GPL(pwm_free);
+
+/**
+ * pwm_config() - change a PWM device configuration
+ * @pwm: PWM device
+ * @duty_ns: "on" time (in nanoseconds)
+ * @period_ns: duration (in nanoseconds) of one cycle
+ */
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+       if (!pwm || period_ns == 0 || duty_ns > period_ns)
+               return -EINVAL;
+
+       return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
+}
+EXPORT_SYMBOL_GPL(pwm_config);
+
+/**
+ * pwm_enable() - start a PWM output toggling
+ * @pwm: PWM device
+ */
+int pwm_enable(struct pwm_device *pwm)
+{
+       if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags))
+               return pwm->chip->ops->enable(pwm->chip, pwm);
+
+       return pwm ? 0 : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(pwm_enable);
+
+/**
+ * pwm_disable() - stop a PWM output toggling
+ * @pwm: PWM device
+ */
+void pwm_disable(struct pwm_device *pwm)
+{
+       if (pwm && test_and_clear_bit(PWMF_ENABLED, &pwm->flags))
+               pwm->chip->ops->disable(pwm->chip, pwm);
+}
+EXPORT_SYMBOL_GPL(pwm_disable);
+
+static struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
+{
+       struct pwm_chip *chip;
+
+       mutex_lock(&pwm_lock);
+
+       list_for_each_entry(chip, &pwm_chips, list)
+               if (chip->dev && chip->dev->of_node == np) {
+                       mutex_unlock(&pwm_lock);
+                       return chip;
+               }
+
+       mutex_unlock(&pwm_lock);
+
+       return ERR_PTR(-EPROBE_DEFER);
+}
+
+/**
+ * of_pwm_request() - request a PWM via the PWM framework
+ * @np: device node to get the PWM from
+ * @con_id: consumer name
+ *
+ * Returns the PWM device parsed from the phandle and index specified in the
+ * "pwms" property of a device tree node or a negative error-code on failure.
+ * Values parsed from the device tree are stored in the returned PWM device
+ * object.
+ *
+ * If con_id is NULL, the first PWM device listed in the "pwms" property will
+ * be requested. Otherwise the "pwm-names" property is used to do a reverse
+ * lookup of the PWM index. This also means that the "pwm-names" property
+ * becomes mandatory for devices that look up the PWM device via the con_id
+ * parameter.
+ */
+static struct pwm_device *of_pwm_request(struct device_node *np,
+                                        const char *con_id)
+{
+       struct pwm_device *pwm = NULL;
+       struct of_phandle_args args;
+       struct pwm_chip *pc;
+       int index = 0;
+       int err;
+
+       if (con_id) {
+               index = of_property_match_string(np, "pwm-names", con_id);
+               if (index < 0)
+                       return ERR_PTR(index);
+       }
+
+       err = of_parse_phandle_with_args(np, "pwms", "#pwm-cells", index,
+                                        &args);
+       if (err) {
+               pr_debug("%s(): can't parse \"pwms\" property\n", __func__);
+               return ERR_PTR(err);
+       }
+
+       pc = of_node_to_pwmchip(args.np);
+       if (IS_ERR(pc)) {
+               pr_debug("%s(): PWM chip not found\n", __func__);
+               pwm = ERR_CAST(pc);
+               goto put;
+       }
+
+       if (args.args_count != pc->of_pwm_n_cells) {
+               pr_debug("%s: wrong #pwm-cells for %s\n", np->full_name,
+                        args.np->full_name);
+               pwm = ERR_PTR(-EINVAL);
+               goto put;
+       }
+
+       pwm = pc->of_xlate(pc, &args);
+       if (IS_ERR(pwm))
+               goto put;
+
+       /*
+        * If a consumer name was not given, try to look it up from the
+        * "pwm-names" property if it exists. Otherwise use the name of
+        * the user device node.
+        */
+       if (!con_id) {
+               err = of_property_read_string_index(np, "pwm-names", index,
+                                                   &con_id);
+               if (err < 0)
+                       con_id = np->name;
+       }
+
+       pwm->label = con_id;
+
+put:
+       of_node_put(args.np);
+
+       return pwm;
+}
+
+/**
+ * pwm_add_table() - register PWM device consumers
+ * @table: array of consumers to register
+ * @num: number of consumers in table
+ */
+void __init pwm_add_table(struct pwm_lookup *table, size_t num)
+{
+       mutex_lock(&pwm_lookup_lock);
+
+       while (num--) {
+               list_add_tail(&table->list, &pwm_lookup_list);
+               table++;
+       }
+
+       mutex_unlock(&pwm_lookup_lock);
+}
+
+/**
+ * pwm_get() - look up and request a PWM device
+ * @dev: device for PWM consumer
+ * @con_id: consumer name
+ *
+ * Lookup is first attempted using DT. If the device was not instantiated from
+ * a device tree, a PWM chip and a relative index is looked up via a table
+ * supplied by board setup code (see pwm_add_table()).
+ *
+ * Once a PWM chip has been found the specified PWM device will be requested
+ * and is ready to be used.
+ */
+struct pwm_device *pwm_get(struct device *dev, const char *con_id)
+{
+       struct pwm_device *pwm = ERR_PTR(-EPROBE_DEFER);
+       const char *dev_id = dev ? dev_name(dev): NULL;
+       struct pwm_chip *chip = NULL;
+       unsigned int index = 0;
+       unsigned int best = 0;
+       struct pwm_lookup *p;
+       unsigned int match;
+
+       /* look up via DT first */
+       if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
+               return of_pwm_request(dev->of_node, con_id);
+
+       /*
+        * We look up the provider in the static table typically provided by
+        * board setup code. We first try to lookup the consumer device by
+        * name. If the consumer device was passed in as NULL or if no match
+        * was found, we try to find the consumer by directly looking it up
+        * by name.
+        *
+        * If a match is found, the provider PWM chip is looked up by name
+        * and a PWM device is requested using the PWM device per-chip index.
+        *
+        * The lookup algorithm was shamelessly taken from the clock
+        * framework:
+        *
+        * We do slightly fuzzy matching here:
+        *  An entry with a NULL ID is assumed to be a wildcard.
+        *  If an entry has a device ID, it must match
+        *  If an entry has a connection ID, it must match
+        * Then we take the most specific entry - with the following order
+        * of precedence: dev+con > dev only > con only.
+        */
+       mutex_lock(&pwm_lookup_lock);
+
+       list_for_each_entry(p, &pwm_lookup_list, list) {
+               match = 0;
+
+               if (p->dev_id) {
+                       if (!dev_id || strcmp(p->dev_id, dev_id))
+                               continue;
+
+                       match += 2;
+               }
+
+               if (p->con_id) {
+                       if (!con_id || strcmp(p->con_id, con_id))
+                               continue;
+
+                       match += 1;
+               }
+
+               if (match > best) {
+                       chip = pwmchip_find_by_name(p->provider);
+                       index = p->index;
+
+                       if (match != 3)
+                               best = match;
+                       else
+                               break;
+               }
+       }
+
+       if (chip)
+               pwm = pwm_request_from_chip(chip, index, con_id ?: dev_id);
+
+       mutex_unlock(&pwm_lookup_lock);
+
+       return pwm;
+}
+EXPORT_SYMBOL_GPL(pwm_get);
+
+/**
+ * pwm_put() - release a PWM device
+ * @pwm: PWM device
+ */
+void pwm_put(struct pwm_device *pwm)
+{
+       if (!pwm)
+               return;
+
+       mutex_lock(&pwm_lock);
+
+       if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) {
+               pr_warning("PWM device already freed\n");
+               goto out;
+       }
+
+       if (pwm->chip->ops->free)
+               pwm->chip->ops->free(pwm->chip, pwm);
+
+       pwm->label = NULL;
+
+       module_put(pwm->chip->ops->owner);
+out:
+       mutex_unlock(&pwm_lock);
+}
+EXPORT_SYMBOL_GPL(pwm_put);
+
+#ifdef CONFIG_DEBUG_FS
+static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
+{
+       unsigned int i;
+
+       for (i = 0; i < chip->npwm; i++) {
+               struct pwm_device *pwm = &chip->pwms[i];
+
+               seq_printf(s, " pwm-%-3d (%-20.20s):", i, pwm->label);
+
+               if (test_bit(PWMF_REQUESTED, &pwm->flags))
+                       seq_printf(s, " requested");
+
+               if (test_bit(PWMF_ENABLED, &pwm->flags))
+                       seq_printf(s, " enabled");
+
+               seq_printf(s, "\n");
+       }
+}
+
+static void *pwm_seq_start(struct seq_file *s, loff_t *pos)
+{
+       mutex_lock(&pwm_lock);
+       s->private = "";
+
+       return seq_list_start(&pwm_chips, *pos);
+}
+
+static void *pwm_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       s->private = "\n";
+
+       return seq_list_next(v, &pwm_chips, pos);
+}
+
+static void pwm_seq_stop(struct seq_file *s, void *v)
+{
+       mutex_unlock(&pwm_lock);
+}
+
+static int pwm_seq_show(struct seq_file *s, void *v)
+{
+       struct pwm_chip *chip = list_entry(v, struct pwm_chip, list);
+
+       seq_printf(s, "%s%s/%s, %d PWM device%s\n", (char *)s->private,
+                  chip->dev->bus ? chip->dev->bus->name : "no-bus",
+                  dev_name(chip->dev), chip->npwm,
+                  (chip->npwm != 1) ? "s" : "");
+
+       if (chip->ops->dbg_show)
+               chip->ops->dbg_show(chip, s);
+       else
+               pwm_dbg_show(chip, s);
+
+       return 0;
+}
+
+static const struct seq_operations pwm_seq_ops = {
+       .start = pwm_seq_start,
+       .next = pwm_seq_next,
+       .stop = pwm_seq_stop,
+       .show = pwm_seq_show,
+};
+
+static int pwm_seq_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &pwm_seq_ops);
+}
+
+static const struct file_operations pwm_debugfs_ops = {
+       .owner = THIS_MODULE,
+       .open = pwm_seq_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int __init pwm_debugfs_init(void)
+{
+       debugfs_create_file("pwm", S_IFREG | S_IRUGO, NULL, NULL,
+                           &pwm_debugfs_ops);
+
+       return 0;
+}
+
+subsys_initcall(pwm_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/pwm/pwm-bfin.c b/drivers/pwm/pwm-bfin.c
new file mode 100644 (file)
index 0000000..d53c4e7
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Blackfin Pulse Width Modulation (PWM) core
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#include <asm/gptimers.h>
+#include <asm/portmux.h>
+
+struct bfin_pwm_chip {
+       struct pwm_chip chip;
+};
+
+struct bfin_pwm {
+       unsigned short pin;
+};
+
+static const unsigned short pwm_to_gptimer_per[] = {
+       P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR4, P_TMR5,
+       P_TMR6, P_TMR7, P_TMR8, P_TMR9, P_TMR10, P_TMR11,
+};
+
+static int bfin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct bfin_pwm *priv;
+       int ret;
+
+       if (pwm->hwpwm >= ARRAY_SIZE(pwm_to_gptimer_per))
+               return -EINVAL;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->pin = pwm_to_gptimer_per[pwm->hwpwm];
+
+       ret = peripheral_request(priv->pin, NULL);
+       if (ret) {
+               kfree(priv);
+               return ret;
+       }
+
+       pwm_set_chip_data(pwm, priv);
+
+       return 0;
+}
+
+static void bfin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct bfin_pwm *priv = pwm_get_chip_data(pwm);
+
+       if (priv) {
+               peripheral_free(priv->pin);
+               kfree(priv);
+       }
+}
+
+static int bfin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+               int duty_ns, int period_ns)
+{
+       struct bfin_pwm *priv = pwm_get_chip_data(pwm);
+       unsigned long period, duty;
+       unsigned long long val;
+
+       if (duty_ns < 0 || duty_ns > period_ns)
+               return -EINVAL;
+
+       val = (unsigned long long)get_sclk() * period_ns;
+       do_div(val, NSEC_PER_SEC);
+       period = val;
+
+       val = (unsigned long long)period * duty_ns;
+       do_div(val, period_ns);
+       duty = period - val;
+
+       if (duty >= period)
+               duty = period - 1;
+
+       set_gptimer_config(priv->pin, TIMER_MODE_PWM | TIMER_PERIOD_CNT);
+       set_gptimer_pwidth(priv->pin, duty);
+       set_gptimer_period(priv->pin, period);
+
+       return 0;
+}
+
+static int bfin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct bfin_pwm *priv = pwm_get_chip_data(pwm);
+
+       enable_gptimer(priv->pin);
+
+       return 0;
+}
+
+static void bfin_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct bfin_pwm *priv = pwm_get_chip_data(pwm);
+
+       disable_gptimer(priv->pin);
+}
+
+static struct pwm_ops bfin_pwm_ops = {
+       .request = bfin_pwm_request,
+       .free = bfin_pwm_free,
+       .config = bfin_pwm_config,
+       .enable = bfin_pwm_enable,
+       .disable = bfin_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+static int bfin_pwm_probe(struct platform_device *pdev)
+{
+       struct bfin_pwm_chip *pwm;
+       int ret;
+
+       pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+       if (!pwm) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, pwm);
+
+       pwm->chip.dev = &pdev->dev;
+       pwm->chip.ops = &bfin_pwm_ops;
+       pwm->chip.base = -1;
+       pwm->chip.npwm = 12;
+
+       ret = pwmchip_add(&pwm->chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit bfin_pwm_remove(struct platform_device *pdev)
+{
+       struct bfin_pwm_chip *pwm = platform_get_drvdata(pdev);
+
+       return pwmchip_remove(&pwm->chip);
+}
+
+static struct platform_driver bfin_pwm_driver = {
+       .driver = {
+               .name = "bfin-pwm",
+       },
+       .probe = bfin_pwm_probe,
+       .remove = __devexit_p(bfin_pwm_remove),
+};
+
+module_platform_driver(bfin_pwm_driver);
+
+MODULE_LICENSE("GPL");
similarity index 50%
rename from arch/arm/plat-mxc/pwm.c
rename to drivers/pwm/pwm-imx.c
index c0cab2270dd171f64b713fb5b3a1700fb298900c..2a0b35333972836e0793fbe7a9f2e2c2de50e2af 100644 (file)
 #define MX3_PWMCR_CLKSRC_IPG      (1 << 16)
 #define MX3_PWMCR_EN              (1 << 0)
 
-
-
-struct pwm_device {
-       struct list_head        node;
-       struct platform_device *pdev;
-
-       const char      *label;
+struct imx_chip {
        struct clk      *clk;
 
        int             clk_enabled;
        void __iomem    *mmio_base;
 
-       unsigned int    use_count;
-       unsigned int    pwm_id;
+       struct pwm_chip chip;
 };
 
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+#define to_imx_chip(chip)      container_of(chip, struct imx_chip, chip)
+
+static int imx_pwm_config(struct pwm_chip *chip,
+               struct pwm_device *pwm, int duty_ns, int period_ns)
 {
-       if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
-               return -EINVAL;
+       struct imx_chip *imx = to_imx_chip(chip);
 
        if (!(cpu_is_mx1() || cpu_is_mx21())) {
                unsigned long long c;
                unsigned long period_cycles, duty_cycles, prescale;
                u32 cr;
 
-               c = clk_get_rate(pwm->clk);
+               c = clk_get_rate(imx->clk);
                c = c * period_ns;
                do_div(c, 1000000000);
                period_cycles = c;
@@ -86,8 +81,8 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
                else
                        period_cycles = 0;
 
-               writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR);
-               writel(period_cycles, pwm->mmio_base + MX3_PWMPR);
+               writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);
+               writel(period_cycles, imx->mmio_base + MX3_PWMPR);
 
                cr = MX3_PWMCR_PRESCALER(prescale) |
                        MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
@@ -98,7 +93,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
                else
                        cr |= MX3_PWMCR_CLKSRC_IPG_HIGH;
 
-               writel(cr, pwm->mmio_base + MX3_PWMCR);
+               writel(cr, imx->mmio_base + MX3_PWMCR);
        } else if (cpu_is_mx1() || cpu_is_mx21()) {
                /* The PWM subsystem allows for exact frequencies. However,
                 * I cannot connect a scope on my device to the PWM line and
@@ -116,191 +111,120 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
                 * both the prescaler (/1 .. /128) and then by CLKSEL
                 * (/2 .. /16).
                 */
-               u32 max = readl(pwm->mmio_base + MX1_PWMP);
+               u32 max = readl(imx->mmio_base + MX1_PWMP);
                u32 p = max * duty_ns / period_ns;
-               writel(max - p, pwm->mmio_base + MX1_PWMS);
+               writel(max - p, imx->mmio_base + MX1_PWMS);
        } else {
                BUG();
        }
 
        return 0;
 }
-EXPORT_SYMBOL(pwm_config);
 
-int pwm_enable(struct pwm_device *pwm)
+static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
+       struct imx_chip *imx = to_imx_chip(chip);
        int rc = 0;
 
-       if (!pwm->clk_enabled) {
-               rc = clk_prepare_enable(pwm->clk);
+       if (!imx->clk_enabled) {
+               rc = clk_prepare_enable(imx->clk);
                if (!rc)
-                       pwm->clk_enabled = 1;
+                       imx->clk_enabled = 1;
        }
        return rc;
 }
-EXPORT_SYMBOL(pwm_enable);
 
-void pwm_disable(struct pwm_device *pwm)
+static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-       writel(0, pwm->mmio_base + MX3_PWMCR);
+       struct imx_chip *imx = to_imx_chip(chip);
 
-       if (pwm->clk_enabled) {
-               clk_disable_unprepare(pwm->clk);
-               pwm->clk_enabled = 0;
-       }
-}
-EXPORT_SYMBOL(pwm_disable);
+       writel(0, imx->mmio_base + MX3_PWMCR);
 
-static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_list);
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-       struct pwm_device *pwm;
-       int found = 0;
-
-       mutex_lock(&pwm_lock);
-
-       list_for_each_entry(pwm, &pwm_list, node) {
-               if (pwm->pwm_id == pwm_id) {
-                       found = 1;
-                       break;
-               }
+       if (imx->clk_enabled) {
+               clk_disable_unprepare(imx->clk);
+               imx->clk_enabled = 0;
        }
-
-       if (found) {
-               if (pwm->use_count == 0) {
-                       pwm->use_count++;
-                       pwm->label = label;
-               } else
-                       pwm = ERR_PTR(-EBUSY);
-       } else
-               pwm = ERR_PTR(-ENOENT);
-
-       mutex_unlock(&pwm_lock);
-       return pwm;
 }
-EXPORT_SYMBOL(pwm_request);
 
-void pwm_free(struct pwm_device *pwm)
-{
-       mutex_lock(&pwm_lock);
-
-       if (pwm->use_count) {
-               pwm->use_count--;
-               pwm->label = NULL;
-       } else
-               pr_warning("PWM device already freed\n");
-
-       mutex_unlock(&pwm_lock);
-}
-EXPORT_SYMBOL(pwm_free);
+static struct pwm_ops imx_pwm_ops = {
+       .enable = imx_pwm_enable,
+       .disable = imx_pwm_disable,
+       .config = imx_pwm_config,
+       .owner = THIS_MODULE,
+};
 
-static int __devinit mxc_pwm_probe(struct platform_device *pdev)
+static int __devinit imx_pwm_probe(struct platform_device *pdev)
 {
-       struct pwm_device *pwm;
+       struct imx_chip *imx;
        struct resource *r;
        int ret = 0;
 
-       pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
-       if (pwm == NULL) {
+       imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
+       if (imx == NULL) {
                dev_err(&pdev->dev, "failed to allocate memory\n");
                return -ENOMEM;
        }
 
-       pwm->clk = clk_get(&pdev->dev, "pwm");
+       imx->clk = devm_clk_get(&pdev->dev, "pwm");
 
-       if (IS_ERR(pwm->clk)) {
-               ret = PTR_ERR(pwm->clk);
-               goto err_free;
-       }
+       if (IS_ERR(imx->clk))
+               return PTR_ERR(imx->clk);
 
-       pwm->clk_enabled = 0;
+       imx->chip.ops = &imx_pwm_ops;
+       imx->chip.dev = &pdev->dev;
+       imx->chip.base = -1;
+       imx->chip.npwm = 1;
 
-       pwm->use_count = 0;
-       pwm->pwm_id = pdev->id;
-       pwm->pdev = pdev;
+       imx->clk_enabled = 0;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (r == NULL) {
                dev_err(&pdev->dev, "no memory resource defined\n");
-               ret = -ENODEV;
-               goto err_free_clk;
-       }
-
-       r = request_mem_region(r->start, resource_size(r), pdev->name);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "failed to request memory resource\n");
-               ret = -EBUSY;
-               goto err_free_clk;
+               return -ENODEV;
        }
 
-       pwm->mmio_base = ioremap(r->start, resource_size(r));
-       if (pwm->mmio_base == NULL) {
-               dev_err(&pdev->dev, "failed to ioremap() registers\n");
-               ret = -ENODEV;
-               goto err_free_mem;
-       }
+       imx->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
+       if (imx->mmio_base == NULL)
+               return -EADDRNOTAVAIL;
 
-       mutex_lock(&pwm_lock);
-       list_add_tail(&pwm->node, &pwm_list);
-       mutex_unlock(&pwm_lock);
+       ret = pwmchip_add(&imx->chip);
+       if (ret < 0)
+               return ret;
 
-       platform_set_drvdata(pdev, pwm);
+       platform_set_drvdata(pdev, imx);
        return 0;
-
-err_free_mem:
-       release_mem_region(r->start, resource_size(r));
-err_free_clk:
-       clk_put(pwm->clk);
-err_free:
-       kfree(pwm);
-       return ret;
 }
 
-static int __devexit mxc_pwm_remove(struct platform_device *pdev)
+static int __devexit imx_pwm_remove(struct platform_device *pdev)
 {
-       struct pwm_device *pwm;
-       struct resource *r;
+       struct imx_chip *imx;
 
-       pwm = platform_get_drvdata(pdev);
-       if (pwm == NULL)
+       imx = platform_get_drvdata(pdev);
+       if (imx == NULL)
                return -ENODEV;
 
-       mutex_lock(&pwm_lock);
-       list_del(&pwm->node);
-       mutex_unlock(&pwm_lock);
-
-       iounmap(pwm->mmio_base);
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(r->start, resource_size(r));
-
-       clk_put(pwm->clk);
-
-       kfree(pwm);
-       return 0;
+       return pwmchip_remove(&imx->chip);
 }
 
-static struct platform_driver mxc_pwm_driver = {
+static struct platform_driver imx_pwm_driver = {
        .driver         = {
                .name   = "mxc_pwm",
        },
-       .probe          = mxc_pwm_probe,
-       .remove         = __devexit_p(mxc_pwm_remove),
+       .probe          = imx_pwm_probe,
+       .remove         = __devexit_p(imx_pwm_remove),
 };
 
-static int __init mxc_pwm_init(void)
+static int __init imx_pwm_init(void)
 {
-       return platform_driver_register(&mxc_pwm_driver);
+       return platform_driver_register(&imx_pwm_driver);
 }
-arch_initcall(mxc_pwm_init);
+arch_initcall(imx_pwm_init);
 
-static void __exit mxc_pwm_exit(void)
+static void __exit imx_pwm_exit(void)
 {
-       platform_driver_unregister(&mxc_pwm_driver);
+       platform_driver_unregister(&imx_pwm_driver);
 }
-module_exit(mxc_pwm_exit);
+module_exit(imx_pwm_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c
new file mode 100644 (file)
index 0000000..adb87f0
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2012 Alexandre Pereira da Silva <aletes.xgr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+struct lpc32xx_pwm_chip {
+       struct pwm_chip chip;
+       struct clk *clk;
+       void __iomem *base;
+};
+
+#define PWM_ENABLE     (1 << 31)
+#define PWM_RELOADV(x) (((x) & 0xFF) << 8)
+#define PWM_DUTY(x)    ((x) & 0xFF)
+
+#define to_lpc32xx_pwm_chip(_chip) \
+       container_of(_chip, struct lpc32xx_pwm_chip, chip)
+
+static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                             int duty_ns, int period_ns)
+{
+       struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip);
+       unsigned long long c;
+       int period_cycles, duty_cycles;
+
+       c = clk_get_rate(lpc32xx->clk) / 256;
+       c = c * period_ns;
+       do_div(c, NSEC_PER_SEC);
+
+       /* Handle high and low extremes */
+       if (c == 0)
+               c = 1;
+       if (c > 255)
+               c = 0; /* 0 set division by 256 */
+       period_cycles = c;
+
+       c = 256 * duty_ns;
+       do_div(c, period_ns);
+       duty_cycles = c;
+
+       writel(PWM_ENABLE | PWM_RELOADV(period_cycles) | PWM_DUTY(duty_cycles),
+               lpc32xx->base + (pwm->hwpwm << 2));
+
+       return 0;
+}
+
+static int lpc32xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip);
+
+       return clk_enable(lpc32xx->clk);
+}
+
+static void lpc32xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct lpc32xx_pwm_chip *lpc32xx = to_lpc32xx_pwm_chip(chip);
+
+       writel(0, lpc32xx->base + (pwm->hwpwm << 2));
+       clk_disable(lpc32xx->clk);
+}
+
+static const struct pwm_ops lpc32xx_pwm_ops = {
+       .config = lpc32xx_pwm_config,
+       .enable = lpc32xx_pwm_enable,
+       .disable = lpc32xx_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+static int lpc32xx_pwm_probe(struct platform_device *pdev)
+{
+       struct lpc32xx_pwm_chip *lpc32xx;
+       struct resource *res;
+       int ret;
+
+       lpc32xx = devm_kzalloc(&pdev->dev, sizeof(*lpc32xx), GFP_KERNEL);
+       if (!lpc32xx)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
+       lpc32xx->base = devm_request_and_ioremap(&pdev->dev, res);
+       if (!lpc32xx->base)
+               return -EADDRNOTAVAIL;
+
+       lpc32xx->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(lpc32xx->clk))
+               return PTR_ERR(lpc32xx->clk);
+
+       lpc32xx->chip.dev = &pdev->dev;
+       lpc32xx->chip.ops = &lpc32xx_pwm_ops;
+       lpc32xx->chip.npwm = 2;
+
+       ret = pwmchip_add(&lpc32xx->chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to add PWM chip, error %d\n", ret);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, lpc32xx);
+
+       return 0;
+}
+
+static int __devexit lpc32xx_pwm_remove(struct platform_device *pdev)
+{
+       struct lpc32xx_pwm_chip *lpc32xx = platform_get_drvdata(pdev);
+
+       clk_disable(lpc32xx->clk);
+       return pwmchip_remove(&lpc32xx->chip);
+}
+
+static struct of_device_id lpc32xx_pwm_dt_ids[] = {
+       { .compatible = "nxp,lpc3220-pwm", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_pwm_dt_ids);
+
+static struct platform_driver lpc32xx_pwm_driver = {
+       .driver = {
+               .name = "lpc32xx-pwm",
+               .of_match_table = of_match_ptr(lpc32xx_pwm_dt_ids),
+       },
+       .probe = lpc32xx_pwm_probe,
+       .remove = __devexit_p(lpc32xx_pwm_remove),
+};
+module_platform_driver(lpc32xx_pwm_driver);
+
+MODULE_ALIAS("platform:lpc32xx-pwm");
+MODULE_AUTHOR("Alexandre Pereira da Silva <aletes.xgr@gmail.com>");
+MODULE_DESCRIPTION("LPC32XX PWM Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c
new file mode 100644 (file)
index 0000000..e585264
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/stmp_device.h>
+
+#define SET    0x4
+#define CLR    0x8
+#define TOG    0xc
+
+#define PWM_CTRL               0x0
+#define PWM_ACTIVE0            0x10
+#define PWM_PERIOD0            0x20
+#define  PERIOD_PERIOD(p)      ((p) & 0xffff)
+#define  PERIOD_PERIOD_MAX     0x10000
+#define  PERIOD_ACTIVE_HIGH    (3 << 16)
+#define  PERIOD_INACTIVE_LOW   (2 << 18)
+#define  PERIOD_CDIV(div)      (((div) & 0x7) << 20)
+#define  PERIOD_CDIV_MAX       8
+
+struct mxs_pwm_chip {
+       struct pwm_chip chip;
+       struct device *dev;
+       struct clk *clk;
+       void __iomem *base;
+};
+
+#define to_mxs_pwm_chip(_chip) container_of(_chip, struct mxs_pwm_chip, chip)
+
+static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                         int duty_ns, int period_ns)
+{
+       struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip);
+       int ret, div = 0;
+       unsigned int period_cycles, duty_cycles;
+       unsigned long rate;
+       unsigned long long c;
+
+       rate = clk_get_rate(mxs->clk);
+       while (1) {
+               c = rate / (1 << div);
+               c = c * period_ns;
+               do_div(c, 1000000000);
+               if (c < PERIOD_PERIOD_MAX)
+                       break;
+               div++;
+               if (div > PERIOD_CDIV_MAX)
+                       return -EINVAL;
+       }
+
+       period_cycles = c;
+       c *= duty_ns;
+       do_div(c, period_ns);
+       duty_cycles = c;
+
+       /*
+        * If the PWM channel is disabled, make sure to turn on the clock
+        * before writing the register. Otherwise, keep it enabled.
+        */
+       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+               ret = clk_prepare_enable(mxs->clk);
+               if (ret)
+                       return ret;
+       }
+
+       writel(duty_cycles << 16,
+                       mxs->base + PWM_ACTIVE0 + pwm->hwpwm * 0x20);
+       writel(PERIOD_PERIOD(period_cycles) | PERIOD_ACTIVE_HIGH |
+              PERIOD_INACTIVE_LOW | PERIOD_CDIV(div),
+                       mxs->base + PWM_PERIOD0 + pwm->hwpwm * 0x20);
+
+       /*
+        * If the PWM is not enabled, turn the clock off again to save power.
+        */
+       if (!test_bit(PWMF_ENABLED, &pwm->flags))
+               clk_disable_unprepare(mxs->clk);
+
+       return 0;
+}
+
+static int mxs_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip);
+       int ret;
+
+       ret = clk_prepare_enable(mxs->clk);
+       if (ret)
+               return ret;
+
+       writel(1 << pwm->hwpwm, mxs->base + PWM_CTRL + SET);
+
+       return 0;
+}
+
+static void mxs_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip);
+
+       writel(1 << pwm->hwpwm, mxs->base + PWM_CTRL + CLR);
+
+       clk_disable_unprepare(mxs->clk);
+}
+
+static const struct pwm_ops mxs_pwm_ops = {
+       .config = mxs_pwm_config,
+       .enable = mxs_pwm_enable,
+       .disable = mxs_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+static int mxs_pwm_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct mxs_pwm_chip *mxs;
+       struct resource *res;
+       struct pinctrl *pinctrl;
+       int ret;
+
+       mxs = devm_kzalloc(&pdev->dev, sizeof(*mxs), GFP_KERNEL);
+       if (!mxs)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mxs->base = devm_request_and_ioremap(&pdev->dev, res);
+       if (!mxs->base)
+               return -EADDRNOTAVAIL;
+
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl))
+               return PTR_ERR(pinctrl);
+
+       mxs->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(mxs->clk))
+               return PTR_ERR(mxs->clk);
+
+       mxs->chip.dev = &pdev->dev;
+       mxs->chip.ops = &mxs_pwm_ops;
+       mxs->chip.base = -1;
+       ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to get pwm number: %d\n", ret);
+               return ret;
+       }
+
+       ret = pwmchip_add(&mxs->chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to add pwm chip %d\n", ret);
+               return ret;
+       }
+
+       mxs->dev = &pdev->dev;
+       platform_set_drvdata(pdev, mxs);
+
+       stmp_reset_block(mxs->base);
+
+       return 0;
+}
+
+static int __devexit mxs_pwm_remove(struct platform_device *pdev)
+{
+       struct mxs_pwm_chip *mxs = platform_get_drvdata(pdev);
+
+       return pwmchip_remove(&mxs->chip);
+}
+
+static struct of_device_id mxs_pwm_dt_ids[] = {
+       { .compatible = "fsl,imx23-pwm", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_pwm_dt_ids);
+
+static struct platform_driver mxs_pwm_driver = {
+       .driver = {
+               .name = "mxs-pwm",
+               .of_match_table = of_match_ptr(mxs_pwm_dt_ids),
+       },
+       .probe = mxs_pwm_probe,
+       .remove = __devexit_p(mxs_pwm_remove),
+};
+module_platform_driver(mxs_pwm_driver);
+
+MODULE_ALIAS("platform:mxs-pwm");
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("Freescale MXS PWM Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
new file mode 100644 (file)
index 0000000..bd5867a
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * drivers/pwm/pwm-pxa.c
+ *
+ * simple driver for PWM (Pulse Width Modulator) controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 2008-02-13  initial version
+ *             eric miao <eric.miao@marvell.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+
+#include <asm/div64.h>
+
+#define HAS_SECONDARY_PWM      0x10
+#define PWM_ID_BASE(d)         ((d) & 0xf)
+
+static const struct platform_device_id pwm_id_table[] = {
+       /*   PWM    has_secondary_pwm? */
+       { "pxa25x-pwm", 0 },
+       { "pxa27x-pwm", 0 | HAS_SECONDARY_PWM },
+       { "pxa168-pwm", 1 },
+       { "pxa910-pwm", 1 },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, pwm_id_table);
+
+/* PWM registers and bits definitions */
+#define PWMCR          (0x00)
+#define PWMDCR         (0x04)
+#define PWMPCR         (0x08)
+
+#define PWMCR_SD       (1 << 6)
+#define PWMDCR_FD      (1 << 10)
+
+struct pxa_pwm_chip {
+       struct pwm_chip chip;
+       struct device   *dev;
+
+       struct clk      *clk;
+       int             clk_enabled;
+       void __iomem    *mmio_base;
+};
+
+static inline struct pxa_pwm_chip *to_pxa_pwm_chip(struct pwm_chip *chip)
+{
+       return container_of(chip, struct pxa_pwm_chip, chip);
+}
+
+/*
+ * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
+ * duty_ns   = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
+ */
+static int pxa_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                         int duty_ns, int period_ns)
+{
+       struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
+       unsigned long long c;
+       unsigned long period_cycles, prescale, pv, dc;
+       unsigned long offset;
+       int rc;
+
+       if (period_ns == 0 || duty_ns > period_ns)
+               return -EINVAL;
+
+       offset = pwm->hwpwm ? 0x10 : 0;
+
+       c = clk_get_rate(pc->clk);
+       c = c * period_ns;
+       do_div(c, 1000000000);
+       period_cycles = c;
+
+       if (period_cycles < 1)
+               period_cycles = 1;
+       prescale = (period_cycles - 1) / 1024;
+       pv = period_cycles / (prescale + 1) - 1;
+
+       if (prescale > 63)
+               return -EINVAL;
+
+       if (duty_ns == period_ns)
+               dc = PWMDCR_FD;
+       else
+               dc = (pv + 1) * duty_ns / period_ns;
+
+       /* NOTE: the clock to PWM has to be enabled first
+        * before writing to the registers
+        */
+       rc = clk_prepare_enable(pc->clk);
+       if (rc < 0)
+               return rc;
+
+       writel(prescale, pc->mmio_base + offset + PWMCR);
+       writel(dc, pc->mmio_base + offset + PWMDCR);
+       writel(pv, pc->mmio_base + offset + PWMPCR);
+
+       clk_disable_unprepare(pc->clk);
+       return 0;
+}
+
+static int pxa_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
+       int rc = 0;
+
+       if (!pc->clk_enabled) {
+               rc = clk_prepare_enable(pc->clk);
+               if (!rc)
+                       pc->clk_enabled++;
+       }
+       return rc;
+}
+
+static void pxa_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct pxa_pwm_chip *pc = to_pxa_pwm_chip(chip);
+
+       if (pc->clk_enabled) {
+               clk_disable_unprepare(pc->clk);
+               pc->clk_enabled--;
+       }
+}
+
+static struct pwm_ops pxa_pwm_ops = {
+       .config = pxa_pwm_config,
+       .enable = pxa_pwm_enable,
+       .disable = pxa_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+static int __devinit pwm_probe(struct platform_device *pdev)
+{
+       const struct platform_device_id *id = platform_get_device_id(pdev);
+       struct pxa_pwm_chip *pwm;
+       struct resource *r;
+       int ret = 0;
+
+       pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+       if (pwm == NULL) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       pwm->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(pwm->clk))
+               return PTR_ERR(pwm->clk);
+
+       pwm->clk_enabled = 0;
+
+       pwm->chip.dev = &pdev->dev;
+       pwm->chip.ops = &pxa_pwm_ops;
+       pwm->chip.base = -1;
+       pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               dev_err(&pdev->dev, "no memory resource defined\n");
+               return -ENODEV;
+       }
+
+       pwm->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
+       if (pwm->mmio_base == NULL)
+               return -EADDRNOTAVAIL;
+
+       ret = pwmchip_add(&pwm->chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, pwm);
+       return 0;
+}
+
+static int __devexit pwm_remove(struct platform_device *pdev)
+{
+       struct pxa_pwm_chip *chip;
+
+       chip = platform_get_drvdata(pdev);
+       if (chip == NULL)
+               return -ENODEV;
+
+       return pwmchip_remove(&chip->chip);
+}
+
+static struct platform_driver pwm_driver = {
+       .driver         = {
+               .name   = "pxa25x-pwm",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = pwm_probe,
+       .remove         = __devexit_p(pwm_remove),
+       .id_table       = pwm_id_table,
+};
+
+static int __init pwm_init(void)
+{
+       return platform_driver_register(&pwm_driver);
+}
+arch_initcall(pwm_init);
+
+static void __exit pwm_exit(void)
+{
+       platform_driver_unregister(&pwm_driver);
+}
+module_exit(pwm_exit);
+
+MODULE_LICENSE("GPL v2");
similarity index 56%
rename from arch/arm/plat-samsung/pwm.c
rename to drivers/pwm/pwm-samsung.c
index d3583050fb05461d83af523a9d1f909d9994c094..d10386528c9ce4c684413f750960b23a12225fa8 100644 (file)
@@ -1,4 +1,4 @@
-/* arch/arm/plat-s3c/pwm.c
+/* drivers/pwm/pwm-samsung.c
  *
  * Copyright (c) 2007 Ben Dooks
  * Copyright (c) 2008 Simtec Electronics
@@ -11,6 +11,8 @@
  * the Free Software Foundation; either version 2 of the License.
 */
 
+#define pr_fmt(fmt) "pwm-samsung: " fmt
+
 #include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
@@ -24,8 +26,7 @@
 
 #include <plat/regs-timer.h>
 
-struct pwm_device {
-       struct list_head         list;
+struct s3c_chip {
        struct platform_device  *pdev;
 
        struct clk              *clk_div;
@@ -36,81 +37,36 @@ struct pwm_device {
        unsigned int             duty_ns;
 
        unsigned char            tcon_base;
-       unsigned char            use_count;
        unsigned char            pwm_id;
+       struct pwm_chip          chip;
 };
 
+#define to_s3c_chip(chip)      container_of(chip, struct s3c_chip, chip)
+
 #define pwm_dbg(_pwm, msg...) dev_dbg(&(_pwm)->pdev->dev, msg)
 
 static struct clk *clk_scaler[2];
 
-static inline int pwm_is_tdiv(struct pwm_device *pwm)
-{
-       return clk_get_parent(pwm->clk) == pwm->clk_div;
-}
-
-static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_list);
-
-struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-       struct pwm_device *pwm;
-       int found = 0;
-
-       mutex_lock(&pwm_lock);
-
-       list_for_each_entry(pwm, &pwm_list, list) {
-               if (pwm->pwm_id == pwm_id) {
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (found) {
-               if (pwm->use_count == 0) {
-                       pwm->use_count = 1;
-                       pwm->label = label;
-               } else
-                       pwm = ERR_PTR(-EBUSY);
-       } else
-               pwm = ERR_PTR(-ENOENT);
-
-       mutex_unlock(&pwm_lock);
-       return pwm;
-}
-
-EXPORT_SYMBOL(pwm_request);
-
-
-void pwm_free(struct pwm_device *pwm)
+static inline int pwm_is_tdiv(struct s3c_chip *chip)
 {
-       mutex_lock(&pwm_lock);
-
-       if (pwm->use_count) {
-               pwm->use_count--;
-               pwm->label = NULL;
-       } else
-               printk(KERN_ERR "PWM%d device already freed\n", pwm->pwm_id);
-
-       mutex_unlock(&pwm_lock);
+       return clk_get_parent(chip->clk) == chip->clk_div;
 }
 
-EXPORT_SYMBOL(pwm_free);
-
 #define pwm_tcon_start(pwm) (1 << (pwm->tcon_base + 0))
 #define pwm_tcon_invert(pwm) (1 << (pwm->tcon_base + 2))
 #define pwm_tcon_autoreload(pwm) (1 << (pwm->tcon_base + 3))
 #define pwm_tcon_manulupdate(pwm) (1 << (pwm->tcon_base + 1))
 
-int pwm_enable(struct pwm_device *pwm)
+static int s3c_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
+       struct s3c_chip *s3c = to_s3c_chip(chip);
        unsigned long flags;
        unsigned long tcon;
 
        local_irq_save(flags);
 
        tcon = __raw_readl(S3C2410_TCON);
-       tcon |= pwm_tcon_start(pwm);
+       tcon |= pwm_tcon_start(s3c);
        __raw_writel(tcon, S3C2410_TCON);
 
        local_irq_restore(flags);
@@ -118,31 +74,28 @@ int pwm_enable(struct pwm_device *pwm)
        return 0;
 }
 
-EXPORT_SYMBOL(pwm_enable);
-
-void pwm_disable(struct pwm_device *pwm)
+static void s3c_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
+       struct s3c_chip *s3c = to_s3c_chip(chip);
        unsigned long flags;
        unsigned long tcon;
 
        local_irq_save(flags);
 
        tcon = __raw_readl(S3C2410_TCON);
-       tcon &= ~pwm_tcon_start(pwm);
+       tcon &= ~pwm_tcon_start(s3c);
        __raw_writel(tcon, S3C2410_TCON);
 
        local_irq_restore(flags);
 }
 
-EXPORT_SYMBOL(pwm_disable);
-
-static unsigned long pwm_calc_tin(struct pwm_device *pwm, unsigned long freq)
+static unsigned long pwm_calc_tin(struct s3c_chip *s3c, unsigned long freq)
 {
        unsigned long tin_parent_rate;
        unsigned int div;
 
-       tin_parent_rate = clk_get_rate(clk_get_parent(pwm->clk_div));
-       pwm_dbg(pwm, "tin parent at %lu\n", tin_parent_rate);
+       tin_parent_rate = clk_get_rate(clk_get_parent(s3c->clk_div));
+       pwm_dbg(s3c, "tin parent at %lu\n", tin_parent_rate);
 
        for (div = 2; div <= 16; div *= 2) {
                if ((tin_parent_rate / (div << 16)) < freq)
@@ -154,8 +107,10 @@ static unsigned long pwm_calc_tin(struct pwm_device *pwm, unsigned long freq)
 
 #define NS_IN_HZ (1000000000UL)
 
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+static int s3c_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+               int duty_ns, int period_ns)
 {
+       struct s3c_chip *s3c = to_s3c_chip(chip);
        unsigned long tin_rate;
        unsigned long tin_ns;
        unsigned long period;
@@ -174,38 +129,38 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
        if (duty_ns > period_ns)
                return -EINVAL;
 
-       if (period_ns == pwm->period_ns &&
-           duty_ns == pwm->duty_ns)
+       if (period_ns == s3c->period_ns &&
+           duty_ns == s3c->duty_ns)
                return 0;
 
        /* The TCMP and TCNT can be read without a lock, they're not
         * shared between the timers. */
 
-       tcmp = __raw_readl(S3C2410_TCMPB(pwm->pwm_id));
-       tcnt = __raw_readl(S3C2410_TCNTB(pwm->pwm_id));
+       tcmp = __raw_readl(S3C2410_TCMPB(s3c->pwm_id));
+       tcnt = __raw_readl(S3C2410_TCNTB(s3c->pwm_id));
 
        period = NS_IN_HZ / period_ns;
 
-       pwm_dbg(pwm, "duty_ns=%d, period_ns=%d (%lu)\n",
+       pwm_dbg(s3c, "duty_ns=%d, period_ns=%d (%lu)\n",
                duty_ns, period_ns, period);
 
        /* Check to see if we are changing the clock rate of the PWM */
 
-       if (pwm->period_ns != period_ns) {
-               if (pwm_is_tdiv(pwm)) {
-                       tin_rate = pwm_calc_tin(pwm, period);
-                       clk_set_rate(pwm->clk_div, tin_rate);
+       if (s3c->period_ns != period_ns) {
+               if (pwm_is_tdiv(s3c)) {
+                       tin_rate = pwm_calc_tin(s3c, period);
+                       clk_set_rate(s3c->clk_div, tin_rate);
                } else
-                       tin_rate = clk_get_rate(pwm->clk);
+                       tin_rate = clk_get_rate(s3c->clk);
 
-               pwm->period_ns = period_ns;
+               s3c->period_ns = period_ns;
 
-               pwm_dbg(pwm, "tin_rate=%lu\n", tin_rate);
+               pwm_dbg(s3c, "tin_rate=%lu\n", tin_rate);
 
                tin_ns = NS_IN_HZ / tin_rate;
                tcnt = period_ns / tin_ns;
        } else
-               tin_ns = NS_IN_HZ / clk_get_rate(pwm->clk);
+               tin_ns = NS_IN_HZ / clk_get_rate(s3c->clk);
 
        /* Note, counters count down */
 
@@ -216,7 +171,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
        if (tcmp == tcnt)
                tcmp--;
 
-       pwm_dbg(pwm, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt);
+       pwm_dbg(s3c, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt);
 
        if (tcmp < 0)
                tcmp = 0;
@@ -225,15 +180,15 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
 
        local_irq_save(flags);
 
-       __raw_writel(tcmp, S3C2410_TCMPB(pwm->pwm_id));
-       __raw_writel(tcnt, S3C2410_TCNTB(pwm->pwm_id));
+       __raw_writel(tcmp, S3C2410_TCMPB(s3c->pwm_id));
+       __raw_writel(tcnt, S3C2410_TCNTB(s3c->pwm_id));
 
        tcon = __raw_readl(S3C2410_TCON);
-       tcon |= pwm_tcon_manulupdate(pwm);
-       tcon |= pwm_tcon_autoreload(pwm);
+       tcon |= pwm_tcon_manulupdate(s3c);
+       tcon |= pwm_tcon_autoreload(s3c);
        __raw_writel(tcon, S3C2410_TCON);
 
-       tcon &= ~pwm_tcon_manulupdate(pwm);
+       tcon &= ~pwm_tcon_manulupdate(s3c);
        __raw_writel(tcon, S3C2410_TCON);
 
        local_irq_restore(flags);
@@ -241,24 +196,17 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
        return 0;
 }
 
-EXPORT_SYMBOL(pwm_config);
-
-static int pwm_register(struct pwm_device *pwm)
-{
-       pwm->duty_ns = -1;
-       pwm->period_ns = -1;
-
-       mutex_lock(&pwm_lock);
-       list_add_tail(&pwm->list, &pwm_list);
-       mutex_unlock(&pwm_lock);
-
-       return 0;
-}
+static struct pwm_ops s3c_pwm_ops = {
+       .enable = s3c_pwm_enable,
+       .disable = s3c_pwm_disable,
+       .config = s3c_pwm_config,
+       .owner = THIS_MODULE,
+};
 
 static int s3c_pwm_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct pwm_device *pwm;
+       struct s3c_chip *s3c;
        unsigned long flags;
        unsigned long tcon;
        unsigned int id = pdev->id;
@@ -269,83 +217,75 @@ static int s3c_pwm_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
-       if (pwm == NULL) {
+       s3c = devm_kzalloc(&pdev->dev, sizeof(*s3c), GFP_KERNEL);
+       if (s3c == NULL) {
                dev_err(dev, "failed to allocate pwm_device\n");
                return -ENOMEM;
        }
 
-       pwm->pdev = pdev;
-       pwm->pwm_id = id;
-
        /* calculate base of control bits in TCON */
-       pwm->tcon_base = id == 0 ? 0 : (id * 4) + 4;
+       s3c->tcon_base = id == 0 ? 0 : (id * 4) + 4;
+       s3c->chip.ops = &s3c_pwm_ops;
+       s3c->chip.base = -1;
+       s3c->chip.npwm = 1;
 
-       pwm->clk = clk_get(dev, "pwm-tin");
-       if (IS_ERR(pwm->clk)) {
+       s3c->clk = devm_clk_get(dev, "pwm-tin");
+       if (IS_ERR(s3c->clk)) {
                dev_err(dev, "failed to get pwm tin clk\n");
-               ret = PTR_ERR(pwm->clk);
-               goto err_alloc;
+               return PTR_ERR(s3c->clk);
        }
 
-       pwm->clk_div = clk_get(dev, "pwm-tdiv");
-       if (IS_ERR(pwm->clk_div)) {
+       s3c->clk_div = devm_clk_get(dev, "pwm-tdiv");
+       if (IS_ERR(s3c->clk_div)) {
                dev_err(dev, "failed to get pwm tdiv clk\n");
-               ret = PTR_ERR(pwm->clk_div);
-               goto err_clk_tin;
+               return PTR_ERR(s3c->clk_div);
        }
 
-       clk_enable(pwm->clk);
-       clk_enable(pwm->clk_div);
+       clk_enable(s3c->clk);
+       clk_enable(s3c->clk_div);
 
        local_irq_save(flags);
 
        tcon = __raw_readl(S3C2410_TCON);
-       tcon |= pwm_tcon_invert(pwm);
+       tcon |= pwm_tcon_invert(s3c);
        __raw_writel(tcon, S3C2410_TCON);
 
        local_irq_restore(flags);
 
-
-       ret = pwm_register(pwm);
-       if (ret) {
+       ret = pwmchip_add(&s3c->chip);
+       if (ret < 0) {
                dev_err(dev, "failed to register pwm\n");
                goto err_clk_tdiv;
        }
 
-       pwm_dbg(pwm, "config bits %02x\n",
-               (__raw_readl(S3C2410_TCON) >> pwm->tcon_base) & 0x0f);
+       pwm_dbg(s3c, "config bits %02x\n",
+               (__raw_readl(S3C2410_TCON) >> s3c->tcon_base) & 0x0f);
 
        dev_info(dev, "tin at %lu, tdiv at %lu, tin=%sclk, base %d\n",
-                clk_get_rate(pwm->clk),
-                clk_get_rate(pwm->clk_div),
-                pwm_is_tdiv(pwm) ? "div" : "ext", pwm->tcon_base);
+                clk_get_rate(s3c->clk),
+                clk_get_rate(s3c->clk_div),
+                pwm_is_tdiv(s3c) ? "div" : "ext", s3c->tcon_base);
 
-       platform_set_drvdata(pdev, pwm);
+       platform_set_drvdata(pdev, s3c);
        return 0;
 
  err_clk_tdiv:
-       clk_disable(pwm->clk_div);
-       clk_disable(pwm->clk);
-       clk_put(pwm->clk_div);
-
- err_clk_tin:
-       clk_put(pwm->clk);
-
- err_alloc:
-       kfree(pwm);
+       clk_disable(s3c->clk_div);
+       clk_disable(s3c->clk);
        return ret;
 }
 
 static int __devexit s3c_pwm_remove(struct platform_device *pdev)
 {
-       struct pwm_device *pwm = platform_get_drvdata(pdev);
+       struct s3c_chip *s3c = platform_get_drvdata(pdev);
+       int err;
+
+       err = pwmchip_remove(&s3c->chip);
+       if (err < 0)
+               return err;
 
-       clk_disable(pwm->clk_div);
-       clk_disable(pwm->clk);
-       clk_put(pwm->clk_div);
-       clk_put(pwm->clk);
-       kfree(pwm);
+       clk_disable(s3c->clk_div);
+       clk_disable(s3c->clk);
 
        return 0;
 }
@@ -353,26 +293,26 @@ static int __devexit s3c_pwm_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int s3c_pwm_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct pwm_device *pwm = platform_get_drvdata(pdev);
+       struct s3c_chip *s3c = platform_get_drvdata(pdev);
 
        /* No one preserve these values during suspend so reset them
         * Otherwise driver leaves PWM unconfigured if same values
         * passed to pwm_config
         */
-       pwm->period_ns = 0;
-       pwm->duty_ns = 0;
+       s3c->period_ns = 0;
+       s3c->duty_ns = 0;
 
        return 0;
 }
 
 static int s3c_pwm_resume(struct platform_device *pdev)
 {
-       struct pwm_device *pwm = platform_get_drvdata(pdev);
+       struct s3c_chip *s3c = platform_get_drvdata(pdev);
        unsigned long tcon;
 
        /* Restore invertion */
        tcon = __raw_readl(S3C2410_TCON);
-       tcon |= pwm_tcon_invert(pwm);
+       tcon |= pwm_tcon_invert(s3c);
        __raw_writel(tcon, S3C2410_TCON);
 
        return 0;
@@ -402,13 +342,13 @@ static int __init pwm_init(void)
        clk_scaler[1] = clk_get(NULL, "pwm-scaler1");
 
        if (IS_ERR(clk_scaler[0]) || IS_ERR(clk_scaler[1])) {
-               printk(KERN_ERR "%s: failed to get scaler clocks\n", __func__);
+               pr_err("failed to get scaler clocks\n");
                return -EINVAL;
        }
 
        ret = platform_driver_register(&s3c_pwm_driver);
        if (ret)
-               printk(KERN_ERR "%s: failed to add pwm driver\n", __func__);
+               pr_err("failed to add pwm driver\n");
 
        return ret;
 }
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
new file mode 100644 (file)
index 0000000..02ce18d
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * drivers/pwm/pwm-tegra.c
+ *
+ * Tegra pulse-width-modulation controller driver
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ * Based on arch/arm/plat-mxc/pwm.c by Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pwm.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define PWM_ENABLE     (1 << 31)
+#define PWM_DUTY_WIDTH 8
+#define PWM_DUTY_SHIFT 16
+#define PWM_SCALE_WIDTH        13
+#define PWM_SCALE_SHIFT        0
+
+#define NUM_PWM 4
+
+struct tegra_pwm_chip {
+       struct pwm_chip         chip;
+       struct device           *dev;
+
+       struct clk              *clk;
+
+       void __iomem            *mmio_base;
+};
+
+static inline struct tegra_pwm_chip *to_tegra_pwm_chip(struct pwm_chip *chip)
+{
+       return container_of(chip, struct tegra_pwm_chip, chip);
+}
+
+static inline u32 pwm_readl(struct tegra_pwm_chip *chip, unsigned int num)
+{
+       return readl(chip->mmio_base + (num << 4));
+}
+
+static inline void pwm_writel(struct tegra_pwm_chip *chip, unsigned int num,
+                            unsigned long val)
+{
+       writel(val, chip->mmio_base + (num << 4));
+}
+
+static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                           int duty_ns, int period_ns)
+{
+       struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
+       unsigned long long c;
+       unsigned long rate, hz;
+       u32 val = 0;
+       int err;
+
+       /*
+        * Convert from duty_ns / period_ns to a fixed number of duty ticks
+        * per (1 << PWM_DUTY_WIDTH) cycles and make sure to round to the
+        * nearest integer during division.
+        */
+       c = duty_ns * ((1 << PWM_DUTY_WIDTH) - 1) + period_ns / 2;
+       do_div(c, period_ns);
+
+       val = (u32)c << PWM_DUTY_SHIFT;
+
+       /*
+        * Compute the prescaler value for which (1 << PWM_DUTY_WIDTH)
+        * cycles at the PWM clock rate will take period_ns nanoseconds.
+        */
+       rate = clk_get_rate(pc->clk) >> PWM_DUTY_WIDTH;
+       hz = 1000000000ul / period_ns;
+
+       rate = (rate + (hz / 2)) / hz;
+
+       /*
+        * Since the actual PWM divider is the register's frequency divider
+        * field minus 1, we need to decrement to get the correct value to
+        * write to the register.
+        */
+       if (rate > 0)
+               rate--;
+
+       /*
+        * Make sure that the rate will fit in the register's frequency
+        * divider field.
+        */
+       if (rate >> PWM_SCALE_WIDTH)
+               return -EINVAL;
+
+       val |= rate << PWM_SCALE_SHIFT;
+
+       /*
+        * If the PWM channel is disabled, make sure to turn on the clock
+        * before writing the register. Otherwise, keep it enabled.
+        */
+       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+               err = clk_prepare_enable(pc->clk);
+               if (err < 0)
+                       return err;
+       } else
+               val |= PWM_ENABLE;
+
+       pwm_writel(pc, pwm->hwpwm, val);
+
+       /*
+        * If the PWM is not enabled, turn the clock off again to save power.
+        */
+       if (!test_bit(PWMF_ENABLED, &pwm->flags))
+               clk_disable_unprepare(pc->clk);
+
+       return 0;
+}
+
+static int tegra_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
+       int rc = 0;
+       u32 val;
+
+       rc = clk_prepare_enable(pc->clk);
+       if (rc < 0)
+               return rc;
+
+       val = pwm_readl(pc, pwm->hwpwm);
+       val |= PWM_ENABLE;
+       pwm_writel(pc, pwm->hwpwm, val);
+
+       return 0;
+}
+
+static void tegra_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
+       u32 val;
+
+       val = pwm_readl(pc, pwm->hwpwm);
+       val &= ~PWM_ENABLE;
+       pwm_writel(pc, pwm->hwpwm, val);
+
+       clk_disable_unprepare(pc->clk);
+}
+
+static const struct pwm_ops tegra_pwm_ops = {
+       .config = tegra_pwm_config,
+       .enable = tegra_pwm_enable,
+       .disable = tegra_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+static int tegra_pwm_probe(struct platform_device *pdev)
+{
+       struct tegra_pwm_chip *pwm;
+       struct resource *r;
+       int ret;
+
+       pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+       if (!pwm) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       pwm->dev = &pdev->dev;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pdev->dev, "no memory resources defined\n");
+               return -ENODEV;
+       }
+
+       pwm->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
+       if (!pwm->mmio_base) {
+               dev_err(&pdev->dev, "failed to ioremap() region\n");
+               return -EADDRNOTAVAIL;
+       }
+
+       platform_set_drvdata(pdev, pwm);
+
+       pwm->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(pwm->clk))
+               return PTR_ERR(pwm->clk);
+
+       pwm->chip.dev = &pdev->dev;
+       pwm->chip.ops = &tegra_pwm_ops;
+       pwm->chip.base = -1;
+       pwm->chip.npwm = NUM_PWM;
+
+       ret = pwmchip_add(&pwm->chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit tegra_pwm_remove(struct platform_device *pdev)
+{
+       struct tegra_pwm_chip *pc = platform_get_drvdata(pdev);
+       int i;
+
+       if (WARN_ON(!pc))
+               return -ENODEV;
+
+       for (i = 0; i < NUM_PWM; i++) {
+               struct pwm_device *pwm = &pc->chip.pwms[i];
+
+               if (!test_bit(PWMF_ENABLED, &pwm->flags))
+                       if (clk_prepare_enable(pc->clk) < 0)
+                               continue;
+
+               pwm_writel(pc, i, 0);
+
+               clk_disable_unprepare(pc->clk);
+       }
+
+       return pwmchip_remove(&pc->chip);
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id tegra_pwm_of_match[] = {
+       { .compatible = "nvidia,tegra20-pwm" },
+       { .compatible = "nvidia,tegra30-pwm" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, tegra_pwm_of_match);
+#endif
+
+static struct platform_driver tegra_pwm_driver = {
+       .driver = {
+               .name = "tegra-pwm",
+               .of_match_table = of_match_ptr(tegra_pwm_of_match),
+       },
+       .probe = tegra_pwm_probe,
+       .remove = __devexit_p(tegra_pwm_remove),
+};
+
+module_platform_driver(tegra_pwm_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("NVIDIA Corporation");
+MODULE_ALIAS("platform:tegra-pwm");
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
new file mode 100644 (file)
index 0000000..3c2ad28
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * ECAP PWM driver
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc. - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/pwm.h>
+
+/* ECAP registers and bits definitions */
+#define CAP1                   0x08
+#define CAP2                   0x0C
+#define CAP3                   0x10
+#define CAP4                   0x14
+#define ECCTL2                 0x2A
+#define ECCTL2_APWM_MODE       BIT(9)
+#define ECCTL2_SYNC_SEL_DISA   (BIT(7) | BIT(6))
+#define ECCTL2_TSCTR_FREERUN   BIT(4)
+
+struct ecap_pwm_chip {
+       struct pwm_chip chip;
+       unsigned int    clk_rate;
+       void __iomem    *mmio_base;
+};
+
+static inline struct ecap_pwm_chip *to_ecap_pwm_chip(struct pwm_chip *chip)
+{
+       return container_of(chip, struct ecap_pwm_chip, chip);
+}
+
+/*
+ * period_ns = 10^9 * period_cycles / PWM_CLK_RATE
+ * duty_ns   = 10^9 * duty_cycles / PWM_CLK_RATE
+ */
+static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+               int duty_ns, int period_ns)
+{
+       struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
+       unsigned long long c;
+       unsigned long period_cycles, duty_cycles;
+       unsigned int reg_val;
+
+       if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC)
+               return -ERANGE;
+
+       c = pc->clk_rate;
+       c = c * period_ns;
+       do_div(c, NSEC_PER_SEC);
+       period_cycles = (unsigned long)c;
+
+       if (period_cycles < 1) {
+               period_cycles = 1;
+               duty_cycles = 1;
+       } else {
+               c = pc->clk_rate;
+               c = c * duty_ns;
+               do_div(c, NSEC_PER_SEC);
+               duty_cycles = (unsigned long)c;
+       }
+
+       pm_runtime_get_sync(pc->chip.dev);
+
+       reg_val = readw(pc->mmio_base + ECCTL2);
+
+       /* Configure APWM mode & disable sync option */
+       reg_val |= ECCTL2_APWM_MODE | ECCTL2_SYNC_SEL_DISA;
+
+       writew(reg_val, pc->mmio_base + ECCTL2);
+
+       if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+               /* Update active registers if not running */
+               writel(duty_cycles, pc->mmio_base + CAP2);
+               writel(period_cycles, pc->mmio_base + CAP1);
+       } else {
+               /*
+                * Update shadow registers to configure period and
+                * compare values. This helps current PWM period to
+                * complete on reconfiguring
+                */
+               writel(duty_cycles, pc->mmio_base + CAP4);
+               writel(period_cycles, pc->mmio_base + CAP3);
+       }
+
+       pm_runtime_put_sync(pc->chip.dev);
+       return 0;
+}
+
+static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
+       unsigned int reg_val;
+
+       /* Leave clock enabled on enabling PWM */
+       pm_runtime_get_sync(pc->chip.dev);
+
+       /*
+        * Enable 'Free run Time stamp counter mode' to start counter
+        * and  'APWM mode' to enable APWM output
+        */
+       reg_val = readw(pc->mmio_base + ECCTL2);
+       reg_val |= ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE;
+       writew(reg_val, pc->mmio_base + ECCTL2);
+       return 0;
+}
+
+static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
+       unsigned int reg_val;
+
+       /*
+        * Disable 'Free run Time stamp counter mode' to stop counter
+        * and 'APWM mode' to put APWM output to low
+        */
+       reg_val = readw(pc->mmio_base + ECCTL2);
+       reg_val &= ~(ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE);
+       writew(reg_val, pc->mmio_base + ECCTL2);
+
+       /* Disable clock on PWM disable */
+       pm_runtime_put_sync(pc->chip.dev);
+}
+
+static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
+               dev_warn(chip->dev, "Removing PWM device without disabling\n");
+               pm_runtime_put_sync(chip->dev);
+       }
+}
+
+static const struct pwm_ops ecap_pwm_ops = {
+       .free           = ecap_pwm_free,
+       .config         = ecap_pwm_config,
+       .enable         = ecap_pwm_enable,
+       .disable        = ecap_pwm_disable,
+       .owner          = THIS_MODULE,
+};
+
+static int __devinit ecap_pwm_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct resource *r;
+       struct clk *clk;
+       struct ecap_pwm_chip *pc;
+
+       pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
+       if (!pc) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       clk = devm_clk_get(&pdev->dev, "fck");
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "failed to get clock\n");
+               return PTR_ERR(clk);
+       }
+
+       pc->clk_rate = clk_get_rate(clk);
+       if (!pc->clk_rate) {
+               dev_err(&pdev->dev, "failed to get clock rate\n");
+               return -EINVAL;
+       }
+
+       pc->chip.dev = &pdev->dev;
+       pc->chip.ops = &ecap_pwm_ops;
+       pc->chip.base = -1;
+       pc->chip.npwm = 1;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pdev->dev, "no memory resource defined\n");
+               return -ENODEV;
+       }
+
+       pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
+       if (!pc->mmio_base) {
+               dev_err(&pdev->dev, "failed to ioremap() registers\n");
+               return -EADDRNOTAVAIL;
+       }
+
+       ret = pwmchip_add(&pc->chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+               return ret;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+       platform_set_drvdata(pdev, pc);
+       return 0;
+}
+
+static int __devexit ecap_pwm_remove(struct platform_device *pdev)
+{
+       struct ecap_pwm_chip *pc = platform_get_drvdata(pdev);
+
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       return pwmchip_remove(&pc->chip);
+}
+
+static struct platform_driver ecap_pwm_driver = {
+       .driver = {
+               .name = "ecap",
+       },
+       .probe = ecap_pwm_probe,
+       .remove = __devexit_p(ecap_pwm_remove),
+};
+
+module_platform_driver(ecap_pwm_driver);
+
+MODULE_DESCRIPTION("ECAP PWM driver");
+MODULE_AUTHOR("Texas Instruments");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
new file mode 100644 (file)
index 0000000..010d232
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * EHRPWM PWM driver
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc. - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+
+/* EHRPWM registers and bits definitions */
+
+/* Time base module registers */
+#define TBCTL                  0x00
+#define TBPRD                  0x0A
+
+#define TBCTL_RUN_MASK         (BIT(15) | BIT(14))
+#define TBCTL_STOP_NEXT                0
+#define TBCTL_STOP_ON_CYCLE    BIT(14)
+#define TBCTL_FREE_RUN         (BIT(15) | BIT(14))
+#define TBCTL_PRDLD_MASK       BIT(3)
+#define TBCTL_PRDLD_SHDW       0
+#define TBCTL_PRDLD_IMDT       BIT(3)
+#define TBCTL_CLKDIV_MASK      (BIT(12) | BIT(11) | BIT(10) | BIT(9) | \
+                               BIT(8) | BIT(7))
+#define TBCTL_CTRMODE_MASK     (BIT(1) | BIT(0))
+#define TBCTL_CTRMODE_UP       0
+#define TBCTL_CTRMODE_DOWN     BIT(0)
+#define TBCTL_CTRMODE_UPDOWN   BIT(1)
+#define TBCTL_CTRMODE_FREEZE   (BIT(1) | BIT(0))
+
+#define TBCTL_HSPCLKDIV_SHIFT  7
+#define TBCTL_CLKDIV_SHIFT     10
+
+#define CLKDIV_MAX             7
+#define HSPCLKDIV_MAX          7
+#define PERIOD_MAX             0xFFFF
+
+/* compare module registers */
+#define CMPA                   0x12
+#define CMPB                   0x14
+
+/* Action qualifier module registers */
+#define AQCTLA                 0x16
+#define AQCTLB                 0x18
+#define AQSFRC                 0x1A
+#define AQCSFRC                        0x1C
+
+#define AQCTL_CBU_MASK         (BIT(9) | BIT(8))
+#define AQCTL_CBU_FRCLOW       BIT(8)
+#define AQCTL_CBU_FRCHIGH      BIT(9)
+#define AQCTL_CBU_FRCTOGGLE    (BIT(9) | BIT(8))
+#define AQCTL_CAU_MASK         (BIT(5) | BIT(4))
+#define AQCTL_CAU_FRCLOW       BIT(4)
+#define AQCTL_CAU_FRCHIGH      BIT(5)
+#define AQCTL_CAU_FRCTOGGLE    (BIT(5) | BIT(4))
+#define AQCTL_PRD_MASK         (BIT(3) | BIT(2))
+#define AQCTL_PRD_FRCLOW       BIT(2)
+#define AQCTL_PRD_FRCHIGH      BIT(3)
+#define AQCTL_PRD_FRCTOGGLE    (BIT(3) | BIT(2))
+#define AQCTL_ZRO_MASK         (BIT(1) | BIT(0))
+#define AQCTL_ZRO_FRCLOW       BIT(0)
+#define AQCTL_ZRO_FRCHIGH      BIT(1)
+#define AQCTL_ZRO_FRCTOGGLE    (BIT(1) | BIT(0))
+
+#define AQSFRC_RLDCSF_MASK     (BIT(7) | BIT(6))
+#define AQSFRC_RLDCSF_ZRO      0
+#define AQSFRC_RLDCSF_PRD      BIT(6)
+#define AQSFRC_RLDCSF_ZROPRD   BIT(7)
+#define AQSFRC_RLDCSF_IMDT     (BIT(7) | BIT(6))
+
+#define AQCSFRC_CSFB_MASK      (BIT(3) | BIT(2))
+#define AQCSFRC_CSFB_FRCDIS    0
+#define AQCSFRC_CSFB_FRCLOW    BIT(2)
+#define AQCSFRC_CSFB_FRCHIGH   BIT(3)
+#define AQCSFRC_CSFB_DISSWFRC  (BIT(3) | BIT(2))
+#define AQCSFRC_CSFA_MASK      (BIT(1) | BIT(0))
+#define AQCSFRC_CSFA_FRCDIS    0
+#define AQCSFRC_CSFA_FRCLOW    BIT(0)
+#define AQCSFRC_CSFA_FRCHIGH   BIT(1)
+#define AQCSFRC_CSFA_DISSWFRC  (BIT(1) | BIT(0))
+
+#define NUM_PWM_CHANNEL                2       /* EHRPWM channels */
+
+struct ehrpwm_pwm_chip {
+       struct pwm_chip chip;
+       unsigned int    clk_rate;
+       void __iomem    *mmio_base;
+};
+
+static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
+{
+       return container_of(chip, struct ehrpwm_pwm_chip, chip);
+}
+
+static void ehrpwm_write(void *base, int offset, unsigned int val)
+{
+       writew(val & 0xFFFF, base + offset);
+}
+
+static void ehrpwm_modify(void *base, int offset,
+               unsigned short mask, unsigned short val)
+{
+       unsigned short regval;
+
+       regval = readw(base + offset);
+       regval &= ~mask;
+       regval |= val & mask;
+       writew(regval, base + offset);
+}
+
+/**
+ * set_prescale_div -  Set up the prescaler divider function
+ * @rqst_prescaler:    prescaler value min
+ * @prescale_div:      prescaler value set
+ * @tb_clk_div:                Time Base Control prescaler bits
+ */
+static int set_prescale_div(unsigned long rqst_prescaler,
+               unsigned short *prescale_div, unsigned short *tb_clk_div)
+{
+       unsigned int clkdiv, hspclkdiv;
+
+       for (clkdiv = 0; clkdiv <= CLKDIV_MAX; clkdiv++) {
+               for (hspclkdiv = 0; hspclkdiv <= HSPCLKDIV_MAX; hspclkdiv++) {
+
+                       /*
+                        * calculations for prescaler value :
+                        * prescale_div = HSPCLKDIVIDER * CLKDIVIDER.
+                        * HSPCLKDIVIDER =  2 ** hspclkdiv
+                        * CLKDIVIDER = (1),            if clkdiv == 0 *OR*
+                        *              (2 * clkdiv),   if clkdiv != 0
+                        *
+                        * Configure prescale_div value such that period
+                        * register value is less than 65535.
+                        */
+
+                       *prescale_div = (1 << clkdiv) *
+                                       (hspclkdiv ? (hspclkdiv * 2) : 1);
+                       if (*prescale_div > rqst_prescaler) {
+                               *tb_clk_div = (clkdiv << TBCTL_CLKDIV_SHIFT) |
+                                       (hspclkdiv << TBCTL_HSPCLKDIV_SHIFT);
+                               return 0;
+                       }
+               }
+       }
+       return 1;
+}
+
+static void configure_chans(struct ehrpwm_pwm_chip *pc, int chan,
+               unsigned long duty_cycles)
+{
+       int cmp_reg, aqctl_reg;
+       unsigned short aqctl_val, aqctl_mask;
+
+       /*
+        * Channels can be configured from action qualifier module.
+        * Channel 0 configured with compare A register and for
+        * up-counter mode.
+        * Channel 1 configured with compare B register and for
+        * up-counter mode.
+        */
+       if (chan == 1) {
+               aqctl_reg = AQCTLB;
+               cmp_reg = CMPB;
+               /* Configure PWM Low from compare B value */
+               aqctl_val = AQCTL_CBU_FRCLOW;
+               aqctl_mask = AQCTL_CBU_MASK;
+       } else {
+               cmp_reg = CMPA;
+               aqctl_reg = AQCTLA;
+               /* Configure PWM Low from compare A value*/
+               aqctl_val = AQCTL_CAU_FRCLOW;
+               aqctl_mask = AQCTL_CAU_MASK;
+       }
+
+       /* Configure PWM High from period value and zero value */
+       aqctl_val |= AQCTL_PRD_FRCHIGH | AQCTL_ZRO_FRCHIGH;
+       aqctl_mask |= AQCTL_PRD_MASK | AQCTL_ZRO_MASK;
+       ehrpwm_modify(pc->mmio_base,  aqctl_reg, aqctl_mask, aqctl_val);
+
+       ehrpwm_write(pc->mmio_base,  cmp_reg, duty_cycles);
+}
+
+/*
+ * period_ns = 10^9 * (ps_divval * period_cycles) / PWM_CLK_RATE
+ * duty_ns   = 10^9 * (ps_divval * duty_cycles) / PWM_CLK_RATE
+ */
+static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+               int duty_ns, int period_ns)
+{
+       struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
+       unsigned long long c;
+       unsigned long period_cycles, duty_cycles;
+       unsigned short ps_divval, tb_divval;
+
+       if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC)
+               return -ERANGE;
+
+       c = pc->clk_rate;
+       c = c * period_ns;
+       do_div(c, NSEC_PER_SEC);
+       period_cycles = (unsigned long)c;
+
+       if (period_cycles < 1) {
+               period_cycles = 1;
+               duty_cycles = 1;
+       } else {
+               c = pc->clk_rate;
+               c = c * duty_ns;
+               do_div(c, NSEC_PER_SEC);
+               duty_cycles = (unsigned long)c;
+       }
+
+       /* Configure clock prescaler to support Low frequency PWM wave */
+       if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval,
+                               &tb_divval)) {
+               dev_err(chip->dev, "Unsupported values\n");
+               return -EINVAL;
+       }
+
+       pm_runtime_get_sync(chip->dev);
+
+       /* Update clock prescaler values */
+       ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CLKDIV_MASK, tb_divval);
+
+       /* Update period & duty cycle with presacler division */
+       period_cycles = period_cycles / ps_divval;
+       duty_cycles = duty_cycles / ps_divval;
+
+       /* Configure shadow loading on Period register */
+       ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_PRDLD_MASK, TBCTL_PRDLD_SHDW);
+
+       ehrpwm_write(pc->mmio_base, TBPRD, period_cycles);
+
+       /* Configure ehrpwm counter for up-count mode */
+       ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CTRMODE_MASK,
+                       TBCTL_CTRMODE_UP);
+
+       /* Configure the channel for duty cycle */
+       configure_chans(pc, pwm->hwpwm, duty_cycles);
+       pm_runtime_put_sync(chip->dev);
+       return 0;
+}
+
+static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
+       unsigned short aqcsfrc_val, aqcsfrc_mask;
+
+       /* Leave clock enabled on enabling PWM */
+       pm_runtime_get_sync(chip->dev);
+
+       /* Disabling Action Qualifier on PWM output */
+       if (pwm->hwpwm) {
+               aqcsfrc_val = AQCSFRC_CSFB_FRCDIS;
+               aqcsfrc_mask = AQCSFRC_CSFB_MASK;
+       } else {
+               aqcsfrc_val = AQCSFRC_CSFA_FRCDIS;
+               aqcsfrc_mask = AQCSFRC_CSFA_MASK;
+       }
+
+       /* Changes to shadow mode */
+       ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK,
+                       AQSFRC_RLDCSF_ZRO);
+
+       ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
+
+       /* Enable time counter for free_run */
+       ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN);
+       return 0;
+}
+
+static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
+       unsigned short aqcsfrc_val, aqcsfrc_mask;
+
+       /* Action Qualifier puts PWM output low forcefully */
+       if (pwm->hwpwm) {
+               aqcsfrc_val = AQCSFRC_CSFB_FRCLOW;
+               aqcsfrc_mask = AQCSFRC_CSFB_MASK;
+       } else {
+               aqcsfrc_val = AQCSFRC_CSFA_FRCLOW;
+               aqcsfrc_mask = AQCSFRC_CSFA_MASK;
+       }
+
+       /*
+        * Changes to immediate action on Action Qualifier. This puts
+        * Action Qualifier control on PWM output from next TBCLK
+        */
+       ehrpwm_modify(pc->mmio_base, AQSFRC, AQSFRC_RLDCSF_MASK,
+                       AQSFRC_RLDCSF_IMDT);
+
+       ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
+
+       /* Stop Time base counter */
+       ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT);
+
+       /* Disable clock on PWM disable */
+       pm_runtime_put_sync(chip->dev);
+}
+
+static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
+               dev_warn(chip->dev, "Removing PWM device without disabling\n");
+               pm_runtime_put_sync(chip->dev);
+       }
+}
+
+static const struct pwm_ops ehrpwm_pwm_ops = {
+       .free           = ehrpwm_pwm_free,
+       .config         = ehrpwm_pwm_config,
+       .enable         = ehrpwm_pwm_enable,
+       .disable        = ehrpwm_pwm_disable,
+       .owner          = THIS_MODULE,
+};
+
+static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct resource *r;
+       struct clk *clk;
+       struct ehrpwm_pwm_chip *pc;
+
+       pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
+       if (!pc) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       clk = devm_clk_get(&pdev->dev, "fck");
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "failed to get clock\n");
+               return PTR_ERR(clk);
+       }
+
+       pc->clk_rate = clk_get_rate(clk);
+       if (!pc->clk_rate) {
+               dev_err(&pdev->dev, "failed to get clock rate\n");
+               return -EINVAL;
+       }
+
+       pc->chip.dev = &pdev->dev;
+       pc->chip.ops = &ehrpwm_pwm_ops;
+       pc->chip.base = -1;
+       pc->chip.npwm = NUM_PWM_CHANNEL;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pdev->dev, "no memory resource defined\n");
+               return -ENODEV;
+       }
+
+       pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
+       if (!pc->mmio_base) {
+               dev_err(&pdev->dev, "failed to ioremap() registers\n");
+               return  -EADDRNOTAVAIL;
+       }
+
+       ret = pwmchip_add(&pc->chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+               return ret;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+       platform_set_drvdata(pdev, pc);
+       return 0;
+}
+
+static int __devexit ehrpwm_pwm_remove(struct platform_device *pdev)
+{
+       struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev);
+
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       return pwmchip_remove(&pc->chip);
+}
+
+static struct platform_driver ehrpwm_pwm_driver = {
+       .driver = {
+               .name = "ehrpwm",
+       },
+       .probe = ehrpwm_pwm_probe,
+       .remove = __devexit_p(ehrpwm_pwm_remove),
+};
+
+module_platform_driver(ehrpwm_pwm_driver);
+
+MODULE_DESCRIPTION("EHRPWM PWM driver");
+MODULE_AUTHOR("Texas Instruments");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c
new file mode 100644 (file)
index 0000000..5480214
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * drivers/pwm/pwm-vt8500.c
+ *
+ *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+#include <linux/delay.h>
+
+#include <asm/div64.h>
+
+#define VT8500_NR_PWMS 4
+
+struct vt8500_chip {
+       struct pwm_chip chip;
+       void __iomem *base;
+};
+
+#define to_vt8500_chip(chip)   container_of(chip, struct vt8500_chip, chip)
+
+#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask)
+{
+       int loops = msecs_to_loops(10);
+       while ((readb(reg) & bitmask) && --loops)
+               cpu_relax();
+
+       if (unlikely(!loops))
+               pr_warning("Waiting for status bits 0x%x to clear timed out\n",
+                          bitmask);
+}
+
+static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+               int duty_ns, int period_ns)
+{
+       struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
+       unsigned long long c;
+       unsigned long period_cycles, prescale, pv, dc;
+
+       c = 25000000/2; /* wild guess --- need to implement clocks */
+       c = c * period_ns;
+       do_div(c, 1000000000);
+       period_cycles = c;
+
+       if (period_cycles < 1)
+               period_cycles = 1;
+       prescale = (period_cycles - 1) / 4096;
+       pv = period_cycles / (prescale + 1) - 1;
+       if (pv > 4095)
+               pv = 4095;
+
+       if (prescale > 1023)
+               return -EINVAL;
+
+       c = (unsigned long long)pv * duty_ns;
+       do_div(c, period_ns);
+       dc = c;
+
+       pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 1));
+       writel(prescale, vt8500->base + 0x4 + (pwm->hwpwm << 4));
+
+       pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 2));
+       writel(pv, vt8500->base + 0x8 + (pwm->hwpwm << 4));
+
+       pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 3));
+       writel(dc, vt8500->base + 0xc + (pwm->hwpwm << 4));
+
+       return 0;
+}
+
+static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
+
+       pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0));
+       writel(5, vt8500->base + (pwm->hwpwm << 4));
+       return 0;
+}
+
+static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
+
+       pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0));
+       writel(0, vt8500->base + (pwm->hwpwm << 4));
+}
+
+static struct pwm_ops vt8500_pwm_ops = {
+       .enable = vt8500_pwm_enable,
+       .disable = vt8500_pwm_disable,
+       .config = vt8500_pwm_config,
+       .owner = THIS_MODULE,
+};
+
+static int __devinit pwm_probe(struct platform_device *pdev)
+{
+       struct vt8500_chip *chip;
+       struct resource *r;
+       int ret;
+
+       chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       chip->chip.dev = &pdev->dev;
+       chip->chip.ops = &vt8500_pwm_ops;
+       chip->chip.base = -1;
+       chip->chip.npwm = VT8500_NR_PWMS;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               dev_err(&pdev->dev, "no memory resource defined\n");
+               return -ENODEV;
+       }
+
+       chip->base = devm_request_and_ioremap(&pdev->dev, r);
+       if (chip->base == NULL)
+               return -EADDRNOTAVAIL;
+
+       ret = pwmchip_add(&chip->chip);
+       if (ret < 0)
+               return ret;
+
+       platform_set_drvdata(pdev, chip);
+       return ret;
+}
+
+static int __devexit pwm_remove(struct platform_device *pdev)
+{
+       struct vt8500_chip *chip;
+
+       chip = platform_get_drvdata(pdev);
+       if (chip == NULL)
+               return -ENODEV;
+
+       return pwmchip_remove(&chip->chip);
+}
+
+static struct platform_driver pwm_driver = {
+       .driver         = {
+               .name   = "vt8500-pwm",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = pwm_probe,
+       .remove         = __devexit_p(pwm_remove),
+};
+
+static int __init pwm_init(void)
+{
+       return platform_driver_register(&pwm_driver);
+}
+arch_initcall(pwm_init);
+
+static void __exit pwm_exit(void)
+{
+       platform_driver_unregister(&pwm_driver);
+}
+module_exit(pwm_exit);
+
+MODULE_LICENSE("GPL");
index f34c3be6c9fed92bdaf227016f4540b8edda0f89..4e932cc695e9311e811c9be2942798c4ecad5077 100644 (file)
@@ -272,7 +272,7 @@ config REGULATOR_S2MPS11
 
 config REGULATOR_S5M8767
        tristate "Samsung S5M8767A voltage regulator"
-       depends on MFD_S5M_CORE
+       depends on MFD_SEC_CORE
        help
         This driver supports a Samsung S5M8767A voltage output regulator
         via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
index 13d424fc1c14c675958014846b48391ff468dec7..10f2f4d4d190254cfa9602aa19223984c38fa691 100644 (file)
@@ -848,18 +848,12 @@ static __devexit int ab8500_regulator_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id ab8500_regulator_match[] = {
-        { .compatible = "stericsson,ab8500-regulator", },
-        {}
-};
-
 static struct platform_driver ab8500_regulator_driver = {
        .probe = ab8500_regulator_probe,
        .remove = __devexit_p(ab8500_regulator_remove),
        .driver         = {
                .name   = "ab8500-regulator",
                .owner  = THIS_MODULE,
-               .of_match_table = ab8500_regulator_match,
        },
 };
 
index 9dbb491b6efa827a64198baccfc42f6fe6612f79..359f8d18fc3f35f03f0314661aba33def33846f7 100644 (file)
@@ -547,16 +547,10 @@ static int __exit db8500_regulator_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id db8500_prcmu_regulator_match[] = {
-        { .compatible = "stericsson,db8500-prcmu-regulator", },
-        {}
-};
-
 static struct platform_driver db8500_regulator_driver = {
        .driver = {
                .name = "db8500-prcmu-regulators",
                .owner = THIS_MODULE,
-               .of_match_table = db8500_prcmu_regulator_match,
        },
        .probe = db8500_regulator_probe,
        .remove = __exit_p(db8500_regulator_remove),
index 102287fa7ecb48df1aae1de76c484b3fe683051d..abe64a32aedf3a4b38ee05ea7c59849b4959642c 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
-#include <linux/mfd/s5m87xx/s5m-core.h>
-#include <linux/mfd/s5m87xx/s5m-pmic.h>
+#include <linux/mfd/samsung/core.h>
+#include <linux/mfd/samsung/s5m8767.h>
 
 struct s5m8767_info {
        struct device *dev;
-       struct s5m87xx_dev *iodev;
+       struct sec_pmic_dev *iodev;
        int num_regulators;
        struct regulator_dev **rdev;
-       struct s5m_opmode_data *opmode;
+       struct sec_opmode_data *opmode;
 
        int ramp_delay;
        bool buck2_ramp;
@@ -45,43 +45,43 @@ struct s5m8767_info {
        int buck_gpioindex;
 };
 
-struct s5m_voltage_desc {
+struct sec_voltage_desc {
        int max;
        int min;
        int step;
 };
 
-static const struct s5m_voltage_desc buck_voltage_val1 = {
+static const struct sec_voltage_desc buck_voltage_val1 = {
        .max = 2225000,
        .min =  650000,
        .step =   6250,
 };
 
-static const struct s5m_voltage_desc buck_voltage_val2 = {
+static const struct sec_voltage_desc buck_voltage_val2 = {
        .max = 1600000,
        .min =  600000,
        .step =   6250,
 };
 
-static const struct s5m_voltage_desc buck_voltage_val3 = {
+static const struct sec_voltage_desc buck_voltage_val3 = {
        .max = 3000000,
        .min =  750000,
        .step =  12500,
 };
 
-static const struct s5m_voltage_desc ldo_voltage_val1 = {
+static const struct sec_voltage_desc ldo_voltage_val1 = {
        .max = 3950000,
        .min =  800000,
        .step =  50000,
 };
 
-static const struct s5m_voltage_desc ldo_voltage_val2 = {
+static const struct sec_voltage_desc ldo_voltage_val2 = {
        .max = 2375000,
        .min =  800000,
        .step =  25000,
 };
 
-static const struct s5m_voltage_desc *reg_voltage_map[] = {
+static const struct sec_voltage_desc *reg_voltage_map[] = {
        [S5M8767_LDO1] = &ldo_voltage_val2,
        [S5M8767_LDO2] = &ldo_voltage_val2,
        [S5M8767_LDO3] = &ldo_voltage_val1,
@@ -213,7 +213,7 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
        else if (ret)
                return ret;
 
-       ret = s5m_reg_read(s5m8767->iodev, reg, &val);
+       ret = sec_reg_read(s5m8767->iodev, reg, &val);
        if (ret)
                return ret;
 
@@ -230,7 +230,7 @@ static int s5m8767_reg_enable(struct regulator_dev *rdev)
        if (ret)
                return ret;
 
-       return s5m_reg_update(s5m8767->iodev, reg, enable_ctrl, mask);
+       return sec_reg_update(s5m8767->iodev, reg, enable_ctrl, mask);
 }
 
 static int s5m8767_reg_disable(struct regulator_dev *rdev)
@@ -243,7 +243,7 @@ static int s5m8767_reg_disable(struct regulator_dev *rdev)
        if (ret)
                return ret;
 
-       return s5m_reg_update(s5m8767->iodev, reg, ~mask, mask);
+       return sec_reg_update(s5m8767->iodev, reg, ~mask, mask);
 }
 
 static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
@@ -305,7 +305,7 @@ static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
 
        mask = (reg_id < S5M8767_BUCK1) ? 0x3f : 0xff;
 
-       ret = s5m_reg_read(s5m8767->iodev, reg, &val);
+       ret = sec_reg_read(s5m8767->iodev, reg, &val);
        if (ret)
                return ret;
 
@@ -315,7 +315,7 @@ static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
 }
 
 static int s5m8767_convert_voltage_to_sel(
-               const struct s5m_voltage_desc *desc,
+               const struct sec_voltage_desc *desc,
                int min_vol, int max_vol)
 {
        int selector = 0;
@@ -407,7 +407,7 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
                if (ret)
                        return ret;
 
-               return s5m_reg_update(s5m8767->iodev, reg, selector, mask);
+               return sec_reg_update(s5m8767->iodev, reg, selector, mask);
        }
 }
 
@@ -416,7 +416,7 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
                                             unsigned int new_sel)
 {
        struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-       const struct s5m_voltage_desc *desc;
+       const struct sec_voltage_desc *desc;
        int reg_id = rdev_get_id(rdev);
 
        desc = reg_voltage_map[reg_id];
@@ -501,8 +501,8 @@ static struct regulator_desc regulators[] = {
 
 static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
 {
-       struct s5m87xx_dev *iodev = dev_get_drvdata(pdev->dev.parent);
-       struct s5m_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
        struct regulator_config config = { };
        struct regulator_dev **rdev;
        struct s5m8767_info *s5m8767;
@@ -572,21 +572,21 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
                                                pdata->buck2_init +
                                                buck_voltage_val2.step);
 
-       s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init);
+       sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init);
 
        buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
                                                pdata->buck3_init,
                                                pdata->buck3_init +
                                                buck_voltage_val2.step);
 
-       s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init);
+       sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init);
 
        buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
                                                pdata->buck4_init,
                                                pdata->buck4_init +
                                                buck_voltage_val2.step);
 
-       s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init);
+       sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init);
 
        for (i = 0; i < 8; i++) {
                if (s5m8767->buck2_gpiodvs) {
@@ -671,13 +671,13 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
 
        if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
           pdata->buck4_gpiodvs) {
-               s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
+               sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
                                (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1),
                                1 << 1);
-               s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
+               sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
                                (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1),
                                1 << 1);
-               s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
+               sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
                                (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1),
                                1 << 1);
        }
@@ -685,61 +685,61 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
        /* Initialize GPIO DVS registers */
        for (i = 0; i < 8; i++) {
                if (s5m8767->buck2_gpiodvs) {
-                       s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS1 + i,
+                       sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS1 + i,
                                           s5m8767->buck2_vol[i]);
                }
 
                if (s5m8767->buck3_gpiodvs) {
-                       s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS1 + i,
+                       sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS1 + i,
                                           s5m8767->buck3_vol[i]);
                }
 
                if (s5m8767->buck4_gpiodvs) {
-                       s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS1 + i,
+                       sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS1 + i,
                                           s5m8767->buck4_vol[i]);
                }
        }
 
        if (s5m8767->buck2_ramp)
-               s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08);
+               sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08);
 
        if (s5m8767->buck3_ramp)
-               s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x04, 0x04);
+               sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x04, 0x04);
 
        if (s5m8767->buck4_ramp)
-               s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x02, 0x02);
+               sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x02, 0x02);
 
        if (s5m8767->buck2_ramp || s5m8767->buck3_ramp
                || s5m8767->buck4_ramp) {
                switch (s5m8767->ramp_delay) {
                case 5:
-                       s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+                       sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
                                        0x40, 0xf0);
                        break;
                case 10:
-                       s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+                       sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
                                        0x90, 0xf0);
                        break;
                case 25:
-                       s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+                       sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
                                        0xd0, 0xf0);
                        break;
                case 50:
-                       s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+                       sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
                                        0xe0, 0xf0);
                        break;
                case 100:
-                       s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+                       sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
                                        0xf0, 0xf0);
                        break;
                default:
-                       s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+                       sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
                                        0x90, 0xf0);
                }
        }
 
        for (i = 0; i < pdata->num_regulators; i++) {
-               const struct s5m_voltage_desc *desc;
+               const struct sec_voltage_desc *desc;
                int id = pdata->regulators[i].id;
 
                desc = reg_voltage_map[id];
index 08cbdb900a18a290a7065bc73850015f8278ca10..fabc99a75c6596d2b797e55a59fa7ecd2db49fc8 100644 (file)
@@ -135,6 +135,16 @@ config RTC_DRV_88PM860X
          This driver can also be built as a module. If so, the module
          will be called rtc-88pm860x.
 
+config RTC_DRV_88PM80X
+       tristate "Marvell 88PM80x"
+       depends on RTC_CLASS && I2C && MFD_88PM800
+       help
+         If you say yes here you get support for RTC function in Marvell
+         88PM80x chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-88pm80x.
+
 config RTC_DRV_DS1307
        tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"
        help
@@ -694,6 +704,7 @@ config RTC_DRV_AB3100
 config RTC_DRV_AB8500
        tristate "ST-Ericsson AB8500 RTC"
        depends on AB8500_CORE
+       select RTC_INTF_DEV_UIE_EMUL
        help
          Select this to enable the ST-Ericsson AB8500 power management IC RTC
          support. This chip contains a battery- and capacitor-backed RTC.
index 2973921c30d84d70eafea434dd3e678e4c54c3c1..0d5b2b66f90d4f47f97b3cf88fec79ebb2ff4028 100644 (file)
@@ -16,6 +16,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
 # Keep the list ordered.
 
 obj-$(CONFIG_RTC_DRV_88PM860X)  += rtc-88pm860x.o
+obj-$(CONFIG_RTC_DRV_88PM80X)  += rtc-88pm80x.o
 obj-$(CONFIG_RTC_DRV_AB3100)   += rtc-ab3100.o
 obj-$(CONFIG_RTC_DRV_AB8500)   += rtc-ab8500.o
 obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c
new file mode 100644 (file)
index 0000000..a2f956d
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * Real Time Clock driver for Marvell 88PM80x PMIC
+ *
+ * Copyright (c) 2012 Marvell International Ltd.
+ *  Wenzeng Chen<wzch@marvell.com>
+ *  Qiao Zhou <zhouqiao@marvell.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/88pm80x.h>
+#include <linux/rtc.h>
+
+#define PM800_RTC_COUNTER1             (0xD1)
+#define PM800_RTC_COUNTER2             (0xD2)
+#define PM800_RTC_COUNTER3             (0xD3)
+#define PM800_RTC_COUNTER4             (0xD4)
+#define PM800_RTC_EXPIRE1_1            (0xD5)
+#define PM800_RTC_EXPIRE1_2            (0xD6)
+#define PM800_RTC_EXPIRE1_3            (0xD7)
+#define PM800_RTC_EXPIRE1_4            (0xD8)
+#define PM800_RTC_TRIM1                        (0xD9)
+#define PM800_RTC_TRIM2                        (0xDA)
+#define PM800_RTC_TRIM3                        (0xDB)
+#define PM800_RTC_TRIM4                        (0xDC)
+#define PM800_RTC_EXPIRE2_1            (0xDD)
+#define PM800_RTC_EXPIRE2_2            (0xDE)
+#define PM800_RTC_EXPIRE2_3            (0xDF)
+#define PM800_RTC_EXPIRE2_4            (0xE0)
+
+#define PM800_POWER_DOWN_LOG1  (0xE5)
+#define PM800_POWER_DOWN_LOG2  (0xE6)
+
+struct pm80x_rtc_info {
+       struct pm80x_chip *chip;
+       struct regmap *map;
+       struct rtc_device *rtc_dev;
+       struct device *dev;
+       struct delayed_work calib_work;
+
+       int irq;
+       int vrtc;
+};
+
+static irqreturn_t rtc_update_handler(int irq, void *data)
+{
+       struct pm80x_rtc_info *info = (struct pm80x_rtc_info *)data;
+       int mask;
+
+       mask = PM800_ALARM | PM800_ALARM_WAKEUP;
+       regmap_update_bits(info->map, PM800_RTC_CONTROL, mask | PM800_ALARM1_EN,
+                          mask);
+       rtc_update_irq(info->rtc_dev, 1, RTC_AF);
+       return IRQ_HANDLED;
+}
+
+static int pm80x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct pm80x_rtc_info *info = dev_get_drvdata(dev);
+
+       if (enabled)
+               regmap_update_bits(info->map, PM800_RTC_CONTROL,
+                                  PM800_ALARM1_EN, PM800_ALARM1_EN);
+       else
+               regmap_update_bits(info->map, PM800_RTC_CONTROL,
+                                  PM800_ALARM1_EN, 0);
+       return 0;
+}
+
+/*
+ * Calculate the next alarm time given the requested alarm time mask
+ * and the current time.
+ */
+static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,
+                               struct rtc_time *alrm)
+{
+       unsigned long next_time;
+       unsigned long now_time;
+
+       next->tm_year = now->tm_year;
+       next->tm_mon = now->tm_mon;
+       next->tm_mday = now->tm_mday;
+       next->tm_hour = alrm->tm_hour;
+       next->tm_min = alrm->tm_min;
+       next->tm_sec = alrm->tm_sec;
+
+       rtc_tm_to_time(now, &now_time);
+       rtc_tm_to_time(next, &next_time);
+
+       if (next_time < now_time) {
+               /* Advance one day */
+               next_time += 60 * 60 * 24;
+               rtc_time_to_tm(next_time, next);
+       }
+}
+
+static int pm80x_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct pm80x_rtc_info *info = dev_get_drvdata(dev);
+       unsigned char buf[4];
+       unsigned long ticks, base, data;
+       regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
+       base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+       dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);
+
+       /* load 32-bit read-only counter */
+       regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
+       data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+       ticks = base + data;
+       dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+               base, data, ticks);
+       rtc_time_to_tm(ticks, tm);
+       return 0;
+}
+
+static int pm80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct pm80x_rtc_info *info = dev_get_drvdata(dev);
+       unsigned char buf[4];
+       unsigned long ticks, base, data;
+       if ((tm->tm_year < 70) || (tm->tm_year > 138)) {
+               dev_dbg(info->dev,
+                       "Set time %d out of range. Please set time between 1970 to 2038.\n",
+                       1900 + tm->tm_year);
+               return -EINVAL;
+       }
+       rtc_tm_to_time(tm, &ticks);
+
+       /* load 32-bit read-only counter */
+       regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
+       data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+       base = ticks - data;
+       dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+               base, data, ticks);
+       buf[0] = base & 0xFF;
+       buf[1] = (base >> 8) & 0xFF;
+       buf[2] = (base >> 16) & 0xFF;
+       buf[3] = (base >> 24) & 0xFF;
+       regmap_raw_write(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
+
+       return 0;
+}
+
+static int pm80x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct pm80x_rtc_info *info = dev_get_drvdata(dev);
+       unsigned char buf[4];
+       unsigned long ticks, base, data;
+       int ret;
+
+       regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
+       base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+       dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);
+
+       regmap_raw_read(info->map, PM800_RTC_EXPIRE1_1, buf, 4);
+       data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+       ticks = base + data;
+       dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+               base, data, ticks);
+
+       rtc_time_to_tm(ticks, &alrm->time);
+       regmap_read(info->map, PM800_RTC_CONTROL, &ret);
+       alrm->enabled = (ret & PM800_ALARM1_EN) ? 1 : 0;
+       alrm->pending = (ret & (PM800_ALARM | PM800_ALARM_WAKEUP)) ? 1 : 0;
+       return 0;
+}
+
+static int pm80x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct pm80x_rtc_info *info = dev_get_drvdata(dev);
+       struct rtc_time now_tm, alarm_tm;
+       unsigned long ticks, base, data;
+       unsigned char buf[4];
+       int mask;
+
+       regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_ALARM1_EN, 0);
+
+       regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
+       base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+       dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);
+
+       /* load 32-bit read-only counter */
+       regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
+       data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+       ticks = base + data;
+       dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+               base, data, ticks);
+
+       rtc_time_to_tm(ticks, &now_tm);
+       dev_dbg(info->dev, "%s, now time : %lu\n", __func__, ticks);
+       rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time);
+       /* get new ticks for alarm in 24 hours */
+       rtc_tm_to_time(&alarm_tm, &ticks);
+       dev_dbg(info->dev, "%s, alarm time: %lu\n", __func__, ticks);
+       data = ticks - base;
+
+       buf[0] = data & 0xff;
+       buf[1] = (data >> 8) & 0xff;
+       buf[2] = (data >> 16) & 0xff;
+       buf[3] = (data >> 24) & 0xff;
+       regmap_raw_write(info->map, PM800_RTC_EXPIRE1_1, buf, 4);
+       if (alrm->enabled) {
+               mask = PM800_ALARM | PM800_ALARM_WAKEUP | PM800_ALARM1_EN;
+               regmap_update_bits(info->map, PM800_RTC_CONTROL, mask, mask);
+       } else {
+               mask = PM800_ALARM | PM800_ALARM_WAKEUP | PM800_ALARM1_EN;
+               regmap_update_bits(info->map, PM800_RTC_CONTROL, mask,
+                                  PM800_ALARM | PM800_ALARM_WAKEUP);
+       }
+       return 0;
+}
+
+static const struct rtc_class_ops pm80x_rtc_ops = {
+       .read_time = pm80x_rtc_read_time,
+       .set_time = pm80x_rtc_set_time,
+       .read_alarm = pm80x_rtc_read_alarm,
+       .set_alarm = pm80x_rtc_set_alarm,
+       .alarm_irq_enable = pm80x_rtc_alarm_irq_enable,
+};
+
+#ifdef CONFIG_PM
+static int pm80x_rtc_suspend(struct device *dev)
+{
+       return pm80x_dev_suspend(dev);
+}
+
+static int pm80x_rtc_resume(struct device *dev)
+{
+       return pm80x_dev_resume(dev);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume);
+
+static int __devinit pm80x_rtc_probe(struct platform_device *pdev)
+{
+       struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct pm80x_platform_data *pm80x_pdata;
+       struct pm80x_rtc_pdata *pdata = NULL;
+       struct pm80x_rtc_info *info;
+       struct rtc_time tm;
+       unsigned long ticks = 0;
+       int ret;
+
+       pdata = pdev->dev.platform_data;
+       if (pdata == NULL)
+               dev_warn(&pdev->dev, "No platform data!\n");
+
+       info =
+           devm_kzalloc(&pdev->dev, sizeof(struct pm80x_rtc_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       info->irq = platform_get_irq(pdev, 0);
+       if (info->irq < 0) {
+               dev_err(&pdev->dev, "No IRQ resource!\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       info->chip = chip;
+       info->map = chip->regmap;
+       if (!info->map) {
+               dev_err(&pdev->dev, "no regmap!\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       info->dev = &pdev->dev;
+       dev_set_drvdata(&pdev->dev, info);
+
+       ret = pm80x_request_irq(chip, info->irq, rtc_update_handler,
+                               IRQF_ONESHOT, "rtc", info);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+                       info->irq, ret);
+               goto out;
+       }
+
+       ret = pm80x_rtc_read_time(&pdev->dev, &tm);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to read initial time.\n");
+               goto out_rtc;
+       }
+       if ((tm.tm_year < 70) || (tm.tm_year > 138)) {
+               tm.tm_year = 70;
+               tm.tm_mon = 0;
+               tm.tm_mday = 1;
+               tm.tm_hour = 0;
+               tm.tm_min = 0;
+               tm.tm_sec = 0;
+               ret = pm80x_rtc_set_time(&pdev->dev, &tm);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "Failed to set initial time.\n");
+                       goto out_rtc;
+               }
+       }
+       rtc_tm_to_time(&tm, &ticks);
+
+       info->rtc_dev = rtc_device_register("88pm80x-rtc", &pdev->dev,
+                                           &pm80x_rtc_ops, THIS_MODULE);
+       ret = PTR_ERR(info->rtc_dev);
+       if (IS_ERR(info->rtc_dev)) {
+               dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+               goto out_rtc;
+       }
+       /*
+        * enable internal XO instead of internal 3.25MHz clock since it can
+        * free running in PMIC power-down state.
+        */
+       regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_RTC1_USE_XO,
+                          PM800_RTC1_USE_XO);
+
+       if (pdev->dev.parent->platform_data) {
+               pm80x_pdata = pdev->dev.parent->platform_data;
+               pdata = pm80x_pdata->rtc;
+               if (pdata)
+                       info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup;
+       }
+
+       device_init_wakeup(&pdev->dev, 1);
+
+       return 0;
+out_rtc:
+       pm80x_free_irq(chip, info->irq, info);
+out:
+       devm_kfree(&pdev->dev, info);
+       return ret;
+}
+
+static int __devexit pm80x_rtc_remove(struct platform_device *pdev)
+{
+       struct pm80x_rtc_info *info = platform_get_drvdata(pdev);
+       platform_set_drvdata(pdev, NULL);
+       rtc_device_unregister(info->rtc_dev);
+       pm80x_free_irq(info->chip, info->irq, info);
+       devm_kfree(&pdev->dev, info);
+       return 0;
+}
+
+static struct platform_driver pm80x_rtc_driver = {
+       .driver = {
+                  .name = "88pm80x-rtc",
+                  .owner = THIS_MODULE,
+                  .pm = &pm80x_rtc_pm_ops,
+                  },
+       .probe = pm80x_rtc_probe,
+       .remove = __devexit_p(pm80x_rtc_remove),
+};
+
+module_platform_driver(pm80x_rtc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Marvell 88PM80x RTC driver");
+MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>");
+MODULE_ALIAS("platform:88pm80x-rtc");
index 370889d0489bf9e4f196abcbbcd6f11b25e6f5a8..bf3c2f669c3c50584a1c63760ede523b9aa10cfb 100644 (file)
@@ -89,22 +89,17 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
        if (retval < 0)
                return retval;
 
-       /* Early AB8500 chips will not clear the rtc read request bit */
-       if (abx500_get_chip_id(dev) == 0) {
-               usleep_range(1000, 1000);
-       } else {
-               /* Wait for some cycles after enabling the rtc read in ab8500 */
-               while (time_before(jiffies, timeout)) {
-                       retval = abx500_get_register_interruptible(dev,
-                               AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value);
-                       if (retval < 0)
-                               return retval;
-
-                       if (!(value & RTC_READ_REQUEST))
-                               break;
-
-                       usleep_range(1000, 5000);
-               }
+       /* Wait for some cycles after enabling the rtc read in ab8500 */
+       while (time_before(jiffies, timeout)) {
+               retval = abx500_get_register_interruptible(dev,
+                       AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value);
+               if (retval < 0)
+                       return retval;
+
+               if (!(value & RTC_READ_REQUEST))
+                       break;
+
+               usleep_range(1000, 5000);
        }
 
        /* Read the Watchtime registers */
@@ -225,7 +220,8 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
        int retval, i;
        unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
-       unsigned long mins, secs = 0;
+       unsigned long mins, secs = 0, cursec = 0;
+       struct rtc_time curtm;
 
        if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) {
                dev_dbg(dev, "year should be equal to or greater than %d\n",
@@ -236,6 +232,18 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        /* Get the number of seconds since 1970 */
        rtc_tm_to_time(&alarm->time, &secs);
 
+       /*
+        * Check whether alarm is set less than 1min.
+        * Since our RTC doesn't support alarm resolution less than 1min,
+        * return -EINVAL, so UIE EMUL can take it up, incase of UIE_ON
+        */
+       ab8500_rtc_read_time(dev, &curtm); /* Read current time */
+       rtc_tm_to_time(&curtm, &cursec);
+       if ((secs - cursec) < 59) {
+               dev_dbg(dev, "Alarm less than 1 minute not supported\r\n");
+               return -EINVAL;
+       }
+
        /*
         * Convert it to the number of seconds since 01-01-2000 00:00:00, since
         * we only have a small counter in the RTC.
index a5b8a0c4ea842078a31bcfcf5be54c60240ec50e..76b2156d3c62252c80aec1eacce8fe0684950d75 100644 (file)
@@ -155,13 +155,10 @@ static int __exit coh901331_remove(struct platform_device *pdev)
        struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
 
        if (rtap) {
-               free_irq(rtap->irq, rtap);
                rtc_device_unregister(rtap->rtc);
+               clk_unprepare(rtap->clk);
                clk_put(rtap->clk);
-               iounmap(rtap->virtbase);
-               release_mem_region(rtap->phybase, rtap->physize);
                platform_set_drvdata(pdev, NULL);
-               kfree(rtap);
        }
 
        return 0;
@@ -174,49 +171,43 @@ static int __init coh901331_probe(struct platform_device *pdev)
        struct coh901331_port *rtap;
        struct resource *res;
 
-       rtap = kzalloc(sizeof(struct coh901331_port), GFP_KERNEL);
+       rtap = devm_kzalloc(&pdev->dev,
+                           sizeof(struct coh901331_port), GFP_KERNEL);
        if (!rtap)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENOENT;
-               goto out_no_resource;
-       }
+       if (!res)
+               return -ENOENT;
+
        rtap->phybase = res->start;
        rtap->physize = resource_size(res);
 
-       if (request_mem_region(rtap->phybase, rtap->physize,
-                              "rtc-coh901331") == NULL) {
-               ret = -EBUSY;
-               goto out_no_memregion;
-       }
+       if (devm_request_mem_region(&pdev->dev, rtap->phybase, rtap->physize,
+                                   "rtc-coh901331") == NULL)
+               return -EBUSY;
 
-       rtap->virtbase = ioremap(rtap->phybase, rtap->physize);
-       if (!rtap->virtbase) {
-               ret = -ENOMEM;
-               goto out_no_remap;
-       }
+       rtap->virtbase = devm_ioremap(&pdev->dev, rtap->phybase, rtap->physize);
+       if (!rtap->virtbase)
+               return -ENOMEM;
 
        rtap->irq = platform_get_irq(pdev, 0);
-       if (request_irq(rtap->irq, coh901331_interrupt, 0,
-                       "RTC COH 901 331 Alarm", rtap)) {
-               ret = -EIO;
-               goto out_no_irq;
-       }
+       if (devm_request_irq(&pdev->dev, rtap->irq, coh901331_interrupt, 0,
+                            "RTC COH 901 331 Alarm", rtap))
+               return -EIO;
 
        rtap->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(rtap->clk)) {
                ret = PTR_ERR(rtap->clk);
                dev_err(&pdev->dev, "could not get clock\n");
-               goto out_no_clk;
+               return ret;
        }
 
        /* We enable/disable the clock only to assure it works */
-       ret = clk_enable(rtap->clk);
+       ret = clk_prepare_enable(rtap->clk);
        if (ret) {
                dev_err(&pdev->dev, "could not enable clock\n");
-               goto out_no_clk_enable;
+               goto out_no_clk_prepenable;
        }
        clk_disable(rtap->clk);
 
@@ -232,18 +223,9 @@ static int __init coh901331_probe(struct platform_device *pdev)
 
  out_no_rtc:
        platform_set_drvdata(pdev, NULL);
- out_no_clk_enable:
+       clk_unprepare(rtap->clk);
+ out_no_clk_prepenable:
        clk_put(rtap->clk);
- out_no_clk:
-       free_irq(rtap->irq, rtap);
- out_no_irq:
-       iounmap(rtap->virtbase);
- out_no_remap:
-       platform_set_drvdata(pdev, NULL);
- out_no_memregion:
-       release_mem_region(rtap->phybase, SZ_4K);
- out_no_resource:
-       kfree(rtap);
        return ret;
 }
 
@@ -265,6 +247,7 @@ static int coh901331_suspend(struct platform_device *pdev, pm_message_t state)
                writel(0, rtap->virtbase + COH901331_IRQ_MASK);
                clk_disable(rtap->clk);
        }
+       clk_unprepare(rtap->clk);
        return 0;
 }
 
@@ -272,6 +255,7 @@ static int coh901331_resume(struct platform_device *pdev)
 {
        struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
 
+       clk_prepare(rtap->clk);
        if (device_may_wakeup(&pdev->dev)) {
                disable_irq_wake(rtap->irq);
        } else {
@@ -293,6 +277,7 @@ static void coh901331_shutdown(struct platform_device *pdev)
        clk_enable(rtap->clk);
        writel(0, rtap->virtbase + COH901331_IRQ_MASK);
        clk_disable(rtap->clk);
+       clk_unprepare(rtap->clk);
 }
 
 static struct platform_driver coh901331_driver = {
index da6ab5291a414c70b8ed29b57243f8a9192d14c3..78070255bd3f834d7aa8efa937e5ca552c07f4d1 100644 (file)
@@ -245,7 +245,7 @@ static int __devinit da9052_rtc_probe(struct platform_device *pdev)
                                   "ALM", rtc);
        if (ret != 0) {
                rtc_err(rtc->da9052, "irq registration failed: %d\n", ret);
-               goto err_mem;
+               return ret;
        }
 
        rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
@@ -259,8 +259,6 @@ static int __devinit da9052_rtc_probe(struct platform_device *pdev)
 
 err_free_irq:
        free_irq(rtc->irq, rtc);
-err_mem:
-       devm_kfree(&pdev->dev, rtc);
        return ret;
 }
 
@@ -271,7 +269,6 @@ static int __devexit da9052_rtc_remove(struct platform_device *pdev)
        rtc_device_unregister(rtc->rtc);
        free_irq(rtc->irq, rtc);
        platform_set_drvdata(pdev, NULL);
-       devm_kfree(&pdev->dev, rtc);
 
        return 0;
 }
index 1459055a83aaad94a522f093b045bad2a9812b6b..34e4349611dbdd6302a33d7b2917f1144a7ef306 100644 (file)
@@ -69,6 +69,7 @@ struct max8925_rtc_info {
        struct max8925_chip     *chip;
        struct i2c_client       *rtc;
        struct device           *dev;
+       int                     irq;
 };
 
 static irqreturn_t rtc_update_handler(int irq, void *data)
@@ -250,7 +251,7 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)
 {
        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
        struct max8925_rtc_info *info;
-       int irq, ret;
+       int ret;
 
        info = kzalloc(sizeof(struct max8925_rtc_info), GFP_KERNEL);
        if (!info)
@@ -258,13 +259,13 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)
        info->chip = chip;
        info->rtc = chip->rtc;
        info->dev = &pdev->dev;
-       irq = chip->irq_base + MAX8925_IRQ_RTC_ALARM0;
+       info->irq = platform_get_irq(pdev, 0);
 
-       ret = request_threaded_irq(irq, NULL, rtc_update_handler,
+       ret = request_threaded_irq(info->irq, NULL, rtc_update_handler,
                                   IRQF_ONESHOT, "rtc-alarm0", info);
        if (ret < 0) {
                dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
-                       irq, ret);
+                       info->irq, ret);
                goto out_irq;
        }
 
@@ -285,7 +286,7 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)
        return 0;
 out_rtc:
        platform_set_drvdata(pdev, NULL);
-       free_irq(chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info);
+       free_irq(info->irq, info);
 out_irq:
        kfree(info);
        return ret;
@@ -296,7 +297,7 @@ static int __devexit max8925_rtc_remove(struct platform_device *pdev)
        struct max8925_rtc_info *info = platform_get_drvdata(pdev);
 
        if (info) {
-               free_irq(info->chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info);
+               free_irq(info->irq, info);
                rtc_device_unregister(info->rtc_dev);
                kfree(info);
        }
index 546f6850bffbd9d0a9f884528b36d81296a08110..2643d8874925c6d10e82c4939724e1d94e63e0d9 100644 (file)
@@ -404,9 +404,12 @@ static const struct platform_device_id mc13xxx_rtc_idtable[] = {
                .name = "mc13783-rtc",
        }, {
                .name = "mc13892-rtc",
+       }, {
+               .name = "mc34708-rtc",
        },
-       { }
+       { /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable);
 
 static struct platform_driver mc13xxx_rtc_driver = {
        .id_table = mc13xxx_rtc_idtable,
@@ -432,4 +435,3 @@ module_exit(mc13xxx_rtc_exit);
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_DESCRIPTION("RTC driver for Freescale MC13XXX PMIC");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRIVER_NAME);
index 97a3284bb7c60920be7204156fab79b2dabafec6..c2fe426a6ef2d384e50835c1f6f05bc7e3418b9e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/rtc.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/of.h>
 
 #define DRV_VERSION "0.4.3"
 
@@ -285,9 +286,19 @@ static const struct i2c_device_id pcf8563_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pcf8563_id);
 
+#ifdef CONFIG_OF
+static const struct of_device_id pcf8563_of_match[] __devinitconst = {
+       { .compatible = "nxp,pcf8563" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, pcf8563_of_match);
+#endif
+
 static struct i2c_driver pcf8563_driver = {
        .driver         = {
                .name   = "rtc-pcf8563",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(pcf8563_of_match),
        },
        .probe          = pcf8563_probe,
        .remove         = pcf8563_remove,
index cc0533994f6e0650bbd7c2bc2a4976cfb947593e..08378e3cc21cf8209796d50876ee64ae5c0a4aaa 100644 (file)
 
 #define RTC_TIMER_FREQ 32768
 
+/**
+ * struct pl031_vendor_data - per-vendor variations
+ * @ops: the vendor-specific operations used on this silicon version
+ * @clockwatch: if this is an ST Microelectronics silicon version with a
+ *     clockwatch function
+ * @st_weekday: if this is an ST Microelectronics silicon version that need
+ *     the weekday fix
+ * @irqflags: special IRQ flags per variant
+ */
+struct pl031_vendor_data {
+       struct rtc_class_ops ops;
+       bool clockwatch;
+       bool st_weekday;
+       unsigned long irqflags;
+};
+
 struct pl031_local {
+       struct pl031_vendor_data *vendor;
        struct rtc_device *rtc;
        void __iomem *base;
-       u8 hw_designer;
-       u8 hw_revision:4;
 };
 
 static int pl031_alarm_irq_enable(struct device *dev,
@@ -303,7 +318,8 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
 {
        int ret;
        struct pl031_local *ldata;
-       struct rtc_class_ops *ops = id->data;
+       struct pl031_vendor_data *vendor = id->data;
+       struct rtc_class_ops *ops = &vendor->ops;
        unsigned long time;
 
        ret = amba_request_regions(adev, NULL);
@@ -315,6 +331,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
                ret = -ENOMEM;
                goto out;
        }
+       ldata->vendor = vendor;
 
        ldata->base = ioremap(adev->res.start, resource_size(&adev->res));
 
@@ -325,14 +342,11 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
 
        amba_set_drvdata(adev, ldata);
 
-       ldata->hw_designer = amba_manf(adev);
-       ldata->hw_revision = amba_rev(adev);
-
-       dev_dbg(&adev->dev, "designer ID = 0x%02x\n", ldata->hw_designer);
-       dev_dbg(&adev->dev, "revision = 0x%01x\n", ldata->hw_revision);
+       dev_dbg(&adev->dev, "designer ID = 0x%02x\n", amba_manf(adev));
+       dev_dbg(&adev->dev, "revision = 0x%01x\n", amba_rev(adev));
 
        /* Enable the clockwatch on ST Variants */
-       if (ldata->hw_designer == AMBA_VENDOR_ST)
+       if (vendor->clockwatch)
                writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN,
                       ldata->base + RTC_CR);
 
@@ -340,7 +354,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
         * On ST PL031 variants, the RTC reset value does not provide correct
         * weekday for 2000-01-01. Correct the erroneous sunday to saturday.
         */
-       if (ldata->hw_designer == AMBA_VENDOR_ST) {
+       if (vendor->st_weekday) {
                if (readl(ldata->base + RTC_YDR) == 0x2000) {
                        time = readl(ldata->base + RTC_DR);
                        if ((time &
@@ -361,7 +375,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
        }
 
        if (request_irq(adev->irq[0], pl031_interrupt,
-                       0, "rtc-pl031", ldata)) {
+                       vendor->irqflags, "rtc-pl031", ldata)) {
                ret = -EIO;
                goto out_no_irq;
        }
@@ -383,48 +397,65 @@ err_req:
 }
 
 /* Operations for the original ARM version */
-static struct rtc_class_ops arm_pl031_ops = {
-       .read_time = pl031_read_time,
-       .set_time = pl031_set_time,
-       .read_alarm = pl031_read_alarm,
-       .set_alarm = pl031_set_alarm,
-       .alarm_irq_enable = pl031_alarm_irq_enable,
+static struct pl031_vendor_data arm_pl031 = {
+       .ops = {
+               .read_time = pl031_read_time,
+               .set_time = pl031_set_time,
+               .read_alarm = pl031_read_alarm,
+               .set_alarm = pl031_set_alarm,
+               .alarm_irq_enable = pl031_alarm_irq_enable,
+       },
+       .irqflags = IRQF_NO_SUSPEND,
 };
 
 /* The First ST derivative */
-static struct rtc_class_ops stv1_pl031_ops = {
-       .read_time = pl031_read_time,
-       .set_time = pl031_set_time,
-       .read_alarm = pl031_read_alarm,
-       .set_alarm = pl031_set_alarm,
-       .alarm_irq_enable = pl031_alarm_irq_enable,
+static struct pl031_vendor_data stv1_pl031 = {
+       .ops = {
+               .read_time = pl031_read_time,
+               .set_time = pl031_set_time,
+               .read_alarm = pl031_read_alarm,
+               .set_alarm = pl031_set_alarm,
+               .alarm_irq_enable = pl031_alarm_irq_enable,
+       },
+       .clockwatch = true,
+       .st_weekday = true,
+       .irqflags = IRQF_NO_SUSPEND,
 };
 
 /* And the second ST derivative */
-static struct rtc_class_ops stv2_pl031_ops = {
-       .read_time = pl031_stv2_read_time,
-       .set_time = pl031_stv2_set_time,
-       .read_alarm = pl031_stv2_read_alarm,
-       .set_alarm = pl031_stv2_set_alarm,
-       .alarm_irq_enable = pl031_alarm_irq_enable,
+static struct pl031_vendor_data stv2_pl031 = {
+       .ops = {
+               .read_time = pl031_stv2_read_time,
+               .set_time = pl031_stv2_set_time,
+               .read_alarm = pl031_stv2_read_alarm,
+               .set_alarm = pl031_stv2_set_alarm,
+               .alarm_irq_enable = pl031_alarm_irq_enable,
+       },
+       .clockwatch = true,
+       .st_weekday = true,
+       /*
+        * This variant shares the IRQ with another block and must not
+        * suspend that IRQ line.
+        */
+       .irqflags = IRQF_SHARED | IRQF_NO_SUSPEND,
 };
 
 static struct amba_id pl031_ids[] = {
        {
                .id = 0x00041031,
                .mask = 0x000fffff,
-               .data = &arm_pl031_ops,
+               .data = &arm_pl031,
        },
        /* ST Micro variants */
        {
                .id = 0x00180031,
                .mask = 0x00ffffff,
-               .data = &stv1_pl031_ops,
+               .data = &stv1_pl031,
        },
        {
                .id = 0x00280031,
                .mask = 0x00ffffff,
-               .data = &stv2_pl031_ops,
+               .data = &stv2_pl031,
        },
        {0, 0},
 };
index 33b6ba0afa0de1b5034970ef7b78d7d3b468ed4f..2c183ebff715f7acc277a82558544af53083ef4b 100644 (file)
@@ -138,8 +138,7 @@ static int __devinit r9701_probe(struct spi_device *spi)
         * contain invalid values. If so, try to write a default date:
         * 2000/1/1 00:00:00
         */
-       r9701_get_datetime(&spi->dev, &dt);
-       if (rtc_valid_tm(&dt)) {
+       if (r9701_get_datetime(&spi->dev, &dt)) {
                dev_info(&spi->dev, "trying to repair invalid date/time\n");
                dt.tm_sec  = 0;
                dt.tm_min  = 0;
@@ -148,7 +147,8 @@ static int __devinit r9701_probe(struct spi_device *spi)
                dt.tm_mon  = 0;
                dt.tm_year = 100;
 
-               if (r9701_set_datetime(&spi->dev, &dt)) {
+               if (r9701_set_datetime(&spi->dev, &dt) ||
+                               r9701_get_datetime(&spi->dev, &dt)) {
                        dev_err(&spi->dev, "cannot repair RTC register\n");
                        return -ENODEV;
                }
index 7e6af0b22f17d0e3d54bad2e8981689e82be8e81..bfbd92c8d1c9d9cba042b494cfde450066320dea 100644 (file)
 #include <linux/log2.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <plat/regs-rtc.h>
 
index 4cde4fb0cd6cf491fff0c954f75d900b2ebbd7bd..5f84b5563c2d1baff1cd7a61ea2a9b3400388484 100644 (file)
@@ -144,6 +144,15 @@ config SPI_EP93XX
          This enables using the Cirrus EP93xx SPI controller in master
          mode.
 
+config SPI_FALCON
+       tristate "Falcon SPI controller support"
+       depends on SOC_FALCON
+       help
+         The external bus unit (EBU) found on the FALC-ON SoC has SPI
+         emulation that is designed for serial flash access. This driver
+         has only been tested with m25p80 type chips. The hardware has no
+         support for other types of SPI peripherals.
+
 config SPI_GPIO
        tristate "GPIO-based bitbanging SPI Master"
        depends on GENERIC_GPIO
index 273f50d1127a57041319953d13028a8303302ec8..3920dcf4c7400e2c64bfb82803316f5f27535a63 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_SPI_DW_MMIO)             += spi-dw-mmio.o
 obj-$(CONFIG_SPI_DW_PCI)               += spi-dw-midpci.o
 spi-dw-midpci-objs                     := spi-dw-pci.o spi-dw-mid.o
 obj-$(CONFIG_SPI_EP93XX)               += spi-ep93xx.o
+obj-$(CONFIG_SPI_FALCON)               += spi-falcon.o
 obj-$(CONFIG_SPI_FSL_LIB)              += spi-fsl-lib.o
 obj-$(CONFIG_SPI_FSL_ESPI)             += spi-fsl-espi.o
 obj-$(CONFIG_SPI_FSL_SPI)              += spi-fsl-spi.o
diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c
new file mode 100644 (file)
index 0000000..8f6aa73
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ *  Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com>
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#include <lantiq_soc.h>
+
+#define DRV_NAME               "sflash-falcon"
+
+#define FALCON_SPI_XFER_BEGIN  (1 << 0)
+#define FALCON_SPI_XFER_END    (1 << 1)
+
+/* Bus Read Configuration Register0 */
+#define BUSRCON0               0x00000010
+/* Bus Write Configuration Register0 */
+#define BUSWCON0               0x00000018
+/* Serial Flash Configuration Register */
+#define SFCON                  0x00000080
+/* Serial Flash Time Register */
+#define SFTIME                 0x00000084
+/* Serial Flash Status Register */
+#define SFSTAT                 0x00000088
+/* Serial Flash Command Register */
+#define SFCMD                  0x0000008C
+/* Serial Flash Address Register */
+#define SFADDR                 0x00000090
+/* Serial Flash Data Register */
+#define SFDATA                 0x00000094
+/* Serial Flash I/O Control Register */
+#define SFIO                   0x00000098
+/* EBU Clock Control Register */
+#define EBUCC                  0x000000C4
+
+/* Dummy Phase Length */
+#define SFCMD_DUMLEN_OFFSET    16
+#define SFCMD_DUMLEN_MASK      0x000F0000
+/* Chip Select */
+#define SFCMD_CS_OFFSET                24
+#define SFCMD_CS_MASK          0x07000000
+/* field offset */
+#define SFCMD_ALEN_OFFSET      20
+#define SFCMD_ALEN_MASK                0x00700000
+/* SCK Rise-edge Position */
+#define SFTIME_SCKR_POS_OFFSET 8
+#define SFTIME_SCKR_POS_MASK   0x00000F00
+/* SCK Period */
+#define SFTIME_SCK_PER_OFFSET  0
+#define SFTIME_SCK_PER_MASK    0x0000000F
+/* SCK Fall-edge Position */
+#define SFTIME_SCKF_POS_OFFSET 12
+#define SFTIME_SCKF_POS_MASK   0x0000F000
+/* Device Size */
+#define SFCON_DEV_SIZE_A23_0   0x03000000
+#define SFCON_DEV_SIZE_MASK    0x0F000000
+/* Read Data Position */
+#define SFTIME_RD_POS_MASK     0x000F0000
+/* Data Output */
+#define SFIO_UNUSED_WD_MASK    0x0000000F
+/* Command Opcode mask */
+#define SFCMD_OPC_MASK         0x000000FF
+/* dlen bytes of data to write */
+#define SFCMD_DIR_WRITE                0x00000100
+/* Data Length offset */
+#define SFCMD_DLEN_OFFSET      9
+/* Command Error */
+#define SFSTAT_CMD_ERR         0x20000000
+/* Access Command Pending */
+#define SFSTAT_CMD_PEND                0x00400000
+/* Frequency set to 100MHz. */
+#define EBUCC_EBUDIV_SELF100   0x00000001
+/* Serial Flash */
+#define BUSRCON0_AGEN_SERIAL_FLASH     0xF0000000
+/* 8-bit multiplexed */
+#define BUSRCON0_PORTW_8_BIT_MUX       0x00000000
+/* Serial Flash */
+#define BUSWCON0_AGEN_SERIAL_FLASH     0xF0000000
+/* Chip Select after opcode */
+#define SFCMD_KEEP_CS_KEEP_SELECTED    0x00008000
+
+#define CLOCK_100M     100000000
+#define CLOCK_50M      50000000
+
+struct falcon_sflash {
+       u32 sfcmd; /* for caching of opcode, direction, ... */
+       struct spi_master *master;
+};
+
+int falcon_sflash_xfer(struct spi_device *spi, struct spi_transfer *t,
+               unsigned long flags)
+{
+       struct device *dev = &spi->dev;
+       struct falcon_sflash *priv = spi_master_get_devdata(spi->master);
+       const u8 *txp = t->tx_buf;
+       u8 *rxp = t->rx_buf;
+       unsigned int bytelen = ((8 * t->len + 7) / 8);
+       unsigned int len, alen, dumlen;
+       u32 val;
+       enum {
+               state_init,
+               state_command_prepare,
+               state_write,
+               state_read,
+               state_disable_cs,
+               state_end
+       } state = state_init;
+
+       do {
+               switch (state) {
+               case state_init: /* detect phase of upper layer sequence */
+               {
+                       /* initial write ? */
+                       if (flags & FALCON_SPI_XFER_BEGIN) {
+                               if (!txp) {
+                                       dev_err(dev,
+                                               "BEGIN without tx data!\n");
+                                       return -ENODATA;
+                               }
+                               /*
+                                * Prepare the parts of the sfcmd register,
+                                * which should not change during a sequence!
+                                * Only exception are the length fields,
+                                * especially alen and dumlen.
+                                */
+
+                               priv->sfcmd = ((spi->chip_select
+                                               << SFCMD_CS_OFFSET)
+                                              & SFCMD_CS_MASK);
+                               priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED;
+                               priv->sfcmd |= *txp;
+                               txp++;
+                               bytelen--;
+                               if (bytelen) {
+                                       /*
+                                        * more data:
+                                        * maybe address and/or dummy
+                                        */
+                                       state = state_command_prepare;
+                                       break;
+                               } else {
+                                       dev_dbg(dev, "write cmd %02X\n",
+                                               priv->sfcmd & SFCMD_OPC_MASK);
+                               }
+                       }
+                       /* continued write ? */
+                       if (txp && bytelen) {
+                               state = state_write;
+                               break;
+                       }
+                       /* read data? */
+                       if (rxp && bytelen) {
+                               state = state_read;
+                               break;
+                       }
+                       /* end of sequence? */
+                       if (flags & FALCON_SPI_XFER_END)
+                               state = state_disable_cs;
+                       else
+                               state = state_end;
+                       break;
+               }
+               /* collect tx data for address and dummy phase */
+               case state_command_prepare:
+               {
+                       /* txp is valid, already checked */
+                       val = 0;
+                       alen = 0;
+                       dumlen = 0;
+                       while (bytelen > 0) {
+                               if (alen < 3) {
+                                       val = (val << 8) | (*txp++);
+                                       alen++;
+                               } else if ((dumlen < 15) && (*txp == 0)) {
+                                       /*
+                                        * assume dummy bytes are set to 0
+                                        * from upper layer
+                                        */
+                                       dumlen++;
+                                       txp++;
+                               } else {
+                                       break;
+                               }
+                               bytelen--;
+                       }
+                       priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK);
+                       priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) |
+                                        (dumlen << SFCMD_DUMLEN_OFFSET);
+                       if (alen > 0)
+                               ltq_ebu_w32(val, SFADDR);
+
+                       dev_dbg(dev, "wr %02X, alen=%d (addr=%06X) dlen=%d\n",
+                               priv->sfcmd & SFCMD_OPC_MASK,
+                               alen, val, dumlen);
+
+                       if (bytelen > 0) {
+                               /* continue with write */
+                               state = state_write;
+                       } else if (flags & FALCON_SPI_XFER_END) {
+                               /* end of sequence? */
+                               state = state_disable_cs;
+                       } else {
+                               /*
+                                * go to end and expect another
+                                * call (read or write)
+                                */
+                               state = state_end;
+                       }
+                       break;
+               }
+               case state_write:
+               {
+                       /* txp still valid */
+                       priv->sfcmd |= SFCMD_DIR_WRITE;
+                       len = 0;
+                       val = 0;
+                       do {
+                               if (bytelen--)
+                                       val |= (*txp++) << (8 * len++);
+                               if ((flags & FALCON_SPI_XFER_END)
+                                   && (bytelen == 0)) {
+                                       priv->sfcmd &=
+                                               ~SFCMD_KEEP_CS_KEEP_SELECTED;
+                               }
+                               if ((len == 4) || (bytelen == 0)) {
+                                       ltq_ebu_w32(val, SFDATA);
+                                       ltq_ebu_w32(priv->sfcmd
+                                               | (len<<SFCMD_DLEN_OFFSET),
+                                               SFCMD);
+                                       len = 0;
+                                       val = 0;
+                                       priv->sfcmd &= ~(SFCMD_ALEN_MASK
+                                                        | SFCMD_DUMLEN_MASK);
+                               }
+                       } while (bytelen);
+                       state = state_end;
+                       break;
+               }
+               case state_read:
+               {
+                       /* read data */
+                       priv->sfcmd &= ~SFCMD_DIR_WRITE;
+                       do {
+                               if ((flags & FALCON_SPI_XFER_END)
+                                   && (bytelen <= 4)) {
+                                       priv->sfcmd &=
+                                               ~SFCMD_KEEP_CS_KEEP_SELECTED;
+                               }
+                               len = (bytelen > 4) ? 4 : bytelen;
+                               bytelen -= len;
+                               ltq_ebu_w32(priv->sfcmd
+                                       | (len << SFCMD_DLEN_OFFSET), SFCMD);
+                               priv->sfcmd &= ~(SFCMD_ALEN_MASK
+                                                | SFCMD_DUMLEN_MASK);
+                               do {
+                                       val = ltq_ebu_r32(SFSTAT);
+                                       if (val & SFSTAT_CMD_ERR) {
+                                               /* reset error status */
+                                               dev_err(dev, "SFSTAT: CMD_ERR");
+                                               dev_err(dev, " (%x)\n", val);
+                                               ltq_ebu_w32(SFSTAT_CMD_ERR,
+                                                       SFSTAT);
+                                               return -EBADE;
+                                       }
+                               } while (val & SFSTAT_CMD_PEND);
+                               val = ltq_ebu_r32(SFDATA);
+                               do {
+                                       *rxp = (val & 0xFF);
+                                       rxp++;
+                                       val >>= 8;
+                                       len--;
+                               } while (len);
+                       } while (bytelen);
+                       state = state_end;
+                       break;
+               }
+               case state_disable_cs:
+               {
+                       priv->sfcmd &= ~SFCMD_KEEP_CS_KEEP_SELECTED;
+                       ltq_ebu_w32(priv->sfcmd | (0 << SFCMD_DLEN_OFFSET),
+                               SFCMD);
+                       val = ltq_ebu_r32(SFSTAT);
+                       if (val & SFSTAT_CMD_ERR) {
+                               /* reset error status */
+                               dev_err(dev, "SFSTAT: CMD_ERR (%x)\n", val);
+                               ltq_ebu_w32(SFSTAT_CMD_ERR, SFSTAT);
+                               return -EBADE;
+                       }
+                       state = state_end;
+                       break;
+               }
+               case state_end:
+                       break;
+               }
+       } while (state != state_end);
+
+       return 0;
+}
+
+static int falcon_sflash_setup(struct spi_device *spi)
+{
+       unsigned int i;
+       unsigned long flags;
+
+       if (spi->chip_select > 0)
+               return -ENODEV;
+
+       spin_lock_irqsave(&ebu_lock, flags);
+
+       if (spi->max_speed_hz >= CLOCK_100M) {
+               /* set EBU clock to 100 MHz */
+               ltq_sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, EBUCC);
+               i = 1; /* divider */
+       } else {
+               /* set EBU clock to 50 MHz */
+               ltq_sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, EBUCC);
+
+               /* search for suitable divider */
+               for (i = 1; i < 7; i++) {
+                       if (CLOCK_50M / i <= spi->max_speed_hz)
+                               break;
+               }
+       }
+
+       /* setup period of serial clock */
+       ltq_ebu_w32_mask(SFTIME_SCKF_POS_MASK
+                    | SFTIME_SCKR_POS_MASK
+                    | SFTIME_SCK_PER_MASK,
+                    (i << SFTIME_SCKR_POS_OFFSET)
+                    | (i << (SFTIME_SCK_PER_OFFSET + 1)),
+                    SFTIME);
+
+       /*
+        * set some bits of unused_wd, to not trigger HOLD/WP
+        * signals on non QUAD flashes
+        */
+       ltq_ebu_w32((SFIO_UNUSED_WD_MASK & (0x8 | 0x4)), SFIO);
+
+       ltq_ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX,
+                       BUSRCON0);
+       ltq_ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, BUSWCON0);
+       /* set address wrap around to maximum for 24-bit addresses */
+       ltq_ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, SFCON);
+
+       spin_unlock_irqrestore(&ebu_lock, flags);
+
+       return 0;
+}
+
+static int falcon_sflash_prepare_xfer(struct spi_master *master)
+{
+       return 0;
+}
+
+static int falcon_sflash_unprepare_xfer(struct spi_master *master)
+{
+       return 0;
+}
+
+static int falcon_sflash_xfer_one(struct spi_master *master,
+                                       struct spi_message *m)
+{
+       struct falcon_sflash *priv = spi_master_get_devdata(master);
+       struct spi_transfer *t;
+       unsigned long spi_flags;
+       unsigned long flags;
+       int ret = 0;
+
+       priv->sfcmd = 0;
+       m->actual_length = 0;
+
+       spi_flags = FALCON_SPI_XFER_BEGIN;
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               if (list_is_last(&t->transfer_list, &m->transfers))
+                       spi_flags |= FALCON_SPI_XFER_END;
+
+               spin_lock_irqsave(&ebu_lock, flags);
+               ret = falcon_sflash_xfer(m->spi, t, spi_flags);
+               spin_unlock_irqrestore(&ebu_lock, flags);
+
+               if (ret)
+                       break;
+
+               m->actual_length += t->len;
+
+               WARN_ON(t->delay_usecs || t->cs_change);
+               spi_flags = 0;
+       }
+
+       m->status = ret;
+       m->complete(m->context);
+
+       return 0;
+}
+
+static int __devinit falcon_sflash_probe(struct platform_device *pdev)
+{
+       struct falcon_sflash *priv;
+       struct spi_master *master;
+       int ret;
+
+       if (ltq_boot_select() != BS_SPI) {
+               dev_err(&pdev->dev, "invalid bootstrap options\n");
+               return -ENODEV;
+       }
+
+       master = spi_alloc_master(&pdev->dev, sizeof(*priv));
+       if (!master)
+               return -ENOMEM;
+
+       priv = spi_master_get_devdata(master);
+       priv->master = master;
+
+       master->mode_bits = SPI_MODE_3;
+       master->num_chipselect = 1;
+       master->bus_num = -1;
+       master->setup = falcon_sflash_setup;
+       master->prepare_transfer_hardware = falcon_sflash_prepare_xfer;
+       master->transfer_one_message = falcon_sflash_xfer_one;
+       master->unprepare_transfer_hardware = falcon_sflash_unprepare_xfer;
+       master->dev.of_node = pdev->dev.of_node;
+
+       platform_set_drvdata(pdev, priv);
+
+       ret = spi_register_master(master);
+       if (ret)
+               spi_master_put(master);
+       return ret;
+}
+
+static int __devexit falcon_sflash_remove(struct platform_device *pdev)
+{
+       struct falcon_sflash *priv = platform_get_drvdata(pdev);
+
+       spi_unregister_master(priv->master);
+
+       return 0;
+}
+
+static const struct of_device_id falcon_sflash_match[] = {
+       { .compatible = "lantiq,sflash-falcon" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, falcon_sflash_match);
+
+static struct platform_driver falcon_sflash_driver = {
+       .probe  = falcon_sflash_probe,
+       .remove = __devexit_p(falcon_sflash_remove),
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = falcon_sflash_match,
+       }
+};
+
+module_platform_driver(falcon_sflash_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Lantiq Falcon SPI/SFLASH controller driver");
index 945d9623550b621c2731091a7804c66e3949e25e..4afc3b4197385e4cda191553a5fcdfefca080988 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/io.h>
 #include <asm/irq.h>
 #include <linux/fcntl.h>
+#include <linux/platform_device.h>
 #ifdef LIRC_ON_SA1100
 #include <asm/hardware.h>
 #ifdef CONFIG_SA1100_COLLIE
@@ -487,9 +488,11 @@ static struct lirc_driver driver = {
        .owner          = THIS_MODULE,
 };
 
+static struct platform_device *lirc_sir_dev;
 
 static int init_chrdev(void)
 {
+       driver.dev = &lirc_sir_dev->dev;
        driver.minor = lirc_register_driver(&driver);
        if (driver.minor < 0) {
                printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n");
@@ -1215,20 +1218,71 @@ static int init_lirc_sir(void)
        return 0;
 }
 
+static int __devinit lirc_sir_probe(struct platform_device *dev)
+{
+       return 0;
+}
+
+static int __devexit lirc_sir_remove(struct platform_device *dev)
+{
+       return 0;
+}
+
+static struct platform_driver lirc_sir_driver = {
+       .probe          = lirc_sir_probe,
+       .remove         = __devexit_p(lirc_sir_remove),
+       .driver         = {
+               .name   = "lirc_sir",
+               .owner  = THIS_MODULE,
+       },
+};
 
 static int __init lirc_sir_init(void)
 {
        int retval;
 
+       retval = platform_driver_register(&lirc_sir_driver);
+       if (retval) {
+               printk(KERN_ERR LIRC_DRIVER_NAME ": Platform driver register "
+                      "failed!\n");
+               return -ENODEV;
+       }
+
+       lirc_sir_dev = platform_device_alloc("lirc_dev", 0);
+       if (!lirc_sir_dev) {
+               printk(KERN_ERR LIRC_DRIVER_NAME ": Platform device alloc "
+                      "failed!\n");
+               retval = -ENOMEM;
+               goto pdev_alloc_fail;
+       }
+
+       retval = platform_device_add(lirc_sir_dev);
+       if (retval) {
+               printk(KERN_ERR LIRC_DRIVER_NAME ": Platform device add "
+                      "failed!\n");
+               retval = -ENODEV;
+               goto pdev_add_fail;
+       }
+
        retval = init_chrdev();
        if (retval < 0)
-               return retval;
+               goto fail;
+
        retval = init_lirc_sir();
        if (retval) {
                drop_chrdev();
-               return retval;
+               goto fail;
        }
+
        return 0;
+
+fail:
+       platform_device_del(lirc_sir_dev);
+pdev_add_fail:
+       platform_device_put(lirc_sir_dev);
+pdev_alloc_fail:
+       platform_driver_unregister(&lirc_sir_driver);
+       return retval;
 }
 
 static void __exit lirc_sir_exit(void)
@@ -1236,6 +1290,8 @@ static void __exit lirc_sir_exit(void)
        drop_hardware();
        drop_chrdev();
        drop_port();
+       platform_device_unregister(lirc_sir_dev);
+       platform_driver_unregister(&lirc_sir_driver);
        printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
 }
 
index 7e6c4fa130dfb60bbd3dd6b002f5c563ec146aa8..539f739fe9e650562b64b4fb2a0d8ddfd3e9c57c 100644 (file)
@@ -20,5 +20,5 @@ TODO (general):
          - implement loopback of external sound jack with incoming audio?
          - implement pause/resume
 
-Plase send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc Ben Collins
+Plase send patches to Mauro Carvalho Chehab <mchehab@redhat.com> and Cc Ben Collins
 <bcollins@bluecherry.net>
index ef95a500b4dad28684adc99383bc795a6e396066..398070a3d29326b738553df6e280f93b1e5c03f9 100644 (file)
@@ -175,7 +175,7 @@ int solo_i2c_isr(struct solo_dev *solo_dev)
 
        solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC);
 
-       if (status & (SOLO_IIC_STATE_TRNS & SOLO_IIC_STATE_SIG_ERR) ||
+       if (status & (SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR) ||
            solo_dev->i2c_id < 0) {
                solo_i2c_stop(solo_dev);
                return -ENXIO;
index e31949c9c87e37121376d71790acf0ad31af6c22..f15b31b37ca50920a6e4a314eea40f9e8d3185d5 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/ethtool.h>
 #include <linux/phy.h>
 #include <linux/ratelimit.h>
+#include <linux/of_mdio.h>
 
 #include <net/dst.h>
 
@@ -161,22 +162,23 @@ static void cvm_oct_adjust_link(struct net_device *dev)
 int cvm_oct_phy_setup_device(struct net_device *dev)
 {
        struct octeon_ethernet *priv = netdev_priv(dev);
+       struct device_node *phy_node;
 
-       int phy_addr = cvmx_helper_board_get_mii_address(priv->port);
-       if (phy_addr != -1) {
-               char phy_id[MII_BUS_ID_SIZE + 3];
+       if (!priv->of_node)
+               return 0;
 
-               snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "mdio-octeon-0", phy_addr);
+       phy_node = of_parse_phandle(priv->of_node, "phy-handle", 0);
+       if (!phy_node)
+               return 0;
 
-               priv->phydev = phy_connect(dev, phy_id, cvm_oct_adjust_link, 0,
-                                       PHY_INTERFACE_MODE_GMII);
+       priv->phydev = of_phy_connect(dev, phy_node, cvm_oct_adjust_link, 0,
+                                     PHY_INTERFACE_MODE_GMII);
+
+       if (priv->phydev == NULL)
+               return -ENODEV;
+
+       priv->last_link = 0;
+       phy_start_aneg(priv->phydev);
 
-               if (IS_ERR(priv->phydev)) {
-                       priv->phydev = NULL;
-                       return -1;
-               }
-               priv->last_link = 0;
-               phy_start_aneg(priv->phydev);
-       }
        return 0;
 }
index 18f7a790f73d52b42a33d0373c5f69174c076a33..683bedc74ddecfe9965b564c52437e53288648fa 100644 (file)
@@ -24,6 +24,7 @@
  * This file may also be available under a different license from Cavium.
  * Contact Cavium Networks for more information
 **********************************************************************/
+#include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -32,6 +33,7 @@
 #include <linux/phy.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/of_net.h>
 
 #include <net/dst.h>
 
@@ -113,15 +115,6 @@ int rx_napi_weight = 32;
 module_param(rx_napi_weight, int, 0444);
 MODULE_PARM_DESC(rx_napi_weight, "The NAPI WEIGHT parameter.");
 
-/*
- * The offset from mac_addr_base that should be used for the next port
- * that is configured.  By convention, if any mgmt ports exist on the
- * chip, they get the first mac addresses, The ports controlled by
- * this driver are numbered sequencially following any mgmt addresses
- * that may exist.
- */
-static unsigned int cvm_oct_mac_addr_offset;
-
 /**
  * cvm_oct_poll_queue - Workqueue for polling operations.
  */
@@ -176,7 +169,7 @@ static void cvm_oct_periodic_worker(struct work_struct *work)
                queue_delayed_work(cvm_oct_poll_queue, &priv->port_periodic_work, HZ);
  }
 
-static __init void cvm_oct_configure_common_hw(void)
+static __devinit void cvm_oct_configure_common_hw(void)
 {
        /* Setup the FPA */
        cvmx_fpa_enable();
@@ -396,23 +389,21 @@ static void cvm_oct_common_set_multicast_list(struct net_device *dev)
 
  * Returns Zero on success
  */
-static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
+static int cvm_oct_set_mac_filter(struct net_device *dev)
 {
        struct octeon_ethernet *priv = netdev_priv(dev);
        union cvmx_gmxx_prtx_cfg gmx_cfg;
        int interface = INTERFACE(priv->port);
        int index = INDEX(priv->port);
 
-       memcpy(dev->dev_addr, addr + 2, 6);
-
        if ((interface < 2)
            && (cvmx_helper_interface_get_mode(interface) !=
                CVMX_HELPER_INTERFACE_MODE_SPI)) {
                int i;
-               uint8_t *ptr = addr;
+               uint8_t *ptr = dev->dev_addr;
                uint64_t mac = 0;
                for (i = 0; i < 6; i++)
-                       mac = (mac << 8) | (uint64_t) (ptr[i + 2]);
+                       mac = (mac << 8) | (uint64_t)ptr[i];
 
                gmx_cfg.u64 =
                    cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
@@ -421,17 +412,17 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
 
                cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
                cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface),
-                              ptr[2]);
+                              ptr[0]);
                cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface),
-                              ptr[3]);
+                              ptr[1]);
                cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface),
-                              ptr[4]);
+                              ptr[2]);
                cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface),
-                              ptr[5]);
+                              ptr[3]);
                cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface),
-                              ptr[6]);
+                              ptr[4]);
                cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface),
-                              ptr[7]);
+                              ptr[5]);
                cvm_oct_common_set_multicast_list(dev);
                cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
                               gmx_cfg.u64);
@@ -439,6 +430,15 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
        return 0;
 }
 
+static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
+{
+       int r = eth_mac_addr(dev, addr);
+
+       if (r)
+               return r;
+       return cvm_oct_set_mac_filter(dev);
+}
+
 /**
  * cvm_oct_common_init - per network device initialization
  * @dev:    Device to initialize
@@ -448,26 +448,17 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
 int cvm_oct_common_init(struct net_device *dev)
 {
        struct octeon_ethernet *priv = netdev_priv(dev);
-       struct sockaddr sa;
-       u64 mac = ((u64)(octeon_bootinfo->mac_addr_base[0] & 0xff) << 40) |
-               ((u64)(octeon_bootinfo->mac_addr_base[1] & 0xff) << 32) |
-               ((u64)(octeon_bootinfo->mac_addr_base[2] & 0xff) << 24) |
-               ((u64)(octeon_bootinfo->mac_addr_base[3] & 0xff) << 16) |
-               ((u64)(octeon_bootinfo->mac_addr_base[4] & 0xff) << 8) |
-               (u64)(octeon_bootinfo->mac_addr_base[5] & 0xff);
-
-       mac += cvm_oct_mac_addr_offset;
-       sa.sa_data[0] = (mac >> 40) & 0xff;
-       sa.sa_data[1] = (mac >> 32) & 0xff;
-       sa.sa_data[2] = (mac >> 24) & 0xff;
-       sa.sa_data[3] = (mac >> 16) & 0xff;
-       sa.sa_data[4] = (mac >> 8) & 0xff;
-       sa.sa_data[5] = mac & 0xff;
-
-       if (cvm_oct_mac_addr_offset >= octeon_bootinfo->mac_addr_count)
-               printk(KERN_DEBUG "%s: Using MAC outside of the assigned range:"
-                       " %pM\n", dev->name, sa.sa_data);
-       cvm_oct_mac_addr_offset++;
+       const u8 *mac = NULL;
+
+       if (priv->of_node)
+               mac = of_get_mac_address(priv->of_node);
+
+       if (mac && is_valid_ether_addr(mac)) {
+               memcpy(dev->dev_addr, mac, ETH_ALEN);
+               dev->addr_assign_type &= ~NET_ADDR_RANDOM;
+       } else {
+               eth_hw_addr_random(dev);
+       }
 
        /*
         * Force the interface to use the POW send if always_use_pow
@@ -488,7 +479,7 @@ int cvm_oct_common_init(struct net_device *dev)
        SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops);
 
        cvm_oct_phy_setup_device(dev);
-       dev->netdev_ops->ndo_set_mac_address(dev, &sa);
+       cvm_oct_set_mac_filter(dev);
        dev->netdev_ops->ndo_change_mtu(dev, dev->mtu);
 
        /*
@@ -595,22 +586,55 @@ static const struct net_device_ops cvm_oct_pow_netdev_ops = {
 
 extern void octeon_mdiobus_force_mod_depencency(void);
 
-static int __init cvm_oct_init_module(void)
+static struct device_node * __devinit cvm_oct_of_get_child(const struct device_node *parent,
+                                                          int reg_val)
+{
+       struct device_node *node = NULL;
+       int size;
+       const __be32 *addr;
+
+       for (;;) {
+               node = of_get_next_child(parent, node);
+               if (!node)
+                       break;
+               addr = of_get_property(node, "reg", &size);
+               if (addr && (be32_to_cpu(*addr) == reg_val))
+                       break;
+       }
+       return node;
+}
+
+static struct device_node * __devinit cvm_oct_node_for_port(struct device_node *pip,
+                                                           int interface, int port)
+{
+       struct device_node *ni, *np;
+
+       ni = cvm_oct_of_get_child(pip, interface);
+       if (!ni)
+               return NULL;
+
+       np = cvm_oct_of_get_child(ni, port);
+       of_node_put(ni);
+
+       return np;
+}
+
+static int __devinit cvm_oct_probe(struct platform_device *pdev)
 {
        int num_interfaces;
        int interface;
        int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
        int qos;
+       struct device_node *pip;
 
        octeon_mdiobus_force_mod_depencency();
        pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION);
 
-       if (OCTEON_IS_MODEL(OCTEON_CN52XX))
-               cvm_oct_mac_addr_offset = 2; /* First two are the mgmt ports. */
-       else if (OCTEON_IS_MODEL(OCTEON_CN56XX))
-               cvm_oct_mac_addr_offset = 1; /* First one is the mgmt port. */
-       else
-               cvm_oct_mac_addr_offset = 0;
+       pip = pdev->dev.of_node;
+       if (!pip) {
+               pr_err("Error: No 'pip' in /aliases\n");
+               return -EINVAL;
+       }
 
        cvm_oct_poll_queue = create_singlethread_workqueue("octeon-ethernet");
        if (cvm_oct_poll_queue == NULL) {
@@ -689,10 +713,11 @@ static int __init cvm_oct_init_module(void)
                    cvmx_helper_interface_get_mode(interface);
                int num_ports = cvmx_helper_ports_on_interface(interface);
                int port;
+               int port_index;
 
-               for (port = cvmx_helper_get_ipd_port(interface, 0);
+               for (port_index = 0, port = cvmx_helper_get_ipd_port(interface, 0);
                     port < cvmx_helper_get_ipd_port(interface, num_ports);
-                    port++) {
+                    port_index++, port++) {
                        struct octeon_ethernet *priv;
                        struct net_device *dev =
                            alloc_etherdev(sizeof(struct octeon_ethernet));
@@ -703,6 +728,7 @@ static int __init cvm_oct_init_module(void)
 
                        /* Initialize the device private structure. */
                        priv = netdev_priv(dev);
+                       priv->of_node = cvm_oct_node_for_port(pip, interface, port_index);
 
                        INIT_DELAYED_WORK(&priv->port_periodic_work,
                                          cvm_oct_periodic_worker);
@@ -787,7 +813,7 @@ static int __init cvm_oct_init_module(void)
        return 0;
 }
 
-static void __exit cvm_oct_cleanup_module(void)
+static int __devexit cvm_oct_remove(struct platform_device *pdev)
 {
        int port;
 
@@ -835,10 +861,29 @@ static void __exit cvm_oct_cleanup_module(void)
        if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
                cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL,
                                      CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
+       return 0;
 }
 
+static struct of_device_id cvm_oct_match[] = {
+       {
+               .compatible = "cavium,octeon-3860-pip",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, cvm_oct_match);
+
+static struct platform_driver cvm_oct_driver = {
+       .probe          = cvm_oct_probe,
+       .remove         = __devexit_p(cvm_oct_remove),
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = KBUILD_MODNAME,
+               .of_match_table = cvm_oct_match,
+       },
+};
+
+module_platform_driver(cvm_oct_driver);
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
 MODULE_DESCRIPTION("Cavium Networks Octeon ethernet driver.");
-module_init(cvm_oct_init_module);
-module_exit(cvm_oct_cleanup_module);
index d58192563552db54a555f489c97ca675d8f822cd..9360e22e07398d9da6f3dcb5734546d27abc25a2 100644 (file)
@@ -31,6 +31,8 @@
 #ifndef OCTEON_ETHERNET_H
 #define OCTEON_ETHERNET_H
 
+#include <linux/of.h>
+
 /**
  * This is the definition of the Ethernet driver's private
  * driver state stored in netdev_priv(dev).
@@ -59,6 +61,7 @@ struct octeon_ethernet {
        void (*poll) (struct net_device *dev);
        struct delayed_work     port_periodic_work;
        struct work_struct      port_work;      /* may be unused. */
+       struct device_node      *of_node;
 };
 
 int cvm_oct_free_work(void *work_queue_entry);
index 2d7a9fe8f365b64670dca63b98f925e7b0a15e73..2ab31e4f02cc741ee5d7b1c603a9158b34f335c4 100644 (file)
@@ -1251,7 +1251,7 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
  * longer needed. The passive cooling formula uses tc1 and tc2 as described in
  * section 11.1.5.1 of the ACPI specification 3.0.
  */
-struct thermal_zone_device *thermal_zone_device_register(char *type,
+struct thermal_zone_device *thermal_zone_device_register(const char *type,
        int trips, int mask, void *devdata,
        const struct thermal_zone_device_ops *ops,
        int tc1, int tc2, int passive_delay, int polling_delay)
index 8981fbb5748ccf4b7acf3207af2ac0e54d65e46c..cf6bd626f3fe1e3731b062328226b842a84fcb50 100644 (file)
@@ -1583,12 +1583,10 @@ static int __exit m66592_remove(struct platform_device *pdev)
        iounmap(m66592->reg);
        free_irq(platform_get_irq(pdev, 0), m66592);
        m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
-#ifdef CONFIG_HAVE_CLK
        if (m66592->pdata->on_chip) {
                clk_disable(m66592->clk);
                clk_put(m66592->clk);
        }
-#endif
        kfree(m66592);
        return 0;
 }
@@ -1602,9 +1600,7 @@ static int __init m66592_probe(struct platform_device *pdev)
        struct resource *res, *ires;
        void __iomem *reg = NULL;
        struct m66592 *m66592 = NULL;
-#ifdef CONFIG_HAVE_CLK
        char clk_name[8];
-#endif
        int ret = 0;
        int i;
 
@@ -1671,7 +1667,6 @@ static int __init m66592_probe(struct platform_device *pdev)
                goto clean_up;
        }
 
-#ifdef CONFIG_HAVE_CLK
        if (m66592->pdata->on_chip) {
                snprintf(clk_name, sizeof(clk_name), "usbf%d", pdev->id);
                m66592->clk = clk_get(&pdev->dev, clk_name);
@@ -1683,7 +1678,7 @@ static int __init m66592_probe(struct platform_device *pdev)
                }
                clk_enable(m66592->clk);
        }
-#endif
+
        INIT_LIST_HEAD(&m66592->gadget.ep_list);
        m66592->gadget.ep0 = &m66592->ep[0].ep;
        INIT_LIST_HEAD(&m66592->gadget.ep0->ep_list);
@@ -1731,13 +1726,11 @@ err_add_udc:
        m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
 
 clean_up3:
-#ifdef CONFIG_HAVE_CLK
        if (m66592->pdata->on_chip) {
                clk_disable(m66592->clk);
                clk_put(m66592->clk);
        }
 clean_up2:
-#endif
        free_irq(ires->start, m66592);
 clean_up:
        if (m66592) {
index 88c85b4116a2f1234820db626982b0b3bcedd9f5..16c7e14678b8d220b12a33ac98ec40be436c275c 100644 (file)
 #ifndef __M66592_UDC_H__
 #define __M66592_UDC_H__
 
-#ifdef CONFIG_HAVE_CLK
 #include <linux/clk.h>
-#endif
-
 #include <linux/usb/m66592.h>
 
 #define M66592_SYSCFG          0x00
@@ -468,9 +465,7 @@ struct m66592_ep {
 struct m66592 {
        spinlock_t              lock;
        void __iomem            *reg;
-#ifdef CONFIG_HAVE_CLK
        struct clk *clk;
-#endif
        struct m66592_platdata  *pdata;
        unsigned long           irq_trigger;
 
index f3ac2a20c27caac8097db4526c725bc084850585..5a80751accb7de937af730a988fa0f0f2474232a 100644 (file)
@@ -1831,12 +1831,12 @@ static int __exit r8a66597_remove(struct platform_device *pdev)
                iounmap(r8a66597->sudmac_reg);
        free_irq(platform_get_irq(pdev, 0), r8a66597);
        r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
-#ifdef CONFIG_HAVE_CLK
+
        if (r8a66597->pdata->on_chip) {
                clk_disable(r8a66597->clk);
                clk_put(r8a66597->clk);
        }
-#endif
+
        device_unregister(&r8a66597->gadget.dev);
        kfree(r8a66597);
        return 0;
@@ -1868,9 +1868,7 @@ static int __init r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597,
 
 static int __init r8a66597_probe(struct platform_device *pdev)
 {
-#ifdef CONFIG_HAVE_CLK
        char clk_name[8];
-#endif
        struct resource *res, *ires;
        int irq;
        void __iomem *reg = NULL;
@@ -1934,7 +1932,6 @@ static int __init r8a66597_probe(struct platform_device *pdev)
        r8a66597->timer.data = (unsigned long)r8a66597;
        r8a66597->reg = reg;
 
-#ifdef CONFIG_HAVE_CLK
        if (r8a66597->pdata->on_chip) {
                snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
                r8a66597->clk = clk_get(&pdev->dev, clk_name);
@@ -1946,7 +1943,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
                }
                clk_enable(r8a66597->clk);
        }
-#endif
+
        if (r8a66597->pdata->sudmac) {
                ret = r8a66597_sudmac_ioremap(r8a66597, pdev);
                if (ret < 0)
@@ -2006,13 +2003,11 @@ err_add_udc:
 clean_up3:
        free_irq(irq, r8a66597);
 clean_up2:
-#ifdef CONFIG_HAVE_CLK
        if (r8a66597->pdata->on_chip) {
                clk_disable(r8a66597->clk);
                clk_put(r8a66597->clk);
        }
 clean_up_dev:
-#endif
        device_unregister(&r8a66597->gadget.dev);
 clean_up:
        if (r8a66597) {
index 99908c76ccd1cf6972fdb42b1fc65c0f516f6fdd..45c4b2df1785d0de45bbd19669b351abaf85fd55 100644 (file)
 #ifndef __R8A66597_H__
 #define __R8A66597_H__
 
-#ifdef CONFIG_HAVE_CLK
 #include <linux/clk.h>
-#endif
-
 #include <linux/usb/r8a66597.h>
 
 #define R8A66597_MAX_SAMPLING  10
@@ -92,9 +89,7 @@ struct r8a66597 {
        void __iomem            *reg;
        void __iomem            *sudmac_reg;
 
-#ifdef CONFIG_HAVE_CLK
        struct clk *clk;
-#endif
        struct r8a66597_platdata        *pdata;
 
        struct usb_gadget               gadget;
index ec21f4a4a056830eff955230a8762254cd8bf529..bb55eb4a7d485b806e69ba0c5141912f04bd6791 100644 (file)
@@ -152,14 +152,14 @@ static int omap_ehci_init(struct usb_hcd *hcd)
        struct ehci_hcd_omap_platform_data      *pdata;
 
        pdata = hcd->self.controller->platform_data;
+
+       /* Hold PHYs in reset while initializing EHCI controller */
        if (pdata->phy_reset) {
                if (gpio_is_valid(pdata->reset_gpio_port[0]))
-                       gpio_request_one(pdata->reset_gpio_port[0],
-                                        GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
+                       gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
 
                if (gpio_is_valid(pdata->reset_gpio_port[1]))
-                       gpio_request_one(pdata->reset_gpio_port[1],
-                                        GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
+                       gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
 
                /* Hold the PHY in RESET for enough time till DIR is high */
                udelay(10);
index c868be65e7634bcc2b44d9d15610c8275b3be32b..4c634eb56358a1231a6c9fcb1dc05c1b983bf99d 100644 (file)
@@ -95,9 +95,7 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
        int i = 0;
 
        if (r8a66597->pdata->on_chip) {
-#ifdef CONFIG_HAVE_CLK
                clk_enable(r8a66597->clk);
-#endif
                do {
                        r8a66597_write(r8a66597, SCKE, SYSCFG0);
                        tmp = r8a66597_read(r8a66597, SYSCFG0);
@@ -141,9 +139,7 @@ static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
        udelay(1);
 
        if (r8a66597->pdata->on_chip) {
-#ifdef CONFIG_HAVE_CLK
                clk_disable(r8a66597->clk);
-#endif
        } else {
                r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
                r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
@@ -2406,19 +2402,15 @@ static int __devexit r8a66597_remove(struct platform_device *pdev)
        del_timer_sync(&r8a66597->rh_timer);
        usb_remove_hcd(hcd);
        iounmap(r8a66597->reg);
-#ifdef CONFIG_HAVE_CLK
        if (r8a66597->pdata->on_chip)
                clk_put(r8a66597->clk);
-#endif
        usb_put_hcd(hcd);
        return 0;
 }
 
 static int __devinit r8a66597_probe(struct platform_device *pdev)
 {
-#ifdef CONFIG_HAVE_CLK
        char clk_name[8];
-#endif
        struct resource *res = NULL, *ires;
        int irq = -1;
        void __iomem *reg = NULL;
@@ -2482,7 +2474,6 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
        r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
 
        if (r8a66597->pdata->on_chip) {
-#ifdef CONFIG_HAVE_CLK
                snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
                r8a66597->clk = clk_get(&pdev->dev, clk_name);
                if (IS_ERR(r8a66597->clk)) {
@@ -2491,7 +2482,6 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
                        ret = PTR_ERR(r8a66597->clk);
                        goto clean_up2;
                }
-#endif
                r8a66597->max_root_hub = 1;
        } else
                r8a66597->max_root_hub = 2;
@@ -2531,11 +2521,9 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
        return 0;
 
 clean_up3:
-#ifdef CONFIG_HAVE_CLK
        if (r8a66597->pdata->on_chip)
                clk_put(r8a66597->clk);
 clean_up2:
-#endif
        usb_put_hcd(hcd);
 
 clean_up:
index f28782d20eef0eab2a0f7c124146e3c154ba8e2f..672cea307abb774639d6e362b0603309bcdb2c45 100644 (file)
 #ifndef __R8A66597_H__
 #define __R8A66597_H__
 
-#ifdef CONFIG_HAVE_CLK
 #include <linux/clk.h>
-#endif
-
 #include <linux/usb/r8a66597.h>
 
 #define R8A66597_MAX_NUM_PIPE          10
@@ -113,9 +110,7 @@ struct r8a66597_root_hub {
 struct r8a66597 {
        spinlock_t lock;
        void __iomem *reg;
-#ifdef CONFIG_HAVE_CLK
        struct clk *clk;
-#endif
        struct r8a66597_platdata        *pdata;
        struct r8a66597_device          device0;
        struct r8a66597_root_hub        root_hub[R8A66597_MAX_ROOT_HUB];
index dbcdeea30f09c199d0ebaa9b3f14a8f4d9179919..586105b55a7ceae23a79d76e2c8b35578e7827a7 100644 (file)
@@ -81,14 +81,6 @@ struct musb_ep;
 #define is_peripheral_active(m)                (!(m)->is_host)
 #define is_host_active(m)              ((m)->is_host)
 
-#ifndef CONFIG_HAVE_CLK
-/* Dummy stub for clk framework */
-#define clk_get(dev, id)       NULL
-#define clk_put(clock)         do {} while (0)
-#define clk_enable(clock)      do {} while (0)
-#define clk_disable(clock)     do {} while (0)
-#endif
-
 #ifdef CONFIG_PROC_FS
 #include <linux/fs.h>
 #define MUSB_CONFIG_PROC_FS
index 2979292650d6494a5fddef3f3835da5931f37ec0..cf282763a8dc941ab96554ed1cae855d959199de 100644 (file)
@@ -245,7 +245,7 @@ config BACKLIGHT_CARILLO_RANCH
 
 config BACKLIGHT_PWM
        tristate "Generic PWM based Backlight Driver"
-       depends on HAVE_PWM
+       depends on PWM
        help
          If you have a LCD backlight adjustable by PWM, say Y to enable
          this driver.
index 0443a4f718580c4381acf7d5cb538e941b7e2aa5..df1cbb7ef6ca0370551904b190ba968315ee92c7 100644 (file)
@@ -127,7 +127,8 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
        struct atmel_pwm_bl *pwmbl;
        int retval;
 
-       pwmbl = kzalloc(sizeof(struct atmel_pwm_bl), GFP_KERNEL);
+       pwmbl = devm_kzalloc(&pdev->dev, sizeof(struct atmel_pwm_bl),
+                               GFP_KERNEL);
        if (!pwmbl)
                return -ENOMEM;
 
@@ -154,7 +155,8 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
                goto err_free_mem;
 
        if (pwmbl->gpio_on != -1) {
-               retval = gpio_request(pwmbl->gpio_on, "gpio_atmel_pwm_bl");
+               retval = devm_gpio_request(&pdev->dev, pwmbl->gpio_on,
+                                       "gpio_atmel_pwm_bl");
                if (retval) {
                        pwmbl->gpio_on = -1;
                        goto err_free_pwm;
@@ -164,7 +166,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
                retval = gpio_direction_output(pwmbl->gpio_on,
                                0 ^ pdata->on_active_low);
                if (retval)
-                       goto err_free_gpio;
+                       goto err_free_pwm;
        }
 
        memset(&props, 0, sizeof(struct backlight_properties));
@@ -174,7 +176,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
                                          &atmel_pwm_bl_ops, &props);
        if (IS_ERR(bldev)) {
                retval = PTR_ERR(bldev);
-               goto err_free_gpio;
+               goto err_free_pwm;
        }
 
        pwmbl->bldev = bldev;
@@ -196,13 +198,9 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
 err_free_bl_dev:
        platform_set_drvdata(pdev, NULL);
        backlight_device_unregister(bldev);
-err_free_gpio:
-       if (pwmbl->gpio_on != -1)
-               gpio_free(pwmbl->gpio_on);
 err_free_pwm:
        pwm_channel_free(&pwmbl->pwmc);
 err_free_mem:
-       kfree(pwmbl);
        return retval;
 }
 
@@ -210,15 +208,12 @@ static int __exit atmel_pwm_bl_remove(struct platform_device *pdev)
 {
        struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev);
 
-       if (pwmbl->gpio_on != -1) {
+       if (pwmbl->gpio_on != -1)
                gpio_set_value(pwmbl->gpio_on, 0);
-               gpio_free(pwmbl->gpio_on);
-       }
        pwm_channel_disable(&pwmbl->pwmc);
        pwm_channel_free(&pwmbl->pwmc);
        backlight_device_unregister(pwmbl->bldev);
        platform_set_drvdata(pdev, NULL);
-       kfree(pwmbl);
 
        return 0;
 }
index 23d732677ba177e6594818dbc98bf17fb5ada229..c781768ba8923d61d4350e4a4181ede8a0808185 100644 (file)
@@ -492,7 +492,8 @@ static int setup_gpio_backlight(struct corgi_lcd *lcd,
        lcd->gpio_backlight_cont = -1;
 
        if (gpio_is_valid(pdata->gpio_backlight_on)) {
-               err = gpio_request(pdata->gpio_backlight_on, "BL_ON");
+               err = devm_gpio_request(&spi->dev, pdata->gpio_backlight_on,
+                                       "BL_ON");
                if (err) {
                        dev_err(&spi->dev, "failed to request GPIO%d for "
                                "backlight_on\n", pdata->gpio_backlight_on);
@@ -504,11 +505,12 @@ static int setup_gpio_backlight(struct corgi_lcd *lcd,
        }
 
        if (gpio_is_valid(pdata->gpio_backlight_cont)) {
-               err = gpio_request(pdata->gpio_backlight_cont, "BL_CONT");
+               err = devm_gpio_request(&spi->dev, pdata->gpio_backlight_cont,
+                                       "BL_CONT");
                if (err) {
                        dev_err(&spi->dev, "failed to request GPIO%d for "
                                "backlight_cont\n", pdata->gpio_backlight_cont);
-                       goto err_free_backlight_on;
+                       return err;
                }
 
                lcd->gpio_backlight_cont = pdata->gpio_backlight_cont;
@@ -525,11 +527,6 @@ static int setup_gpio_backlight(struct corgi_lcd *lcd,
                }
        }
        return 0;
-
-err_free_backlight_on:
-       if (gpio_is_valid(lcd->gpio_backlight_on))
-               gpio_free(lcd->gpio_backlight_on);
-       return err;
 }
 
 static int __devinit corgi_lcd_probe(struct spi_device *spi)
@@ -602,12 +599,6 @@ static int __devexit corgi_lcd_remove(struct spi_device *spi)
        backlight_update_status(lcd->bl_dev);
        backlight_device_unregister(lcd->bl_dev);
 
-       if (gpio_is_valid(lcd->gpio_backlight_on))
-               gpio_free(lcd->gpio_backlight_on);
-
-       if (gpio_is_valid(lcd->gpio_backlight_cont))
-               gpio_free(lcd->gpio_backlight_cont);
-
        corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
        lcd_device_unregister(lcd->lcd_dev);
 
index 40f606a860934a7bb21fab7fb60b457a390e1c2a..2d90c0648aa056f09992b23d4f70dde5b536137f 100644 (file)
@@ -175,28 +175,27 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
 
        priv->spi = spi;
 
-       ret = gpio_request_one(pdata->reset_gpio, GPIOF_OUT_INIT_HIGH,
-                                               "lcd l4f00242t03 reset");
+       ret = devm_gpio_request_one(&spi->dev, pdata->reset_gpio,
+                       GPIOF_OUT_INIT_HIGH, "lcd l4f00242t03 reset");
        if (ret) {
                dev_err(&spi->dev,
                        "Unable to get the lcd l4f00242t03 reset gpio.\n");
                return ret;
        }
 
-       ret = gpio_request_one(pdata->data_enable_gpio, GPIOF_OUT_INIT_LOW,
-                                               "lcd l4f00242t03 data enable");
+       ret = devm_gpio_request_one(&spi->dev, pdata->data_enable_gpio,
+                       GPIOF_OUT_INIT_LOW, "lcd l4f00242t03 data enable");
        if (ret) {
                dev_err(&spi->dev,
                        "Unable to get the lcd l4f00242t03 data en gpio.\n");
-               goto err;
+               return ret;
        }
 
        priv->io_reg = regulator_get(&spi->dev, "vdd");
        if (IS_ERR(priv->io_reg)) {
-               ret = PTR_ERR(priv->io_reg);
                dev_err(&spi->dev, "%s: Unable to get the IO regulator\n",
                       __func__);
-               goto err2;
+               return PTR_ERR(priv->io_reg);
        }
 
        priv->core_reg = regulator_get(&spi->dev, "vcore");
@@ -204,14 +203,14 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
                ret = PTR_ERR(priv->core_reg);
                dev_err(&spi->dev, "%s: Unable to get the core regulator\n",
                       __func__);
-               goto err3;
+               goto err1;
        }
 
        priv->ld = lcd_device_register("l4f00242t03",
                                        &spi->dev, priv, &l4f_ops);
        if (IS_ERR(priv->ld)) {
                ret = PTR_ERR(priv->ld);
-               goto err4;
+               goto err2;
        }
 
        /* Init the LCD */
@@ -223,14 +222,10 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
 
        return 0;
 
-err4:
+err2:
        regulator_put(priv->core_reg);
-err3:
+err1:
        regulator_put(priv->io_reg);
-err2:
-       gpio_free(pdata->data_enable_gpio);
-err:
-       gpio_free(pdata->reset_gpio);
 
        return ret;
 }
@@ -238,16 +233,12 @@ err:
 static int __devexit l4f00242t03_remove(struct spi_device *spi)
 {
        struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
-       struct l4f00242t03_pdata *pdata = priv->spi->dev.platform_data;
 
        l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN);
        lcd_device_unregister(priv->ld);
 
        dev_set_drvdata(&spi->dev, NULL);
 
-       gpio_free(pdata->data_enable_gpio);
-       gpio_free(pdata->reset_gpio);
-
        regulator_put(priv->io_reg);
        regulator_put(priv->core_reg);
 
index bebeb63607db214e7e679732d2277ac686a015fe..18dca0c29c6836456954a83e97b76fa24625db19 100644 (file)
@@ -295,7 +295,7 @@ static int __devinit lm3533_bl_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       bl = kzalloc(sizeof(*bl), GFP_KERNEL);
+       bl = devm_kzalloc(&pdev->dev, sizeof(*bl), GFP_KERNEL);
        if (!bl) {
                dev_err(&pdev->dev,
                                "failed to allocate memory for backlight\n");
@@ -317,8 +317,7 @@ static int __devinit lm3533_bl_probe(struct platform_device *pdev)
                                                &lm3533_bl_ops, &props);
        if (IS_ERR(bd)) {
                dev_err(&pdev->dev, "failed to register backlight device\n");
-               ret = PTR_ERR(bd);
-               goto err_free;
+               return PTR_ERR(bd);
        }
 
        bl->bd = bd;
@@ -348,8 +347,6 @@ err_sysfs_remove:
        sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group);
 err_unregister:
        backlight_device_unregister(bd);
-err_free:
-       kfree(bl);
 
        return ret;
 }
@@ -367,7 +364,6 @@ static int __devexit lm3533_bl_remove(struct platform_device *pdev)
        lm3533_ctrlbank_disable(&bl->cb);
        sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group);
        backlight_device_unregister(bd);
-       kfree(bl);
 
        return 0;
 }
index a9f2c36966f1ff60fcf0a8873c1d01f93017c500..ea43f2254196b65982875bd420d9c16320d2457f 100644 (file)
@@ -158,29 +158,27 @@ static int __devinit lms283gf05_probe(struct spi_device *spi)
        int ret = 0;
 
        if (pdata != NULL) {
-               ret = gpio_request(pdata->reset_gpio, "LMS285GF05 RESET");
+               ret = devm_gpio_request(&spi->dev, pdata->reset_gpio,
+                                       "LMS285GF05 RESET");
                if (ret)
                        return ret;
 
                ret = gpio_direction_output(pdata->reset_gpio,
                                                !pdata->reset_inverted);
                if (ret)
-                       goto err;
+                       return ret;
        }
 
        st = devm_kzalloc(&spi->dev, sizeof(struct lms283gf05_state),
                                GFP_KERNEL);
        if (st == NULL) {
                dev_err(&spi->dev, "No memory for device state\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
 
        ld = lcd_device_register("lms283gf05", &spi->dev, st, &lms_ops);
-       if (IS_ERR(ld)) {
-               ret = PTR_ERR(ld);
-               goto err;
-       }
+       if (IS_ERR(ld))
+               return PTR_ERR(ld);
 
        st->spi = spi;
        st->ld = ld;
@@ -193,24 +191,14 @@ static int __devinit lms283gf05_probe(struct spi_device *spi)
        lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq));
 
        return 0;
-
-err:
-       if (pdata != NULL)
-               gpio_free(pdata->reset_gpio);
-
-       return ret;
 }
 
 static int __devexit lms283gf05_remove(struct spi_device *spi)
 {
        struct lms283gf05_state *st = dev_get_drvdata(&spi->dev);
-       struct lms283gf05_pdata *pdata = st->spi->dev.platform_data;
 
        lcd_device_unregister(st->ld);
 
-       if (pdata != NULL)
-               gpio_free(pdata->reset_gpio);
-
        return 0;
 }
 
index 72a0e0c917cf3246ecf21d0b2bed41b9c3b502b3..aa6d4f71131f5b6bb22fba425bc04d5caa726a95 100644 (file)
 #include <linux/i2c.h>
 #include <linux/backlight.h>
 #include <linux/err.h>
-#include <linux/lp855x.h>
+#include <linux/platform_data/lp855x.h>
 
 /* Registers */
-#define BRIGHTNESS_CTRL                (0x00)
-#define DEVICE_CTRL            (0x01)
+#define BRIGHTNESS_CTRL                0x00
+#define DEVICE_CTRL            0x01
+#define EEPROM_START           0xA0
+#define EEPROM_END             0xA7
+#define EPROM_START            0xA0
+#define EPROM_END              0xAF
 
 #define BUF_SIZE               20
 #define DEFAULT_BL_NAME                "lcd-backlight"
index f519d55a294c5cdb97cc7b53ff4b81f1cc32d49c..469cf0f109d2a501a9d3d9aafb0ebecf0464f299 100644 (file)
@@ -84,7 +84,8 @@ static int ot200_backlight_probe(struct platform_device *pdev)
        int retval = 0;
 
        /* request gpio */
-       if (gpio_request(GPIO_DIMM, "ot200 backlight dimmer") < 0) {
+       if (devm_gpio_request(&pdev->dev, GPIO_DIMM,
+                               "ot200 backlight dimmer") < 0) {
                dev_err(&pdev->dev, "failed to request GPIO %d\n", GPIO_DIMM);
                return -ENODEV;
        }
@@ -93,14 +94,13 @@ static int ot200_backlight_probe(struct platform_device *pdev)
        pwm_timer = cs5535_mfgpt_alloc_timer(7, MFGPT_DOMAIN_ANY);
        if (!pwm_timer) {
                dev_err(&pdev->dev, "MFGPT 7 not available\n");
-               retval = -ENODEV;
-               goto error_mfgpt_alloc;
+               return -ENODEV;
        }
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (!data) {
                retval = -ENOMEM;
-               goto error_kzalloc;
+               goto error_devm_kzalloc;
        }
 
        /* setup gpio */
@@ -122,26 +122,21 @@ static int ot200_backlight_probe(struct platform_device *pdev)
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
                retval = PTR_ERR(bl);
-               goto error_backlight_device_register;
+               goto error_devm_kzalloc;
        }
 
        platform_set_drvdata(pdev, bl);
 
        return 0;
 
-error_backlight_device_register:
-       kfree(data);
-error_kzalloc:
+error_devm_kzalloc:
        cs5535_mfgpt_free_timer(pwm_timer);
-error_mfgpt_alloc:
-       gpio_free(GPIO_DIMM);
        return retval;
 }
 
 static int ot200_backlight_remove(struct platform_device *pdev)
 {
        struct backlight_device *bl = platform_get_drvdata(pdev);
-       struct ot200_backlight_data *data = bl_get_data(bl);
 
        backlight_device_unregister(bl);
 
@@ -152,9 +147,7 @@ static int ot200_backlight_remove(struct platform_device *pdev)
                MAX_COMP2 - dim_table[100]);
 
        cs5535_mfgpt_free_timer(pwm_timer);
-       gpio_free(GPIO_DIMM);
 
-       kfree(data);
        return 0;
 }
 
index 342b7d7cbb632826611f856a7eaa578220d16681..995f0164c9b082c7da2836123adfcb2b7f10a6c7 100644 (file)
@@ -26,11 +26,13 @@ struct pwm_bl_data {
        struct device           *dev;
        unsigned int            period;
        unsigned int            lth_brightness;
+       unsigned int            *levels;
        int                     (*notify)(struct device *,
                                          int brightness);
        void                    (*notify_after)(struct device *,
                                        int brightness);
        int                     (*check_fb)(struct device *, struct fb_info *);
+       void                    (*exit)(struct device *);
 };
 
 static int pwm_backlight_update_status(struct backlight_device *bl)
@@ -52,9 +54,18 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
                pwm_config(pb->pwm, 0, pb->period);
                pwm_disable(pb->pwm);
        } else {
-               brightness = pb->lth_brightness +
-                       (brightness * (pb->period - pb->lth_brightness) / max);
-               pwm_config(pb->pwm, brightness, pb->period);
+               int duty_cycle;
+
+               if (pb->levels) {
+                       duty_cycle = pb->levels[brightness];
+                       max = pb->levels[max];
+               } else {
+                       duty_cycle = brightness;
+               }
+
+               duty_cycle = pb->lth_brightness +
+                    (duty_cycle * (pb->period - pb->lth_brightness) / max);
+               pwm_config(pb->pwm, duty_cycle, pb->period);
                pwm_enable(pb->pwm);
        }
 
@@ -83,17 +94,98 @@ static const struct backlight_ops pwm_backlight_ops = {
        .check_fb       = pwm_backlight_check_fb,
 };
 
+#ifdef CONFIG_OF
+static int pwm_backlight_parse_dt(struct device *dev,
+                                 struct platform_pwm_backlight_data *data)
+{
+       struct device_node *node = dev->of_node;
+       struct property *prop;
+       int length;
+       u32 value;
+       int ret;
+
+       if (!node)
+               return -ENODEV;
+
+       memset(data, 0, sizeof(*data));
+
+       /* determine the number of brightness levels */
+       prop = of_find_property(node, "brightness-levels", &length);
+       if (!prop)
+               return -EINVAL;
+
+       data->max_brightness = length / sizeof(u32);
+
+       /* read brightness levels from DT property */
+       if (data->max_brightness > 0) {
+               size_t size = sizeof(*data->levels) * data->max_brightness;
+
+               data->levels = devm_kzalloc(dev, size, GFP_KERNEL);
+               if (!data->levels)
+                       return -ENOMEM;
+
+               ret = of_property_read_u32_array(node, "brightness-levels",
+                                                data->levels,
+                                                data->max_brightness);
+               if (ret < 0)
+                       return ret;
+
+               ret = of_property_read_u32(node, "default-brightness-level",
+                                          &value);
+               if (ret < 0)
+                       return ret;
+
+               if (value >= data->max_brightness) {
+                       dev_warn(dev, "invalid default brightness level: %u, using %u\n",
+                                value, data->max_brightness - 1);
+                       value = data->max_brightness - 1;
+               }
+
+               data->dft_brightness = value;
+               data->max_brightness--;
+       }
+
+       /*
+        * TODO: Most users of this driver use a number of GPIOs to control
+        *       backlight power. Support for specifying these needs to be
+        *       added.
+        */
+
+       return 0;
+}
+
+static struct of_device_id pwm_backlight_of_match[] = {
+       { .compatible = "pwm-backlight" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, pwm_backlight_of_match);
+#else
+static int pwm_backlight_parse_dt(struct device *dev,
+                                 struct platform_pwm_backlight_data *data)
+{
+       return -ENODEV;
+}
+#endif
+
 static int pwm_backlight_probe(struct platform_device *pdev)
 {
-       struct backlight_properties props;
        struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
+       struct platform_pwm_backlight_data defdata;
+       struct backlight_properties props;
        struct backlight_device *bl;
        struct pwm_bl_data *pb;
+       unsigned int max;
        int ret;
 
        if (!data) {
-               dev_err(&pdev->dev, "failed to find platform data\n");
-               return -EINVAL;
+               ret = pwm_backlight_parse_dt(&pdev->dev, &defdata);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to find platform data\n");
+                       return ret;
+               }
+
+               data = &defdata;
        }
 
        if (data->init) {
@@ -109,21 +201,42 @@ static int pwm_backlight_probe(struct platform_device *pdev)
                goto err_alloc;
        }
 
-       pb->period = data->pwm_period_ns;
+       if (data->levels) {
+               max = data->levels[data->max_brightness];
+               pb->levels = data->levels;
+       } else
+               max = data->max_brightness;
+
        pb->notify = data->notify;
        pb->notify_after = data->notify_after;
        pb->check_fb = data->check_fb;
-       pb->lth_brightness = data->lth_brightness *
-               (data->pwm_period_ns / data->max_brightness);
+       pb->exit = data->exit;
        pb->dev = &pdev->dev;
 
-       pb->pwm = pwm_request(data->pwm_id, "backlight");
+       pb->pwm = pwm_get(&pdev->dev, NULL);
        if (IS_ERR(pb->pwm)) {
-               dev_err(&pdev->dev, "unable to request PWM for backlight\n");
-               ret = PTR_ERR(pb->pwm);
-               goto err_alloc;
-       } else
-               dev_dbg(&pdev->dev, "got pwm for backlight\n");
+               dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
+
+               pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
+               if (IS_ERR(pb->pwm)) {
+                       dev_err(&pdev->dev, "unable to request legacy PWM\n");
+                       ret = PTR_ERR(pb->pwm);
+                       goto err_alloc;
+               }
+       }
+
+       dev_dbg(&pdev->dev, "got pwm for backlight\n");
+
+       /*
+        * The DT case will set the pwm_period_ns field to 0 and store the
+        * period, parsed from the DT, in the PWM device. For the non-DT case,
+        * set the period from platform data.
+        */
+       if (data->pwm_period_ns > 0)
+               pwm_set_period(pb->pwm, data->pwm_period_ns);
+
+       pb->period = pwm_get_period(pb->pwm);
+       pb->lth_brightness = data->lth_brightness * (pb->period / max);
 
        memset(&props, 0, sizeof(struct backlight_properties));
        props.type = BACKLIGHT_RAW;
@@ -143,7 +256,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
        return 0;
 
 err_bl:
-       pwm_free(pb->pwm);
+       pwm_put(pb->pwm);
 err_alloc:
        if (data->exit)
                data->exit(&pdev->dev);
@@ -152,16 +265,15 @@ err_alloc:
 
 static int pwm_backlight_remove(struct platform_device *pdev)
 {
-       struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
        struct backlight_device *bl = platform_get_drvdata(pdev);
        struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
 
        backlight_device_unregister(bl);
        pwm_config(pb->pwm, 0, pb->period);
        pwm_disable(pb->pwm);
-       pwm_free(pb->pwm);
-       if (data->exit)
-               data->exit(&pdev->dev);
+       pwm_put(pb->pwm);
+       if (pb->exit)
+               pb->exit(&pdev->dev);
        return 0;
 }
 
@@ -195,11 +307,12 @@ static SIMPLE_DEV_PM_OPS(pwm_backlight_pm_ops, pwm_backlight_suspend,
 
 static struct platform_driver pwm_backlight_driver = {
        .driver         = {
-               .name   = "pwm-backlight",
-               .owner  = THIS_MODULE,
+               .name           = "pwm-backlight",
+               .owner          = THIS_MODULE,
 #ifdef CONFIG_PM
-               .pm     = &pwm_backlight_pm_ops,
+               .pm             = &pwm_backlight_pm_ops,
 #endif
+               .of_match_table = of_match_ptr(pwm_backlight_of_match),
        },
        .probe          = pwm_backlight_probe,
        .remove         = pwm_backlight_remove,
index 0d54e607e82d1bd3f86196944d425a8dee40fdb2..49342e1d20beaba317d948219bcea9073499c662 100644 (file)
@@ -92,14 +92,14 @@ static int __devinit tosa_bl_probe(struct i2c_client *client,
 
        data->comadj = sharpsl_param.comadj == -1 ? COMADJ_DEFAULT : sharpsl_param.comadj;
 
-       ret = gpio_request(TOSA_GPIO_BL_C20MA, "backlight");
+       ret = devm_gpio_request(&client->dev, TOSA_GPIO_BL_C20MA, "backlight");
        if (ret) {
                dev_dbg(&data->bl->dev, "Unable to request gpio!\n");
                return ret;
        }
        ret = gpio_direction_output(TOSA_GPIO_BL_C20MA, 0);
        if (ret)
-               goto err_gpio_dir;
+               return ret;
 
        i2c_set_clientdata(client, data);
        data->i2c = client;
@@ -123,8 +123,6 @@ static int __devinit tosa_bl_probe(struct i2c_client *client,
 
 err_reg:
        data->bl = NULL;
-err_gpio_dir:
-       gpio_free(TOSA_GPIO_BL_C20MA);
        return ret;
 }
 
@@ -135,8 +133,6 @@ static int __devexit tosa_bl_remove(struct i2c_client *client)
        backlight_device_unregister(data->bl);
        data->bl = NULL;
 
-       gpio_free(TOSA_GPIO_BL_C20MA);
-
        return 0;
 }
 
index 47823b8efff060b77f1ef4db5bf19554b08e73c7..33047a66cc242baf29a20c7bc0f3ced47682350f 100644 (file)
@@ -193,7 +193,7 @@ static int __devinit tosa_lcd_probe(struct spi_device *spi)
        data->spi = spi;
        dev_set_drvdata(&spi->dev, data);
 
-       ret = gpio_request(TOSA_GPIO_TG_ON, "tg #pwr");
+       ret = devm_gpio_request(&spi->dev, TOSA_GPIO_TG_ON, "tg #pwr");
        if (ret < 0)
                goto err_gpio_tg;
 
@@ -201,7 +201,7 @@ static int __devinit tosa_lcd_probe(struct spi_device *spi)
 
        ret = gpio_direction_output(TOSA_GPIO_TG_ON, 0);
        if (ret < 0)
-               goto err_gpio_dir;
+               goto err_gpio_tg;
 
        mdelay(60);
        tosa_lcd_tg_init(data);
@@ -221,8 +221,6 @@ static int __devinit tosa_lcd_probe(struct spi_device *spi)
 
 err_register:
        tosa_lcd_tg_off(data);
-err_gpio_dir:
-       gpio_free(TOSA_GPIO_TG_ON);
 err_gpio_tg:
        dev_set_drvdata(&spi->dev, NULL);
        return ret;
@@ -239,7 +237,6 @@ static int __devexit tosa_lcd_remove(struct spi_device *spi)
 
        tosa_lcd_tg_off(data);
 
-       gpio_free(TOSA_GPIO_TG_ON);
        dev_set_drvdata(&spi->dev, NULL);
 
        return 0;
index 6e0be43ef6ef8eef90c57a4560bf671c9d756b7a..a32246b8359e50d99e658040b0e12a0bd8f4c5a1 100644 (file)
 #include <linux/slab.h>
 #include "affs.h"
 
-/* This is, of course, shamelessly stolen from fs/minix */
-
-static const int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
-
-static u32
-affs_count_free_bits(u32 blocksize, const void *data)
-{
-       const u32 *map;
-       u32 free;
-       u32 tmp;
-
-       map = data;
-       free = 0;
-       for (blocksize /= 4; blocksize > 0; blocksize--) {
-               tmp = *map++;
-               while (tmp) {
-                       free += nibblemap[tmp & 0xf];
-                       tmp >>= 4;
-               }
-       }
-
-       return free;
-}
-
 u32
 affs_count_free_blocks(struct super_block *sb)
 {
@@ -317,7 +293,7 @@ int affs_init_bitmap(struct super_block *sb, int *flags)
                        goto out;
                }
                pr_debug("AFFS: read bitmap block %d: %d\n", blk, bm->bm_key);
-               bm->bm_free = affs_count_free_bits(sb->s_blocksize - 4, bh->b_data + 4);
+               bm->bm_free = memweight(bh->b_data + 4, sb->s_blocksize - 4);
 
                /* Don't try read the extension if this is the last block,
                 * but we also need the right bm pointer below
@@ -367,7 +343,7 @@ int affs_init_bitmap(struct super_block *sb, int *flags)
 
        /* recalculate bitmap count for last block */
        bm--;
-       bm->bm_free = affs_count_free_bits(sb->s_blocksize - 4, bh->b_data + 4);
+       bm->bm_free = memweight(bh->b_data + 4, sb->s_blocksize - 4);
 
 out:
        affs_brelse(bh);
index adb1cd7ceb9b954af34457efc2d119fb422c6f4f..4bab807227ad938c87039ea2aa1ef8f94fe46146 100644 (file)
@@ -3342,10 +3342,22 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 /* super.c */
 int btrfs_parse_options(struct btrfs_root *root, char *options);
 int btrfs_sync_fs(struct super_block *sb, int wait);
+
+#ifdef CONFIG_PRINTK
+__printf(2, 3)
 void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...);
+#else
+static inline __printf(2, 3)
+void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...)
+{
+}
+#endif
+
+__printf(5, 6)
 void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
                     unsigned int line, int errno, const char *fmt, ...);
 
+
 void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root, const char *function,
                               unsigned int line, int errno);
@@ -3386,6 +3398,7 @@ do {                                                              \
                          (errno), fmt, ##args);                \
 } while (0)
 
+__printf(5, 6)
 void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
                   unsigned int line, int errno, const char *fmt, ...);
 
index 502b20c56e848f4df3ede188a408d535de5b4173..fadeba6a5db964c61ab7d795feb18f31347671c2 100644 (file)
@@ -1114,7 +1114,7 @@ void clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                                spin_unlock(&root->fs_info->delalloc_lock);
                                btrfs_panic(root->fs_info, -EOVERFLOW,
                                          "Can't clear %lu bytes from "
-                                         " dirty_mdatadata_bytes (%lu)",
+                                         " dirty_mdatadata_bytes (%llu)",
                                          buf->len,
                                          root->fs_info->dirty_metadata_bytes);
                        }
index c5dbd91496790a3279b8044552f6664666b68a52..4da08652004d5dc2803dba510c0f9b015607b4a1 100644 (file)
@@ -1241,7 +1241,7 @@ static int __must_check __add_reloc_root(struct btrfs_root *root)
        if (rb_node) {
                btrfs_panic(root->fs_info, -EEXIST, "Duplicate root found "
                            "for start=%llu while inserting into relocation "
-                           "tree\n");
+                           "tree\n", node->bytenr);
                kfree(node);
                return -EEXIST;
        }
index fa61ef59cd61aadf7582ce8f73cdff298331b47f..8c6e61d6eed5b754945930fbaaaaf21d6f98d028 100644 (file)
@@ -125,6 +125,7 @@ static void btrfs_handle_error(struct btrfs_fs_info *fs_info)
        }
 }
 
+#ifdef CONFIG_PRINTK
 /*
  * __btrfs_std_error decodes expected errors from the caller and
  * invokes the approciate error response.
@@ -167,7 +168,7 @@ void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
        va_end(args);
 }
 
-const char *logtypes[] = {
+static const char * const logtypes[] = {
        "emergency",
        "alert",
        "critical",
@@ -185,22 +186,50 @@ void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...)
        struct va_format vaf;
        va_list args;
        const char *type = logtypes[4];
+       int kern_level;
 
        va_start(args, fmt);
 
-       if (fmt[0] == '<' && isdigit(fmt[1]) && fmt[2] == '>') {
-               memcpy(lvl, fmt, 3);
-               lvl[3] = '\0';
-               fmt += 3;
-               type = logtypes[fmt[1] - '0'];
+       kern_level = printk_get_level(fmt);
+       if (kern_level) {
+               size_t size = printk_skip_level(fmt) - fmt;
+               memcpy(lvl, fmt,  size);
+               lvl[size] = '\0';
+               fmt += size;
+               type = logtypes[kern_level - '0'];
        } else
                *lvl = '\0';
 
        vaf.fmt = fmt;
        vaf.va = &args;
+
        printk("%sBTRFS %s (device %s): %pV", lvl, type, sb->s_id, &vaf);
+
+       va_end(args);
 }
 
+#else
+
+void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
+                      unsigned int line, int errno, const char *fmt, ...)
+{
+       struct super_block *sb = fs_info->sb;
+
+       /*
+        * Special case: if the error is EROFS, and we're already
+        * under MS_RDONLY, then it is safe here.
+        */
+       if (errno == -EROFS && (sb->s_flags & MS_RDONLY))
+               return;
+
+       /* Don't go through full error handling during mount */
+       if (sb->s_flags & MS_BORN) {
+               save_error_info(fs_info);
+               btrfs_handle_error(fs_info);
+       }
+}
+#endif
+
 /*
  * We only mark the transaction aborted and then set the file system read-only.
  * This will prevent new transactions from starting or trying to join this
index c0353dfac51f819d3e8cb69644fd50a98fa04224..c994691d94454254cfcb75e796b6fcaaeab8e2b1 100644 (file)
@@ -919,7 +919,7 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
         * own time */
        path.mnt = cache->mnt;
        path.dentry = object->backer;
-       file = dentry_open(&path, O_RDWR, cache->cache_cred);
+       file = dentry_open(&path, O_RDWR | O_LARGEFILE, cache->cache_cred);
        if (IS_ERR(file)) {
                ret = PTR_ERR(file);
        } else {
index 00894ff9246c2175b60177bab59b70456733ff01..f391f1e754145141235bf89d28da37d5c6aba005 100644 (file)
@@ -51,8 +51,7 @@ int ceph_init_dentry(struct dentry *dentry)
                goto out_unlock;
        }
 
-       if (dentry->d_parent == NULL ||   /* nfs fh_to_dentry */
-           ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
+       if (ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
                d_set_d_op(dentry, &ceph_dentry_ops);
        else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR)
                d_set_d_op(dentry, &ceph_snapdir_dentry_ops);
@@ -79,7 +78,7 @@ struct inode *ceph_get_dentry_parent_inode(struct dentry *dentry)
                return NULL;
 
        spin_lock(&dentry->d_lock);
-       if (dentry->d_parent) {
+       if (!IS_ROOT(dentry)) {
                inode = dentry->d_parent->d_inode;
                ihold(inode);
        }
@@ -1154,7 +1153,7 @@ static void ceph_d_prune(struct dentry *dentry)
        dout("ceph_d_prune %p\n", dentry);
 
        /* do we have a valid parent? */
-       if (!dentry->d_parent || IS_ROOT(dentry))
+       if (IS_ROOT(dentry))
                return;
 
        /* if we are not hashed, we don't affect D_COMPLETE */
index 200bc87eceb1cc417a1caa1a73e264cde79dda78..a5a735422aa7a43e5e2d6022c81402f739a1b660 100644 (file)
@@ -10,6 +10,7 @@
 #include "super.h"
 #include "mds_client.h"
 
+#include <linux/ceph/ceph_features.h>
 #include <linux/ceph/messenger.h>
 #include <linux/ceph/decode.h>
 #include <linux/ceph/pagelist.h>
@@ -394,11 +395,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
        s->s_seq = 0;
        mutex_init(&s->s_mutex);
 
-       ceph_con_init(mdsc->fsc->client->msgr, &s->s_con);
-       s->s_con.private = s;
-       s->s_con.ops = &mds_con_ops;
-       s->s_con.peer_name.type = CEPH_ENTITY_TYPE_MDS;
-       s->s_con.peer_name.num = cpu_to_le64(mds);
+       ceph_con_init(&s->s_con, s, &mds_con_ops, &mdsc->fsc->client->msgr);
 
        spin_lock_init(&s->s_gen_ttl_lock);
        s->s_cap_gen = 0;
@@ -440,7 +437,8 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
        mdsc->sessions[mds] = s;
        atomic_inc(&s->s_ref);  /* one ref to sessions[], one to caller */
 
-       ceph_con_open(&s->s_con, ceph_mdsmap_get_addr(mdsc->mdsmap, mds));
+       ceph_con_open(&s->s_con, CEPH_ENTITY_TYPE_MDS, mds,
+                     ceph_mdsmap_get_addr(mdsc->mdsmap, mds));
 
        return s;
 
@@ -1472,11 +1470,6 @@ retry:
                else
                        len += 1 + temp->d_name.len;
                temp = temp->d_parent;
-               if (temp == NULL) {
-                       rcu_read_unlock();
-                       pr_err("build_path corrupt dentry %p\n", dentry);
-                       return ERR_PTR(-EINVAL);
-               }
        }
        rcu_read_unlock();
        if (len)
@@ -1513,12 +1506,6 @@ retry:
                if (pos)
                        path[--pos] = '/';
                temp = temp->d_parent;
-               if (temp == NULL) {
-                       rcu_read_unlock();
-                       pr_err("build_path corrupt dentry\n");
-                       kfree(path);
-                       return ERR_PTR(-EINVAL);
-               }
        }
        rcu_read_unlock();
        if (pos != 0 || read_seqretry(&rename_lock, seq)) {
@@ -2531,7 +2518,9 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
        session->s_state = CEPH_MDS_SESSION_RECONNECTING;
        session->s_seq = 0;
 
+       ceph_con_close(&session->s_con);
        ceph_con_open(&session->s_con,
+                     CEPH_ENTITY_TYPE_MDS, mds,
                      ceph_mdsmap_get_addr(mdsc->mdsmap, mds));
 
        /* replay unsafe requests */
index e5206fc765620f3b550c2457e1f271cb9d81c8c8..cbb2f54a301971cea4e7ed02b029c3e7979cbc18 100644 (file)
@@ -296,8 +296,7 @@ static int build_snap_context(struct ceph_snap_realm *realm)
        struct ceph_snap_realm *parent = realm->parent;
        struct ceph_snap_context *snapc;
        int err = 0;
-       int i;
-       int num = realm->num_prior_parent_snaps + realm->num_snaps;
+       u32 num = realm->num_prior_parent_snaps + realm->num_snaps;
 
        /*
         * build parent context, if it hasn't been built.
@@ -321,11 +320,11 @@ static int build_snap_context(struct ceph_snap_realm *realm)
            realm->cached_context->seq == realm->seq &&
            (!parent ||
             realm->cached_context->seq >= parent->cached_context->seq)) {
-               dout("build_snap_context %llx %p: %p seq %lld (%d snaps)"
+               dout("build_snap_context %llx %p: %p seq %lld (%u snaps)"
                     " (unchanged)\n",
                     realm->ino, realm, realm->cached_context,
                     realm->cached_context->seq,
-                    realm->cached_context->num_snaps);
+                    (unsigned int) realm->cached_context->num_snaps);
                return 0;
        }
 
@@ -342,6 +341,8 @@ static int build_snap_context(struct ceph_snap_realm *realm)
        num = 0;
        snapc->seq = realm->seq;
        if (parent) {
+               u32 i;
+
                /* include any of parent's snaps occurring _after_ my
                   parent became my parent */
                for (i = 0; i < parent->cached_context->num_snaps; i++)
@@ -361,8 +362,9 @@ static int build_snap_context(struct ceph_snap_realm *realm)
 
        sort(snapc->snaps, num, sizeof(u64), cmpu64_rev, NULL);
        snapc->num_snaps = num;
-       dout("build_snap_context %llx %p: %p seq %lld (%d snaps)\n",
-            realm->ino, realm, snapc, snapc->seq, snapc->num_snaps);
+       dout("build_snap_context %llx %p: %p seq %lld (%u snaps)\n",
+            realm->ino, realm, snapc, snapc->seq,
+            (unsigned int) snapc->num_snaps);
 
        if (realm->cached_context)
                ceph_put_snap_context(realm->cached_context);
@@ -402,9 +404,9 @@ static void rebuild_snap_realms(struct ceph_snap_realm *realm)
  * helper to allocate and decode an array of snapids.  free prior
  * instance, if any.
  */
-static int dup_array(u64 **dst, __le64 *src, int num)
+static int dup_array(u64 **dst, __le64 *src, u32 num)
 {
-       int i;
+       u32 i;
 
        kfree(*dst);
        if (num) {
index 7076109f014dae80a85c789c3022b6465f9b70c0..b982239f38f91dfab38fcc093e600d5b11e5c632 100644 (file)
@@ -18,6 +18,7 @@
 #include "super.h"
 #include "mds_client.h"
 
+#include <linux/ceph/ceph_features.h>
 #include <linux/ceph/decode.h>
 #include <linux/ceph/mon_client.h>
 #include <linux/ceph/auth.h>
index f4d5522cb619eba5f5a27842ea52277e9b3d5563..ebc95cc652be17bed2717d8c83f64eb39f69aed0 100644 (file)
@@ -612,9 +612,9 @@ struct ceph_snap_realm {
        u64 parent_since;   /* snapid when our current parent became so */
 
        u64 *prior_parent_snaps;      /* snaps inherited from any parents we */
-       int num_prior_parent_snaps;   /*  had prior to parent_since */
+       u32 num_prior_parent_snaps;   /*  had prior to parent_since */
        u64 *snaps;                   /* snaps specific to this realm */
-       int num_snaps;
+       u32 num_snaps;
 
        struct ceph_snap_realm *parent;
        struct list_head children;       /* list of child realms */
index 785cb3057c95a436c344da2d76ee24b86cb7954b..2c2ae5be99027af909d30a65cb73706a7c0d193a 100644 (file)
@@ -457,6 +457,7 @@ start:
                        for (i = 0; i < numattr; i++)
                                kfree(xattrs[i]);
                        kfree(xattrs);
+                       xattrs = NULL;
                        goto start;
                }
                err = -EIO;
index e95aeeddd25c4038ad1656621bd9af56b7a0868e..3684353ebd5f612a82f7e8981fb2ce80441e8565 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -2002,17 +2002,17 @@ static void coredump_finish(struct mm_struct *mm)
 void set_dumpable(struct mm_struct *mm, int value)
 {
        switch (value) {
-       case 0:
+       case SUID_DUMPABLE_DISABLED:
                clear_bit(MMF_DUMPABLE, &mm->flags);
                smp_wmb();
                clear_bit(MMF_DUMP_SECURELY, &mm->flags);
                break;
-       case 1:
+       case SUID_DUMPABLE_ENABLED:
                set_bit(MMF_DUMPABLE, &mm->flags);
                smp_wmb();
                clear_bit(MMF_DUMP_SECURELY, &mm->flags);
                break;
-       case 2:
+       case SUID_DUMPABLE_SAFE:
                set_bit(MMF_DUMP_SECURELY, &mm->flags);
                smp_wmb();
                set_bit(MMF_DUMPABLE, &mm->flags);
@@ -2025,7 +2025,7 @@ static int __get_dumpable(unsigned long mm_flags)
        int ret;
 
        ret = mm_flags & MMF_DUMPABLE_MASK;
-       return (ret >= 2) ? 2 : ret;
+       return (ret > SUID_DUMPABLE_ENABLED) ? SUID_DUMPABLE_SAFE : ret;
 }
 
 int get_dumpable(struct mm_struct *mm)
@@ -2111,6 +2111,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        int retval = 0;
        int flag = 0;
        int ispipe;
+       bool need_nonrelative = false;
        static atomic_t core_dump_count = ATOMIC_INIT(0);
        struct coredump_params cprm = {
                .signr = signr,
@@ -2136,14 +2137,16 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        if (!cred)
                goto fail;
        /*
-        *      We cannot trust fsuid as being the "true" uid of the
-        *      process nor do we know its entire history. We only know it
-        *      was tainted so we dump it as root in mode 2.
+        * We cannot trust fsuid as being the "true" uid of the process
+        * nor do we know its entire history. We only know it was tainted
+        * so we dump it as root in mode 2, and only into a controlled
+        * environment (pipe handler or fully qualified path).
         */
-       if (__get_dumpable(cprm.mm_flags) == 2) {
+       if (__get_dumpable(cprm.mm_flags) == SUID_DUMPABLE_SAFE) {
                /* Setuid core dump mode */
                flag = O_EXCL;          /* Stop rewrite attacks */
                cred->fsuid = GLOBAL_ROOT_UID;  /* Dump root private */
+               need_nonrelative = true;
        }
 
        retval = coredump_wait(exit_code, &core_state);
@@ -2171,15 +2174,16 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                }
 
                if (cprm.limit == 1) {
-                       /*
+                       /* See umh_pipe_setup() which sets RLIMIT_CORE = 1.
+                        *
                         * Normally core limits are irrelevant to pipes, since
                         * we're not writing to the file system, but we use
-                        * cprm.limit of 1 here as a speacial value. Any
-                        * non-1 limit gets set to RLIM_INFINITY below, but
-                        * a limit of 0 skips the dump.  This is a consistent
-                        * way to catch recursive crashes.  We can still crash
-                        * if the core_pattern binary sets RLIM_CORE =  !1
-                        * but it runs as root, and can do lots of stupid things
+                        * cprm.limit of 1 here as a speacial value, this is a
+                        * consistent way to catch recursive crashes.
+                        * We can still crash if the core_pattern binary sets
+                        * RLIM_CORE = !1, but it runs as root, and can do
+                        * lots of stupid things.
+                        *
                         * Note that we use task_tgid_vnr here to grab the pid
                         * of the process group leader.  That way we get the
                         * right pid if a thread in a multi-threaded
@@ -2223,6 +2227,14 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                if (cprm.limit < binfmt->min_coredump)
                        goto fail_unlock;
 
+               if (need_nonrelative && cn.corename[0] != '/') {
+                       printk(KERN_WARNING "Pid %d(%s) can only dump core "\
+                               "to fully qualified path!\n",
+                               task_tgid_vnr(current), current->comm);
+                       printk(KERN_WARNING "Skipping core dump\n");
+                       goto fail_unlock;
+               }
+
                cprm.file = filp_open(cn.corename,
                                 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
                                 0600);
index 1c361399886249070044987d8c2a93033202f445..376aa77f3ca7f330f2c6346053f2d1e49a990ebf 100644 (file)
@@ -1444,19 +1444,9 @@ ext2_fsblk_t ext2_new_block(struct inode *inode, unsigned long goal, int *errp)
 
 #ifdef EXT2FS_DEBUG
 
-static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
-
-unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars)
+unsigned long ext2_count_free(struct buffer_head *map, unsigned int numchars)
 {
-       unsigned int i;
-       unsigned long sum = 0;
-
-       if (!map)
-               return (0);
-       for (i = 0; i < numchars; i++)
-               sum += nibblemap[map->b_data[i] & 0xf] +
-                       nibblemap[(map->b_data[i] >> 4) & 0xf];
-       return (sum);
+       return numchars * BITS_PER_BYTE - memweight(map->b_data, numchars);
 }
 
 #endif  /*  EXT2FS_DEBUG  */
index c13eb7b91a1100fa108a33275905d31ae35bfb02..8f370e012e613e73016856a9cab3c6257666a1a1 100644 (file)
@@ -644,6 +644,7 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
        }
        brelse(bitmap_bh);
        printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
+               (unsigned long)
                percpu_counter_read(&EXT2_SB(sb)->s_freeinodes_counter),
                desc_count, bitmap_count);
        return desc_count;
index 25cd6089211657839f8f94a68bc075313cd92e2f..90d901f0486b49f01fbfea197b5c0b9f072e280b 100644 (file)
@@ -1813,7 +1813,7 @@ ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb)
        brelse(bitmap_bh);
        printk("ext3_count_free_blocks: stored = "E3FSBLK
                ", computed = "E3FSBLK", "E3FSBLK"\n",
-              le32_to_cpu(es->s_free_blocks_count),
+              (ext3_fsblk_t)le32_to_cpu(es->s_free_blocks_count),
                desc_count, bitmap_count);
        return bitmap_count;
 #else
index 909d13e265603dd24e3e1c2d143e87f7beda4202..ef9c643e8e9d5ff75703227ec9f81f0684340246 100644 (file)
 
 #ifdef EXT3FS_DEBUG
 
-static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
-
 unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars)
 {
-       unsigned int i;
-       unsigned long sum = 0;
-
-       if (!map)
-               return (0);
-       for (i = 0; i < numchars; i++)
-               sum += nibblemap[map->b_data[i] & 0xf] +
-                       nibblemap[(map->b_data[i] >> 4) & 0xf];
-       return (sum);
+       return numchars * BITS_PER_BYTE - memweight(map->b_data, numchars);
 }
 
 #endif  /*  EXT3FS_DEBUG  */
index a94b9c63ee5c4a32f44916d6ecb628b9a070df04..f8716eab99952401dc473deb6619295b4a830f3b 100644 (file)
 #include <linux/jbd2.h>
 #include "ext4.h"
 
-static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
-
 unsigned int ext4_count_free(char *bitmap, unsigned int numchars)
 {
-       unsigned int i, sum = 0;
-
-       for (i = 0; i < numchars; i++)
-               sum += nibblemap[bitmap[i] & 0xf] +
-                       nibblemap[(bitmap[i] >> 4) & 0xf];
-       return sum;
+       return numchars * BITS_PER_BYTE - memweight(bitmap, numchars);
 }
 
 int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
index 6eaa28c98ad1e9038dd939f2960d31034d8663a3..dc49ed2cbffa66af9407f89886d8d84cf2dc9d0f 100644 (file)
 #define FAT_MAX_UNI_CHARS      ((MSDOS_SLOTS - 1) * 13 + 1)
 #define FAT_MAX_UNI_SIZE       (FAT_MAX_UNI_CHARS * sizeof(wchar_t))
 
+static inline unsigned char fat_tolower(unsigned char c)
+{
+       return ((c >= 'A') && (c <= 'Z')) ? c+32 : c;
+}
+
 static inline loff_t fat_make_i_pos(struct super_block *sb,
                                    struct buffer_head *bh,
                                    struct msdos_dir_entry *de)
@@ -333,6 +338,124 @@ parse_long:
        return 0;
 }
 
+/**
+ * fat_parse_short - Parse MS-DOS (short) directory entry.
+ * @sb:                superblock
+ * @de:                directory entry to parse
+ * @name:      FAT_MAX_SHORT_SIZE array in which to place extracted name
+ * @dot_hidden:        Nonzero == prepend '.' to names with ATTR_HIDDEN
+ *
+ * Returns the number of characters extracted into 'name'.
+ */
+static int fat_parse_short(struct super_block *sb,
+                          const struct msdos_dir_entry *de,
+                          unsigned char *name, int dot_hidden)
+{
+       const struct msdos_sb_info *sbi = MSDOS_SB(sb);
+       int isvfat = sbi->options.isvfat;
+       int nocase = sbi->options.nocase;
+       unsigned short opt_shortname = sbi->options.shortname;
+       struct nls_table *nls_disk = sbi->nls_disk;
+       wchar_t uni_name[14];
+       unsigned char c, work[MSDOS_NAME];
+       unsigned char *ptname = name;
+       int chi, chl, i, j, k;
+       int dotoffset = 0;
+       int name_len = 0, uni_len = 0;
+
+       if (!isvfat && dot_hidden && (de->attr & ATTR_HIDDEN)) {
+               *ptname++ = '.';
+               dotoffset = 1;
+       }
+
+       memcpy(work, de->name, sizeof(work));
+       /* see namei.c, msdos_format_name */
+       if (work[0] == 0x05)
+               work[0] = 0xE5;
+
+       /* Filename */
+       for (i = 0, j = 0; i < 8;) {
+               c = work[i];
+               if (!c)
+                       break;
+               chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
+                                       &uni_name[j++], opt_shortname,
+                                       de->lcase & CASE_LOWER_BASE);
+               if (chl <= 1) {
+                       if (!isvfat)
+                               ptname[i] = nocase ? c : fat_tolower(c);
+                       i++;
+                       if (c != ' ') {
+                               name_len = i;
+                               uni_len  = j;
+                       }
+               } else {
+                       uni_len = j;
+                       if (isvfat)
+                               i += min(chl, 8-i);
+                       else {
+                               for (chi = 0; chi < chl && i < 8; chi++, i++)
+                                       ptname[i] = work[i];
+                       }
+                       if (chl)
+                               name_len = i;
+               }
+       }
+
+       i = name_len;
+       j = uni_len;
+       fat_short2uni(nls_disk, ".", 1, &uni_name[j++]);
+       if (!isvfat)
+               ptname[i] = '.';
+       i++;
+
+       /* Extension */
+       for (k = 8; k < MSDOS_NAME;) {
+               c = work[k];
+               if (!c)
+                       break;
+               chl = fat_shortname2uni(nls_disk, &work[k], MSDOS_NAME - k,
+                                       &uni_name[j++], opt_shortname,
+                                       de->lcase & CASE_LOWER_EXT);
+               if (chl <= 1) {
+                       k++;
+                       if (!isvfat)
+                               ptname[i] = nocase ? c : fat_tolower(c);
+                       i++;
+                       if (c != ' ') {
+                               name_len = i;
+                               uni_len  = j;
+                       }
+               } else {
+                       uni_len = j;
+                       if (isvfat) {
+                               int offset = min(chl, MSDOS_NAME-k);
+                               k += offset;
+                               i += offset;
+                       } else {
+                               for (chi = 0; chi < chl && k < MSDOS_NAME;
+                                    chi++, i++, k++) {
+                                               ptname[i] = work[k];
+                               }
+                       }
+                       if (chl)
+                               name_len = i;
+               }
+       }
+
+       if (name_len > 0) {
+               name_len += dotoffset;
+
+               if (sbi->options.isvfat) {
+                       uni_name[uni_len] = 0x0000;
+                       name_len = fat_uni_to_x8(sb, uni_name, name,
+                                                FAT_MAX_SHORT_SIZE);
+               }
+       }
+
+       return name_len;
+}
+
 /*
  * Return values: negative -> error, 0 -> not found, positive -> found,
  * value is the total amount of slots, including the shortname entry.
@@ -344,15 +467,11 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
        struct buffer_head *bh = NULL;
        struct msdos_dir_entry *de;
-       struct nls_table *nls_disk = sbi->nls_disk;
        unsigned char nr_slots;
-       wchar_t bufuname[14];
        wchar_t *unicode = NULL;
-       unsigned char work[MSDOS_NAME];
        unsigned char bufname[FAT_MAX_SHORT_SIZE];
-       unsigned short opt_shortname = sbi->options.shortname;
        loff_t cpos = 0;
-       int chl, i, j, last_u, err, len;
+       int err, len;
 
        err = -ENOENT;
        while (1) {
@@ -380,47 +499,16 @@ parse_record:
                                goto end_of_dir;
                }
 
-               memcpy(work, de->name, sizeof(de->name));
-               /* see namei.c, msdos_format_name */
-               if (work[0] == 0x05)
-                       work[0] = 0xE5;
-               for (i = 0, j = 0, last_u = 0; i < 8;) {
-                       if (!work[i])
-                               break;
-                       chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
-                                               &bufuname[j++], opt_shortname,
-                                               de->lcase & CASE_LOWER_BASE);
-                       if (chl <= 1) {
-                               if (work[i] != ' ')
-                                       last_u = j;
-                       } else {
-                               last_u = j;
-                       }
-                       i += chl;
-               }
-               j = last_u;
-               fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
-               for (i = 8; i < MSDOS_NAME;) {
-                       if (!work[i])
-                               break;
-                       chl = fat_shortname2uni(nls_disk, &work[i],
-                                               MSDOS_NAME - i,
-                                               &bufuname[j++], opt_shortname,
-                                               de->lcase & CASE_LOWER_EXT);
-                       if (chl <= 1) {
-                               if (work[i] != ' ')
-                                       last_u = j;
-                       } else {
-                               last_u = j;
-                       }
-                       i += chl;
-               }
-               if (!last_u)
+               /* Never prepend '.' to hidden files here.
+                * That is done only for msdos mounts (and only when
+                * 'dotsOK=yes'); if we are executing here, it is in the
+                * context of a vfat mount.
+                */
+               len = fat_parse_short(sb, de, bufname, 0);
+               if (len == 0)
                        continue;
 
                /* Compare shortname */
-               bufuname[last_u] = 0x0000;
-               len = fat_uni_to_x8(sb, bufuname, bufname, sizeof(bufname));
                if (fat_name_match(sbi, name, name_len, bufname, len))
                        goto found;
 
@@ -469,20 +557,15 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
        struct buffer_head *bh;
        struct msdos_dir_entry *de;
-       struct nls_table *nls_disk = sbi->nls_disk;
        unsigned char nr_slots;
-       wchar_t bufuname[14];
        wchar_t *unicode = NULL;
-       unsigned char c, work[MSDOS_NAME];
-       unsigned char bufname[FAT_MAX_SHORT_SIZE], *ptname = bufname;
-       unsigned short opt_shortname = sbi->options.shortname;
+       unsigned char bufname[FAT_MAX_SHORT_SIZE];
        int isvfat = sbi->options.isvfat;
-       int nocase = sbi->options.nocase;
        const char *fill_name = NULL;
        unsigned long inum;
        unsigned long lpos, dummy, *furrfu = &lpos;
        loff_t cpos;
-       int chi, chl, i, i2, j, last, last_u, dotoffset = 0, fill_len = 0;
+       int short_len = 0, fill_len = 0;
        int ret = 0;
 
        lock_super(sb);
@@ -556,74 +639,10 @@ parse_record:
                }
        }
 
-       if (sbi->options.dotsOK) {
-               ptname = bufname;
-               dotoffset = 0;
-               if (de->attr & ATTR_HIDDEN) {
-                       *ptname++ = '.';
-                       dotoffset = 1;
-               }
-       }
-
-       memcpy(work, de->name, sizeof(de->name));
-       /* see namei.c, msdos_format_name */
-       if (work[0] == 0x05)
-               work[0] = 0xE5;
-       for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) {
-               if (!(c = work[i]))
-                       break;
-               chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
-                                       &bufuname[j++], opt_shortname,
-                                       de->lcase & CASE_LOWER_BASE);
-               if (chl <= 1) {
-                       ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
-                       if (c != ' ') {
-                               last = i;
-                               last_u = j;
-                       }
-               } else {
-                       last_u = j;
-                       for (chi = 0; chi < chl && i < 8; chi++) {
-                               ptname[i] = work[i];
-                               i++; last = i;
-                       }
-               }
-       }
-       i = last;
-       j = last_u;
-       fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
-       ptname[i++] = '.';
-       for (i2 = 8; i2 < MSDOS_NAME;) {
-               if (!(c = work[i2]))
-                       break;
-               chl = fat_shortname2uni(nls_disk, &work[i2], MSDOS_NAME - i2,
-                                       &bufuname[j++], opt_shortname,
-                                       de->lcase & CASE_LOWER_EXT);
-               if (chl <= 1) {
-                       i2++;
-                       ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
-                       if (c != ' ') {
-                               last = i;
-                               last_u = j;
-                       }
-               } else {
-                       last_u = j;
-                       for (chi = 0; chi < chl && i2 < MSDOS_NAME; chi++) {
-                               ptname[i++] = work[i2++];
-                               last = i;
-                       }
-               }
-       }
-       if (!last)
+       short_len = fat_parse_short(sb, de, bufname, sbi->options.dotsOK);
+       if (short_len == 0)
                goto record_end;
 
-       i = last + dotoffset;
-       j = last_u;
-
-       if (isvfat) {
-               bufuname[j] = 0x0000;
-               i = fat_uni_to_x8(sb, bufuname, bufname, sizeof(bufname));
-       }
        if (nr_slots) {
                /* hack for fat_ioctl_filldir() */
                struct fat_ioctl_filldir_callback *p = dirent;
@@ -631,12 +650,12 @@ parse_record:
                p->longname = fill_name;
                p->long_len = fill_len;
                p->shortname = bufname;
-               p->short_len = i;
+               p->short_len = short_len;
                fill_name = NULL;
                fill_len = 0;
        } else {
                fill_name = bufname;
-               fill_len = i;
+               fill_len = short_len;
        }
 
 start_filldir:
index fc35c5c69136e805b41ffa6102dc1878d68f7a3f..2deeeb86f331c8ad70d56300f1b5d4d5b155fe7b 100644 (file)
@@ -217,6 +217,21 @@ static inline void fat16_towchar(wchar_t *dst, const __u8 *src, size_t len)
 #endif
 }
 
+static inline int fat_get_start(const struct msdos_sb_info *sbi,
+                               const struct msdos_dir_entry *de)
+{
+       int cluster = le16_to_cpu(de->start);
+       if (sbi->fat_bits == 32)
+               cluster |= (le16_to_cpu(de->starthi) << 16);
+       return cluster;
+}
+
+static inline void fat_set_start(struct msdos_dir_entry *de, int cluster)
+{
+       de->start   = cpu_to_le16(cluster);
+       de->starthi = cpu_to_le16(cluster >> 16);
+}
+
 static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len)
 {
 #ifdef __BIG_ENDIAN
index 0038b32cb36276d537f2ec81a46469bf3ad221b1..05e897fe9866c49fb96fa09459240bf7a550586c 100644 (file)
@@ -369,10 +369,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
                inode->i_op = sbi->dir_ops;
                inode->i_fop = &fat_dir_operations;
 
-               MSDOS_I(inode)->i_start = le16_to_cpu(de->start);
-               if (sbi->fat_bits == 32)
-                       MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16);
-
+               MSDOS_I(inode)->i_start = fat_get_start(sbi, de);
                MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
                error = fat_calc_dir_size(inode);
                if (error < 0)
@@ -385,9 +382,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
                inode->i_mode = fat_make_mode(sbi, de->attr,
                        ((sbi->options.showexec && !is_exec(de->name + 8))
                         ? S_IRUGO|S_IWUGO : S_IRWXUGO));
-               MSDOS_I(inode)->i_start = le16_to_cpu(de->start);
-               if (sbi->fat_bits == 32)
-                       MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16);
+               MSDOS_I(inode)->i_start = fat_get_start(sbi, de);
 
                MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
                inode->i_size = le32_to_cpu(de->size);
@@ -613,8 +608,7 @@ retry:
        else
                raw_entry->size = cpu_to_le32(inode->i_size);
        raw_entry->attr = fat_make_attrs(inode);
-       raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart);
-       raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16);
+       fat_set_start(raw_entry, MSDOS_I(inode)->i_logstart);
        fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time,
                          &raw_entry->date, NULL);
        if (sbi->options.isvfat) {
index 70d993a9380572bac393a45f3dcb9896db404f9e..b0e12bf9f4a1c0fc32dc42facffaf84ff75fe880 100644 (file)
@@ -246,8 +246,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name,
        de.ctime_cs = 0;
        de.time = time;
        de.date = date;
-       de.start = cpu_to_le16(cluster);
-       de.starthi = cpu_to_le16(cluster >> 16);
+       fat_set_start(&de, cluster);
        de.size = 0;
 
        err = fat_add_entries(dir, &de, 1, sinfo);
@@ -530,9 +529,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
                mark_inode_dirty(old_inode);
 
        if (update_dotdot) {
-               int start = MSDOS_I(new_dir)->i_logstart;
-               dotdot_de->start = cpu_to_le16(start);
-               dotdot_de->starthi = cpu_to_le16(start >> 16);
+               fat_set_start(dotdot_de, MSDOS_I(new_dir)->i_logstart);
                mark_buffer_dirty_inode(dotdot_bh, old_inode);
                if (IS_DIRSYNC(new_dir)) {
                        err = sync_dirty_buffer(dotdot_bh);
@@ -572,9 +569,7 @@ error_dotdot:
        corrupt = 1;
 
        if (update_dotdot) {
-               int start = MSDOS_I(old_dir)->i_logstart;
-               dotdot_de->start = cpu_to_le16(start);
-               dotdot_de->starthi = cpu_to_le16(start >> 16);
+               fat_set_start(dotdot_de, MSDOS_I(old_dir)->i_logstart);
                mark_buffer_dirty_inode(dotdot_bh, old_inode);
                corrupt |= sync_dirty_buffer(dotdot_bh);
        }
index 6cc480652433b66a52c42cbcd3bde3f19e348f30..6a6d8c0715a1c16daf2b1ac53e8d461eb2253810 100644 (file)
@@ -651,8 +651,7 @@ shortname:
        de->time = de->ctime = time;
        de->date = de->cdate = de->adate = date;
        de->ctime_cs = time_cs;
-       de->start = cpu_to_le16(cluster);
-       de->starthi = cpu_to_le16(cluster >> 16);
+       fat_set_start(de, cluster);
        de->size = 0;
 out_free:
        __putname(uname);
@@ -965,9 +964,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
                mark_inode_dirty(old_inode);
 
        if (update_dotdot) {
-               int start = MSDOS_I(new_dir)->i_logstart;
-               dotdot_de->start = cpu_to_le16(start);
-               dotdot_de->starthi = cpu_to_le16(start >> 16);
+               fat_set_start(dotdot_de, MSDOS_I(new_dir)->i_logstart);
                mark_buffer_dirty_inode(dotdot_bh, old_inode);
                if (IS_DIRSYNC(new_dir)) {
                        err = sync_dirty_buffer(dotdot_bh);
@@ -1009,9 +1006,7 @@ error_dotdot:
        corrupt = 1;
 
        if (update_dotdot) {
-               int start = MSDOS_I(old_dir)->i_logstart;
-               dotdot_de->start = cpu_to_le16(start);
-               dotdot_de->starthi = cpu_to_le16(start >> 16);
+               fat_set_start(dotdot_de, MSDOS_I(old_dir)->i_logstart);
                mark_buffer_dirty_inode(dotdot_bh, old_inode);
                corrupt |= sync_dirty_buffer(dotdot_bh);
        }
index 81b70e665bf000412f73aa300890a53823db36f0..887b5ba8c9b56be800d4d3f7a799fc21f1c7892c 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/signal.h>
 #include <linux/rcupdate.h>
 #include <linux/pid_namespace.h>
+#include <linux/user_namespace.h>
 
 #include <asm/poll.h>
 #include <asm/siginfo.h>
@@ -340,6 +341,31 @@ static int f_getown_ex(struct file *filp, unsigned long arg)
        return ret;
 }
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+static int f_getowner_uids(struct file *filp, unsigned long arg)
+{
+       struct user_namespace *user_ns = current_user_ns();
+       uid_t * __user dst = (void * __user)arg;
+       uid_t src[2];
+       int err;
+
+       read_lock(&filp->f_owner.lock);
+       src[0] = from_kuid(user_ns, filp->f_owner.uid);
+       src[1] = from_kuid(user_ns, filp->f_owner.euid);
+       read_unlock(&filp->f_owner.lock);
+
+       err  = put_user(src[0], &dst[0]);
+       err |= put_user(src[1], &dst[1]);
+
+       return err;
+}
+#else
+static int f_getowner_uids(struct file *filp, unsigned long arg)
+{
+       return -EINVAL;
+}
+#endif
+
 static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
                struct file *filp)
 {
@@ -396,6 +422,9 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
        case F_SETOWN_EX:
                err = f_setown_ex(filp, arg);
                break;
+       case F_GETOWNER_UIDS:
+               err = f_getowner_uids(filp, arg);
+               break;
        case F_GETSIG:
                err = filp->f_owner.signum;
                break;
index 8f660dd6137a1105ba648e1a1412ffc5900c1233..50d0b78130a1331204e7dc3b0909f57acacd65e1 100644 (file)
@@ -628,8 +628,8 @@ static long writeback_sb_inodes(struct super_block *sb,
                }
 
                /*
-                * Don't bother with new inodes or inodes beeing freed, first
-                * kind does not need peridic writeout yet, and for the latter
+                * Don't bother with new inodes or inodes being freed, first
+                * kind does not need periodic writeout yet, and for the latter
                 * kind writeout is handled by the freer.
                 */
                spin_lock(&inode->i_lock);
index 47333209801378c5cbd5baef0c948c1767a4fa2a..fdafb2d71654740776bd1b77931b955da350ecad 100644 (file)
@@ -365,7 +365,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        u64 last_fs_block, last_fs_page;
        int err;
 
-       err = -EINVAL;
+       err = -ENOMEM;
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
                goto out;
index 183cc1f0af1cf6be225053e2032f47a063be25d3..6d1ee7204c889b347897b50590b620a658920020 100644 (file)
@@ -4,8 +4,10 @@
 
 #include <linux/module.h>
 #include <linux/lockd/bind.h>
+#include <net/net_namespace.h>
+
+#include "netns.h"
 
-static LIST_HEAD(grace_list);
 static DEFINE_SPINLOCK(grace_lock);
 
 /**
@@ -19,10 +21,12 @@ static DEFINE_SPINLOCK(grace_lock);
  *
  * This function is called to start a grace period.
  */
-void locks_start_grace(struct lock_manager *lm)
+void locks_start_grace(struct net *net, struct lock_manager *lm)
 {
+       struct lockd_net *ln = net_generic(net, lockd_net_id);
+
        spin_lock(&grace_lock);
-       list_add(&lm->list, &grace_list);
+       list_add(&lm->list, &ln->grace_list);
        spin_unlock(&grace_lock);
 }
 EXPORT_SYMBOL_GPL(locks_start_grace);
@@ -52,8 +56,10 @@ EXPORT_SYMBOL_GPL(locks_end_grace);
  * to answer ordinary lock requests, and when they should accept only
  * lock reclaims.
  */
-int locks_in_grace(void)
+int locks_in_grace(struct net *net)
 {
-       return !list_empty(&grace_list);
+       struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+       return !list_empty(&ln->grace_list);
 }
 EXPORT_SYMBOL_GPL(locks_in_grace);
index eb75ca7c2d6edd4782ad9f025b6115c78b3c9307..f9b22e58f78f053a05fffa2ec11feaa32bc2518a 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <net/ipv6.h>
 
+#include "netns.h"
+
 #define NLMDBG_FACILITY                NLMDBG_HOSTCACHE
 #define NLM_HOST_NRHASH                32
 #define NLM_HOST_REBIND                (60 * HZ)
@@ -41,11 +43,10 @@ static struct hlist_head    nlm_client_hosts[NLM_HOST_NRHASH];
                hlist_for_each_entry_safe((host), (pos), (next), \
                                                (chain), h_hash)
 
-static unsigned long           next_gc;
 static unsigned long           nrhosts;
 static DEFINE_MUTEX(nlm_host_mutex);
 
-static void                    nlm_gc_hosts(void);
+static void                    nlm_gc_hosts(struct net *net);
 
 struct nlm_lookup_host_info {
        const int               server;         /* search for server|client */
@@ -172,6 +173,7 @@ out:
 static void nlm_destroy_host_locked(struct nlm_host *host)
 {
        struct rpc_clnt *clnt;
+       struct lockd_net *ln = net_generic(host->net, lockd_net_id);
 
        dprintk("lockd: destroy host %s\n", host->h_name);
 
@@ -188,6 +190,7 @@ static void nlm_destroy_host_locked(struct nlm_host *host)
                rpc_shutdown_client(clnt);
        kfree(host);
 
+       ln->nrhosts--;
        nrhosts--;
 }
 
@@ -228,6 +231,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
        struct hlist_node *pos;
        struct nlm_host *host;
        struct nsm_handle *nsm = NULL;
+       struct lockd_net *ln = net_generic(net, lockd_net_id);
 
        dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
                        (hostname ? hostname : "<none>"), version,
@@ -262,6 +266,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
                goto out;
 
        hlist_add_head(&host->h_hash, chain);
+       ln->nrhosts++;
        nrhosts++;
 
        dprintk("lockd: %s created host %s (%s)\n", __func__,
@@ -326,7 +331,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
        struct nsm_handle *nsm = NULL;
        struct sockaddr *src_sap = svc_daddr(rqstp);
        size_t src_len = rqstp->rq_daddrlen;
-       struct net *net = rqstp->rq_xprt->xpt_net;
+       struct net *net = SVC_NET(rqstp);
        struct nlm_lookup_host_info ni = {
                .server         = 1,
                .sap            = svc_addr(rqstp),
@@ -337,6 +342,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
                .hostname_len   = hostname_len,
                .net            = net,
        };
+       struct lockd_net *ln = net_generic(net, lockd_net_id);
 
        dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
                        (int)hostname_len, hostname, rqstp->rq_vers,
@@ -344,8 +350,8 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
 
        mutex_lock(&nlm_host_mutex);
 
-       if (time_after_eq(jiffies, next_gc))
-               nlm_gc_hosts();
+       if (time_after_eq(jiffies, ln->next_gc))
+               nlm_gc_hosts(net);
 
        chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
        hlist_for_each_entry(host, pos, chain, h_hash) {
@@ -382,6 +388,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
        memcpy(nlm_srcaddr(host), src_sap, src_len);
        host->h_srcaddrlen = src_len;
        hlist_add_head(&host->h_hash, chain);
+       ln->nrhosts++;
        nrhosts++;
 
        dprintk("lockd: %s created host %s (%s)\n",
@@ -565,6 +572,35 @@ void nlm_host_rebooted(const struct nlm_reboot *info)
        nsm_release(nsm);
 }
 
+static void nlm_complain_hosts(struct net *net)
+{
+       struct hlist_head *chain;
+       struct hlist_node *pos;
+       struct nlm_host *host;
+
+       if (net) {
+               struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+               if (ln->nrhosts == 0)
+                       return;
+               printk(KERN_WARNING "lockd: couldn't shutdown host module for net %p!\n", net);
+               dprintk("lockd: %lu hosts left in net %p:\n", ln->nrhosts, net);
+       } else {
+               if (nrhosts == 0)
+                       return;
+               printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
+               dprintk("lockd: %lu hosts left:\n", nrhosts);
+       }
+
+       for_each_host(host, pos, chain, nlm_server_hosts) {
+               if (net && host->net != net)
+                       continue;
+               dprintk("       %s (cnt %d use %d exp %ld net %p)\n",
+                       host->h_name, atomic_read(&host->h_count),
+                       host->h_inuse, host->h_expires, host->net);
+       }
+}
+
 void
 nlm_shutdown_hosts_net(struct net *net)
 {
@@ -572,11 +608,10 @@ nlm_shutdown_hosts_net(struct net *net)
        struct hlist_node *pos;
        struct nlm_host *host;
 
-       dprintk("lockd: shutting down host module\n");
        mutex_lock(&nlm_host_mutex);
 
        /* First, make all hosts eligible for gc */
-       dprintk("lockd: nuking all hosts...\n");
+       dprintk("lockd: nuking all hosts in net %p...\n", net);
        for_each_host(host, pos, chain, nlm_server_hosts) {
                if (net && host->net != net)
                        continue;
@@ -588,8 +623,10 @@ nlm_shutdown_hosts_net(struct net *net)
        }
 
        /* Then, perform a garbage collection pass */
-       nlm_gc_hosts();
+       nlm_gc_hosts(net);
        mutex_unlock(&nlm_host_mutex);
+
+       nlm_complain_hosts(net);
 }
 
 /*
@@ -599,22 +636,8 @@ nlm_shutdown_hosts_net(struct net *net)
 void
 nlm_shutdown_hosts(void)
 {
-       struct hlist_head *chain;
-       struct hlist_node *pos;
-       struct nlm_host *host;
-
+       dprintk("lockd: shutting down host module\n");
        nlm_shutdown_hosts_net(NULL);
-
-       /* complain if any hosts are left */
-       if (nrhosts != 0) {
-               printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
-               dprintk("lockd: %lu hosts left:\n", nrhosts);
-               for_each_host(host, pos, chain, nlm_server_hosts) {
-                       dprintk("       %s (cnt %d use %d exp %ld net %p)\n",
-                               host->h_name, atomic_read(&host->h_count),
-                               host->h_inuse, host->h_expires, host->net);
-               }
-       }
 }
 
 /*
@@ -623,30 +646,39 @@ nlm_shutdown_hosts(void)
  * mark & sweep for resources held by remote clients.
  */
 static void
-nlm_gc_hosts(void)
+nlm_gc_hosts(struct net *net)
 {
        struct hlist_head *chain;
        struct hlist_node *pos, *next;
        struct nlm_host *host;
 
-       dprintk("lockd: host garbage collection\n");
-       for_each_host(host, pos, chain, nlm_server_hosts)
+       dprintk("lockd: host garbage collection for net %p\n", net);
+       for_each_host(host, pos, chain, nlm_server_hosts) {
+               if (net && host->net != net)
+                       continue;
                host->h_inuse = 0;
+       }
 
        /* Mark all hosts that hold locks, blocks or shares */
-       nlmsvc_mark_resources();
+       nlmsvc_mark_resources(net);
 
        for_each_host_safe(host, pos, next, chain, nlm_server_hosts) {
+               if (net && host->net != net)
+                       continue;
                if (atomic_read(&host->h_count) || host->h_inuse
                 || time_before(jiffies, host->h_expires)) {
                        dprintk("nlm_gc_hosts skipping %s "
-                               "(cnt %d use %d exp %ld)\n",
+                               "(cnt %d use %d exp %ld net %p)\n",
                                host->h_name, atomic_read(&host->h_count),
-                               host->h_inuse, host->h_expires);
+                               host->h_inuse, host->h_expires, host->net);
                        continue;
                }
                nlm_destroy_host_locked(host);
        }
 
-       next_gc = jiffies + NLM_HOST_COLLECT;
+       if (net) {
+               struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+               ln->next_gc = jiffies + NLM_HOST_COLLECT;
+       }
 }
index ce227e0fbc5c192b0ccaaff7cc1640d33379adc1..4eee248ba96e441eb54e460130d3dde2f20d6ca1 100644 (file)
@@ -1,10 +1,17 @@
 #ifndef __LOCKD_NETNS_H__
 #define __LOCKD_NETNS_H__
 
+#include <linux/fs.h>
 #include <net/netns/generic.h>
 
 struct lockd_net {
        unsigned int nlmsvc_users;
+       unsigned long next_gc;
+       unsigned long nrhosts;
+
+       struct delayed_work grace_period_end;
+       struct lock_manager lockd_manager;
+       struct list_head grace_list;
 };
 
 extern int lockd_net_id;
index 80938fda67e0e6fde67999d3556820b87b6acd33..31a63f87b80602346cc78cfead614d35f620c9cd 100644 (file)
@@ -87,32 +87,36 @@ static unsigned long get_lockd_grace_period(void)
                return nlm_timeout * 5 * HZ;
 }
 
-static struct lock_manager lockd_manager = {
-};
-
-static void grace_ender(struct work_struct *not_used)
+static void grace_ender(struct work_struct *grace)
 {
-       locks_end_grace(&lockd_manager);
-}
+       struct delayed_work *dwork = container_of(grace, struct delayed_work,
+                                                 work);
+       struct lockd_net *ln = container_of(dwork, struct lockd_net,
+                                           grace_period_end);
 
-static DECLARE_DELAYED_WORK(grace_period_end, grace_ender);
+       locks_end_grace(&ln->lockd_manager);
+}
 
-static void set_grace_period(void)
+static void set_grace_period(struct net *net)
 {
        unsigned long grace_period = get_lockd_grace_period();
+       struct lockd_net *ln = net_generic(net, lockd_net_id);
 
-       locks_start_grace(&lockd_manager);
-       cancel_delayed_work_sync(&grace_period_end);
-       schedule_delayed_work(&grace_period_end, grace_period);
+       locks_start_grace(net, &ln->lockd_manager);
+       cancel_delayed_work_sync(&ln->grace_period_end);
+       schedule_delayed_work(&ln->grace_period_end, grace_period);
 }
 
 static void restart_grace(void)
 {
        if (nlmsvc_ops) {
-               cancel_delayed_work_sync(&grace_period_end);
-               locks_end_grace(&lockd_manager);
+               struct net *net = &init_net;
+               struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+               cancel_delayed_work_sync(&ln->grace_period_end);
+               locks_end_grace(&ln->lockd_manager);
                nlmsvc_invalidate_all();
-               set_grace_period();
+               set_grace_period(net);
        }
 }
 
@@ -137,8 +141,6 @@ lockd(void *vrqstp)
                nlm_timeout = LOCKD_DFLT_TIMEO;
        nlmsvc_timeout = nlm_timeout * HZ;
 
-       set_grace_period();
-
        /*
         * The main request loop. We don't terminate until the last
         * NFS mount or NFS daemon has gone away.
@@ -184,8 +186,6 @@ lockd(void *vrqstp)
                svc_process(rqstp);
        }
        flush_signals(current);
-       cancel_delayed_work_sync(&grace_period_end);
-       locks_end_grace(&lockd_manager);
        if (nlmsvc_ops)
                nlmsvc_invalidate_all();
        nlm_shutdown_hosts();
@@ -266,6 +266,7 @@ static int lockd_up_net(struct svc_serv *serv, struct net *net)
        error = make_socks(serv, net);
        if (error < 0)
                goto err_socks;
+       set_grace_period(net);
        dprintk("lockd_up_net: per-net data created; net=%p\n", net);
        return 0;
 
@@ -283,6 +284,8 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net)
        if (ln->nlmsvc_users) {
                if (--ln->nlmsvc_users == 0) {
                        nlm_shutdown_hosts_net(net);
+                       cancel_delayed_work_sync(&ln->grace_period_end);
+                       locks_end_grace(&ln->lockd_manager);
                        svc_shutdown_net(serv, net);
                        dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net);
                }
@@ -589,6 +592,10 @@ module_param(nlm_max_connections, uint, 0644);
 
 static int lockd_init_net(struct net *net)
 {
+       struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+       INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender);
+       INIT_LIST_HEAD(&ln->grace_list);
        return 0;
 }
 
index 9a41fdc19511ffb85cccab8fef5d42096bd08dca..4a43d253c045d0c50f1ddf63eabffc133774c314 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/time.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/share.h>
+#include <linux/sunrpc/svc_xprt.h>
 
 #define NLMDBG_FACILITY                NLMDBG_CLIENT
 
@@ -151,7 +152,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept requests during grace period */
-       if (locks_in_grace()) {
+       if (locks_in_grace(SVC_NET(rqstp))) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -161,7 +162,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
        /* Try to cancel request. */
-       resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
+       resp->status = nlmsvc_cancel_blocked(SVC_NET(rqstp), file, &argp->lock);
 
        dprintk("lockd: CANCEL        status %d\n", ntohl(resp->status));
        nlmsvc_release_host(host);
@@ -184,7 +185,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (locks_in_grace()) {
+       if (locks_in_grace(SVC_NET(rqstp))) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -194,7 +195,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
        /* Now try to remove the lock */
-       resp->status = nlmsvc_unlock(file, &argp->lock);
+       resp->status = nlmsvc_unlock(SVC_NET(rqstp), file, &argp->lock);
 
        dprintk("lockd: UNLOCK        status %d\n", ntohl(resp->status));
        nlmsvc_release_host(host);
@@ -321,7 +322,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (locks_in_grace() && !argp->reclaim) {
+       if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -354,7 +355,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept requests during grace period */
-       if (locks_in_grace()) {
+       if (locks_in_grace(SVC_NET(rqstp))) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
index e46353f41a4202ec2138998ab5449b833dc139db..afe4488c33d886a3c1bf58c1b827c05f09c3aa77 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/svc_xprt.h>
 #include <linux/lockd/nlm.h>
 #include <linux/lockd/lockd.h>
 #include <linux/kthread.h>
@@ -447,11 +447,11 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
                goto out;
        }
 
-       if (locks_in_grace() && !reclaim) {
+       if (locks_in_grace(SVC_NET(rqstp)) && !reclaim) {
                ret = nlm_lck_denied_grace_period;
                goto out;
        }
-       if (reclaim && !locks_in_grace()) {
+       if (reclaim && !locks_in_grace(SVC_NET(rqstp))) {
                ret = nlm_lck_denied_grace_period;
                goto out;
        }
@@ -559,7 +559,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
                goto out;
        }
 
-       if (locks_in_grace()) {
+       if (locks_in_grace(SVC_NET(rqstp))) {
                ret = nlm_lck_denied_grace_period;
                goto out;
        }
@@ -603,7 +603,7 @@ out:
  * must be removed.
  */
 __be32
-nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
+nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
 {
        int     error;
 
@@ -615,7 +615,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
                                (long long)lock->fl.fl_end);
 
        /* First, cancel any lock that might be there */
-       nlmsvc_cancel_blocked(file, lock);
+       nlmsvc_cancel_blocked(net, file, lock);
 
        lock->fl.fl_type = F_UNLCK;
        error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
@@ -631,7 +631,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
  * The calling procedure must check whether the file can be closed.
  */
 __be32
-nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
+nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
 {
        struct nlm_block        *block;
        int status = 0;
@@ -643,7 +643,7 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
                                (long long)lock->fl.fl_start,
                                (long long)lock->fl.fl_end);
 
-       if (locks_in_grace())
+       if (locks_in_grace(net))
                return nlm_lck_denied_grace_period;
 
        mutex_lock(&file->f_mutex);
index d27aab11f32414ae165cec40083ef20f08de0466..de8f2caa22359f8fa11dbd178fc1e78c5f1cc7ef 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/time.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/share.h>
+#include <linux/sunrpc/svc_xprt.h>
 
 #define NLMDBG_FACILITY                NLMDBG_CLIENT
 
@@ -175,13 +176,14 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
 {
        struct nlm_host *host;
        struct nlm_file *file;
+       struct net *net = SVC_NET(rqstp);
 
        dprintk("lockd: CANCEL        called\n");
 
        resp->cookie = argp->cookie;
 
        /* Don't accept requests during grace period */
-       if (locks_in_grace()) {
+       if (locks_in_grace(net)) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -191,7 +193,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
        /* Try to cancel request. */
-       resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock));
+       resp->status = cast_status(nlmsvc_cancel_blocked(net, file, &argp->lock));
 
        dprintk("lockd: CANCEL        status %d\n", ntohl(resp->status));
        nlmsvc_release_host(host);
@@ -208,13 +210,14 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
 {
        struct nlm_host *host;
        struct nlm_file *file;
+       struct net *net = SVC_NET(rqstp);
 
        dprintk("lockd: UNLOCK        called\n");
 
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (locks_in_grace()) {
+       if (locks_in_grace(net)) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -224,7 +227,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
                return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
        /* Now try to remove the lock */
-       resp->status = cast_status(nlmsvc_unlock(file, &argp->lock));
+       resp->status = cast_status(nlmsvc_unlock(net, file, &argp->lock));
 
        dprintk("lockd: UNLOCK        status %d\n", ntohl(resp->status));
        nlmsvc_release_host(host);
@@ -361,7 +364,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (locks_in_grace() && !argp->reclaim) {
+       if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
@@ -394,7 +397,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->cookie = argp->cookie;
 
        /* Don't accept requests during grace period */
-       if (locks_in_grace()) {
+       if (locks_in_grace(SVC_NET(rqstp))) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
index 2240d384d7877042c44ba134489b431e9de10118..0deb5f6c9dd47170ee2b19390362f2549ab7cac9 100644 (file)
@@ -309,7 +309,8 @@ nlm_release_file(struct nlm_file *file)
  * Helpers function for resource traversal
  *
  * nlmsvc_mark_host:
- *     used by the garbage collector; simply sets h_inuse.
+ *     used by the garbage collector; simply sets h_inuse only for those
+ *     hosts, which passed network check.
  *     Always returns 0.
  *
  * nlmsvc_same_host:
@@ -320,12 +321,15 @@ nlm_release_file(struct nlm_file *file)
  *     returns 1 iff the host is a client.
  *     Used by nlmsvc_invalidate_all
  */
+
 static int
-nlmsvc_mark_host(void *data, struct nlm_host *dummy)
+nlmsvc_mark_host(void *data, struct nlm_host *hint)
 {
        struct nlm_host *host = data;
 
-       host->h_inuse = 1;
+       if ((hint->net == NULL) ||
+           (host->net == hint->net))
+               host->h_inuse = 1;
        return 0;
 }
 
@@ -358,10 +362,13 @@ nlmsvc_is_client(void *data, struct nlm_host *dummy)
  * Mark all hosts that still hold resources
  */
 void
-nlmsvc_mark_resources(void)
+nlmsvc_mark_resources(struct net *net)
 {
-       dprintk("lockd: nlmsvc_mark_resources\n");
-       nlm_traverse_files(NULL, nlmsvc_mark_host, NULL);
+       struct nlm_host hint;
+
+       dprintk("lockd: nlmsvc_mark_resources for net %p\n", net);
+       hint.net = net;
+       nlm_traverse_files(&hint, nlmsvc_mark_host, NULL);
 }
 
 /*
index 82c353304f9eeccab27b01b86379441df323deeb..cdcf219a7391a0c5097ad0e74fb3a5ea6debdc92 100644 (file)
@@ -427,18 +427,8 @@ static void lease_break_callback(struct file_lock *fl)
        kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
 }
 
-static void lease_release_private_callback(struct file_lock *fl)
-{
-       if (!fl->fl_file)
-               return;
-
-       f_delown(fl->fl_file);
-       fl->fl_file->f_owner.signum = 0;
-}
-
 static const struct lock_manager_operations lease_manager_ops = {
        .lm_break = lease_break_callback,
-       .lm_release_private = lease_release_private_callback,
        .lm_change = lease_modify,
 };
 
@@ -580,12 +570,6 @@ static void locks_delete_lock(struct file_lock **thisfl_p)
        fl->fl_next = NULL;
        list_del_init(&fl->fl_link);
 
-       fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
-       if (fl->fl_fasync != NULL) {
-               printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
-               fl->fl_fasync = NULL;
-       }
-
        if (fl->fl_nspid) {
                put_pid(fl->fl_nspid);
                fl->fl_nspid = NULL;
@@ -1155,8 +1139,18 @@ int lease_modify(struct file_lock **before, int arg)
                return error;
        lease_clear_pending(fl, arg);
        locks_wake_up_blocks(fl);
-       if (arg == F_UNLCK)
+       if (arg == F_UNLCK) {
+               struct file *filp = fl->fl_file;
+
+               f_delown(filp);
+               filp->f_owner.signum = 0;
+               fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
+               if (fl->fl_fasync != NULL) {
+                       printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
+                       fl->fl_fasync = NULL;
+               }
                locks_delete_lock(before);
+       }
        return 0;
 }
 
index 13487ad168944e37eb8871161c3077d50b5a271c..78e2d93e5c830f33cc370d8ca98262fcfe27e883 100644 (file)
@@ -32,7 +32,8 @@ static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
        if (block < 0) {
                printk("MINIX-fs: block_to_path: block %ld < 0 on dev %s\n",
                        block, bdevname(sb->s_bdev, b));
-       } else if (block >= (minix_sb(inode->i_sb)->s_max_size/sb->s_blocksize)) {
+       } else if ((u64)block * (u64)sb->s_blocksize >=
+                       minix_sb(sb)->s_max_size) {
                if (printk_ratelimit())
                        printk("MINIX-fs: block_to_path: "
                               "block %ld too big on dev %s\n",
index f90f4f5cd421dc7be9db2151ead1d8d458acf096..404c6a8ac394423da4079aa965fd987e80a0e0cc 100644 (file)
@@ -88,9 +88,8 @@ config NFS_V4
 
 config NFS_V4_1
        bool "NFS client support for NFSv4.1 (EXPERIMENTAL)"
-       depends on NFS_FS && NFS_V4 && EXPERIMENTAL
+       depends on NFS_V4 && EXPERIMENTAL
        select SUNRPC_BACKCHANNEL
-       select PNFS_FILE_LAYOUT
        help
          This option enables support for minor version 1 of the NFSv4 protocol
          (RFC 5661) in the kernel's NFS client.
@@ -99,15 +98,17 @@ config NFS_V4_1
 
 config PNFS_FILE_LAYOUT
        tristate
+       depends on NFS_V4_1
+       default m
 
 config PNFS_BLOCK
        tristate
-       depends on NFS_FS && NFS_V4_1 && BLK_DEV_DM
+       depends on NFS_V4_1 && BLK_DEV_DM
        default m
 
 config PNFS_OBJLAYOUT
        tristate
-       depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD
+       depends on NFS_V4_1 && SCSI_OSD_ULD
        default m
 
 config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
index 7ddd45d9f1707d24a7661a402d95f58aef108c03..0b96c2038346309bde0926e971ade7db4f72d37a 100644 (file)
@@ -13,11 +13,16 @@ nfs-$(CONFIG_NFS_V2)        += proc.o nfs2xdr.o
 nfs-$(CONFIG_NFS_V3)   += nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V3_ACL)       += nfs3acl.o
 nfs-$(CONFIG_NFS_V4)   += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
-                          delegation.o idmap.o \
+                          nfs4super.o nfs4file.o delegation.o idmap.o \
                           callback.o callback_xdr.o callback_proc.o \
-                          nfs4namespace.o
+                          nfs4namespace.o nfs4getroot.o nfs4client.o
 nfs-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o
-nfs-$(CONFIG_SYSCTL) += sysctl.o
+
+ifeq ($(CONFIG_SYSCTL), y)
+nfs-y += sysctl.o
+nfs-$(CONFIG_NFS_V4) += nfs4sysctl.o
+endif
+
 nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
 
 obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
index e64b01d2a338274a459bc9c56c60dacf282aad84..742ff4ffced78fe9071da9c15ee22f458bfde3ca 100644 (file)
@@ -863,7 +863,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
                .drc_status = 0,
                .clp = NULL,
                .slotid = NFS4_NO_SLOT,
-               .net = rqstp->rq_xprt->xpt_net,
+               .net = SVC_NET(rqstp),
        };
        unsigned int nops = 0;
 
@@ -879,7 +879,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
                return rpc_garbage_args;
 
        if (hdr_arg.minorversion == 0) {
-               cps.clp = nfs4_find_client_ident(rqstp->rq_xprt->xpt_net, hdr_arg.cb_ident);
+               cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident);
                if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
                        return rpc_drop_reply;
        }
index f005b5bebdc73bba4d548d134699dd4f00c471ca..65afa382c5e3583c78a24e3deb907dd8bdfc276a 100644 (file)
 #define NFSDBG_FACILITY                NFSDBG_CLIENT
 
 static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
-#ifdef CONFIG_NFS_V4
-
-/*
- * Get a unique NFSv4.0 callback identifier which will be used
- * by the V4.0 callback service to lookup the nfs_client struct
- */
-static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
-{
-       int ret = 0;
-       struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
-
-       if (clp->rpc_ops->version != 4 || minorversion != 0)
-               return ret;
-retry:
-       if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL))
-               return -ENOMEM;
-       spin_lock(&nn->nfs_client_lock);
-       ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident);
-       spin_unlock(&nn->nfs_client_lock);
-       if (ret == -EAGAIN)
-               goto retry;
-       return ret;
-}
-#endif /* CONFIG_NFS_V4 */
-
-/*
- * Turn off NFSv4 uid/gid mapping when using AUTH_SYS
- */
-static bool nfs4_disable_idmapping = true;
 
 /*
  * RPC cruft for NFS
@@ -130,24 +101,13 @@ const struct rpc_program nfsacl_program = {
 };
 #endif  /* CONFIG_NFS_V3_ACL */
 
-struct nfs_client_initdata {
-       unsigned long init_flags;
-       const char *hostname;
-       const struct sockaddr *addr;
-       size_t addrlen;
-       const struct nfs_rpc_ops *rpc_ops;
-       int proto;
-       u32 minorversion;
-       struct net *net;
-};
-
 /*
  * Allocate a shared client record
  *
  * Since these are allocated/deallocated very rarely, we don't
  * bother putting them in a slab cache...
  */
-static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
+struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
 {
        struct nfs_client *clp;
        struct rpc_cred *cred;
@@ -177,18 +137,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
        clp->cl_proto = cl_init->proto;
        clp->cl_net = get_net(cl_init->net);
 
-#ifdef CONFIG_NFS_V4
-       err = nfs_get_cb_ident_idr(clp, cl_init->minorversion);
-       if (err)
-               goto error_cleanup;
-
-       spin_lock_init(&clp->cl_lock);
-       INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
-       rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
-       clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
-       clp->cl_minorversion = cl_init->minorversion;
-       clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion];
-#endif
        cred = rpc_lookup_machine_cred("*");
        if (!IS_ERR(cred))
                clp->cl_machine_cred = cred;
@@ -203,45 +151,6 @@ error_0:
 }
 
 #ifdef CONFIG_NFS_V4
-#ifdef CONFIG_NFS_V4_1
-static void nfs4_shutdown_session(struct nfs_client *clp)
-{
-       if (nfs4_has_session(clp)) {
-               nfs4_destroy_session(clp->cl_session);
-               nfs4_destroy_clientid(clp);
-       }
-
-}
-#else /* CONFIG_NFS_V4_1 */
-static void nfs4_shutdown_session(struct nfs_client *clp)
-{
-}
-#endif /* CONFIG_NFS_V4_1 */
-
-/*
- * Destroy the NFS4 callback service
- */
-static void nfs4_destroy_callback(struct nfs_client *clp)
-{
-       if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
-               nfs_callback_down(clp->cl_mvops->minor_version);
-}
-
-static void nfs4_shutdown_client(struct nfs_client *clp)
-{
-       if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
-               nfs4_kill_renewd(clp);
-       nfs4_shutdown_session(clp);
-       nfs4_destroy_callback(clp);
-       if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
-               nfs_idmap_delete(clp);
-
-       rpc_destroy_wait_queue(&clp->cl_rpcwaitq);
-       kfree(clp->cl_serverowner);
-       kfree(clp->cl_serverscope);
-       kfree(clp->cl_implid);
-}
-
 /* idr_remove_all is not needed as all id's are removed by nfs_put_client */
 void nfs_cleanup_cb_ident_idr(struct net *net)
 {
@@ -264,16 +173,7 @@ static void pnfs_init_server(struct nfs_server *server)
        rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC");
 }
 
-static void nfs4_destroy_server(struct nfs_server *server)
-{
-       nfs4_purge_state_owners(server);
-}
-
 #else
-static void nfs4_shutdown_client(struct nfs_client *clp)
-{
-}
-
 void nfs_cleanup_cb_ident_idr(struct net *net)
 {
 }
@@ -291,12 +191,10 @@ static void pnfs_init_server(struct nfs_server *server)
 /*
  * Destroy a shared client record
  */
-static void nfs_free_client(struct nfs_client *clp)
+void nfs_free_client(struct nfs_client *clp)
 {
        dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version);
 
-       nfs4_shutdown_client(clp);
-
        nfs_fscache_release_client_cookie(clp);
 
        /* -EIO all pending I/O */
@@ -333,7 +231,7 @@ void nfs_put_client(struct nfs_client *clp)
 
                BUG_ON(!list_empty(&clp->cl_superblocks));
 
-               nfs_free_client(clp);
+               clp->rpc_ops->free_client(clp);
        }
 }
 EXPORT_SYMBOL_GPL(nfs_put_client);
@@ -412,8 +310,8 @@ static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1,
  * Test if two socket addresses represent the same actual socket,
  * by comparing (only) relevant fields, excluding the port number.
  */
-static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
-                                    const struct sockaddr *sa2)
+int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
+                             const struct sockaddr *sa2)
 {
        if (sa1->sa_family != sa2->sa_family)
                return 0;
@@ -447,33 +345,6 @@ static int nfs_sockaddr_cmp(const struct sockaddr *sa1,
        return 0;
 }
 
-#if defined(CONFIG_NFS_V4_1)
-/* Common match routine for v4.0 and v4.1 callback services */
-static bool nfs4_cb_match_client(const struct sockaddr *addr,
-               struct nfs_client *clp, u32 minorversion)
-{
-       struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
-
-       /* Don't match clients that failed to initialise */
-       if (!(clp->cl_cons_state == NFS_CS_READY ||
-           clp->cl_cons_state == NFS_CS_SESSION_INITING))
-               return false;
-
-       smp_rmb();
-
-       /* Match the version and minorversion */
-       if (clp->rpc_ops->version != 4 ||
-           clp->cl_minorversion != minorversion)
-               return false;
-
-       /* Match only the IP address, not the port number */
-       if (!nfs_sockaddr_match_ipaddr(addr, clap))
-               return false;
-
-       return true;
-}
-#endif /* CONFIG_NFS_V4_1 */
-
 /*
  * Find an nfs_client on the list that matches the initialisation data
  * that is supplied.
@@ -552,7 +423,7 @@ nfs_found_client(const struct nfs_client_initdata *cl_init,
  * Look up a client by IP address and protocol version
  * - creates a new record if one doesn't yet exist
  */
-static struct nfs_client *
+struct nfs_client *
 nfs_get_client(const struct nfs_client_initdata *cl_init,
               const struct rpc_timeout *timeparms,
               const char *ip_addr,
@@ -572,7 +443,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
                if (clp) {
                        spin_unlock(&nn->nfs_client_lock);
                        if (new)
-                               nfs_free_client(new);
+                               new->rpc_ops->free_client(new);
                        return nfs_found_client(cl_init, clp);
                }
                if (new) {
@@ -586,7 +457,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
 
                spin_unlock(&nn->nfs_client_lock);
 
-               new = nfs_alloc_client(cl_init);
+               new = cl_init->rpc_ops->alloc_client(cl_init);
        } while (!IS_ERR(new));
 
        dprintk("<-- nfs_get_client() Failed to find %s (%ld)\n",
@@ -607,7 +478,7 @@ void nfs_mark_client_ready(struct nfs_client *clp, int state)
 /*
  * Initialise the timeout values for a connection
  */
-static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
+void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
                                    unsigned int timeo, unsigned int retrans)
 {
        to->to_initval = timeo * HZ / 10;
@@ -648,9 +519,9 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
 /*
  * Create an RPC client handle
  */
-static int nfs_create_rpc_client(struct nfs_client *clp,
-                                const struct rpc_timeout *timeparms,
-                                rpc_authflavor_t flavor)
+int nfs_create_rpc_client(struct nfs_client *clp,
+                         const struct rpc_timeout *timeparms,
+                         rpc_authflavor_t flavor)
 {
        struct rpc_clnt         *clnt = NULL;
        struct rpc_create_args args = {
@@ -767,7 +638,7 @@ static inline void nfs_init_server_aclclient(struct nfs_server *server)
 /*
  * Create a general RPC client
  */
-static int nfs_init_server_rpcclient(struct nfs_server *server,
+int nfs_init_server_rpcclient(struct nfs_server *server,
                const struct rpc_timeout *timeo,
                rpc_authflavor_t pseudoflavour)
 {
@@ -975,7 +846,6 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
                server->wsize = NFS_MAX_FILE_IO_SIZE;
        server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
        server->pnfs_blksize = fsinfo->blksize;
-       set_pnfs_layoutdriver(server, mntfh, fsinfo->layouttype);
 
        server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
 
@@ -1001,7 +871,7 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
 /*
  * Probe filesystem information, including the FSID on v2/v3
  */
-static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr)
+int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr)
 {
        struct nfs_fsinfo fsinfo;
        struct nfs_client *clp = server->nfs_client;
@@ -1045,7 +915,7 @@ out_error:
 /*
  * Copy useful information when duplicating a server record
  */
-static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
+void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
 {
        target->flags = source->flags;
        target->rsize = source->rsize;
@@ -1058,7 +928,7 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve
        target->options = source->options;
 }
 
-static void nfs_server_insert_lists(struct nfs_server *server)
+void nfs_server_insert_lists(struct nfs_server *server)
 {
        struct nfs_client *clp = server->nfs_client;
        struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
@@ -1092,7 +962,7 @@ static void nfs_server_remove_lists(struct nfs_server *server)
 /*
  * Allocate and initialise a server record
  */
-static struct nfs_server *nfs_alloc_server(void)
+struct nfs_server *nfs_alloc_server(void)
 {
        struct nfs_server *server;
 
@@ -1138,7 +1008,6 @@ void nfs_free_server(struct nfs_server *server)
        dprintk("--> nfs_free_server()\n");
 
        nfs_server_remove_lists(server);
-       unset_pnfs_layoutdriver(server);
 
        if (server->destroy != NULL)
                server->destroy(server);
@@ -1226,522 +1095,6 @@ error:
        return ERR_PTR(error);
 }
 
-#ifdef CONFIG_NFS_V4
-/*
- * NFSv4.0 callback thread helper
- *
- * Find a client by callback identifier
- */
-struct nfs_client *
-nfs4_find_client_ident(struct net *net, int cb_ident)
-{
-       struct nfs_client *clp;
-       struct nfs_net *nn = net_generic(net, nfs_net_id);
-
-       spin_lock(&nn->nfs_client_lock);
-       clp = idr_find(&nn->cb_ident_idr, cb_ident);
-       if (clp)
-               atomic_inc(&clp->cl_count);
-       spin_unlock(&nn->nfs_client_lock);
-       return clp;
-}
-
-#if defined(CONFIG_NFS_V4_1)
-/*
- * NFSv4.1 callback thread helper
- * For CB_COMPOUND calls, find a client by IP address, protocol version,
- * minorversion, and sessionID
- *
- * Returns NULL if no such client
- */
-struct nfs_client *
-nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
-                          struct nfs4_sessionid *sid)
-{
-       struct nfs_client *clp;
-       struct nfs_net *nn = net_generic(net, nfs_net_id);
-
-       spin_lock(&nn->nfs_client_lock);
-       list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
-               if (nfs4_cb_match_client(addr, clp, 1) == false)
-                       continue;
-
-               if (!nfs4_has_session(clp))
-                       continue;
-
-               /* Match sessionid*/
-               if (memcmp(clp->cl_session->sess_id.data,
-                   sid->data, NFS4_MAX_SESSIONID_LEN) != 0)
-                       continue;
-
-               atomic_inc(&clp->cl_count);
-               spin_unlock(&nn->nfs_client_lock);
-               return clp;
-       }
-       spin_unlock(&nn->nfs_client_lock);
-       return NULL;
-}
-
-#else /* CONFIG_NFS_V4_1 */
-
-struct nfs_client *
-nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
-                          struct nfs4_sessionid *sid)
-{
-       return NULL;
-}
-#endif /* CONFIG_NFS_V4_1 */
-
-/*
- * Initialize the NFS4 callback service
- */
-static int nfs4_init_callback(struct nfs_client *clp)
-{
-       int error;
-
-       if (clp->rpc_ops->version == 4) {
-               struct rpc_xprt *xprt;
-
-               xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
-
-               if (nfs4_has_session(clp)) {
-                       error = xprt_setup_backchannel(xprt,
-                                               NFS41_BC_MIN_CALLBACKS);
-                       if (error < 0)
-                               return error;
-               }
-
-               error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
-               if (error < 0) {
-                       dprintk("%s: failed to start callback. Error = %d\n",
-                               __func__, error);
-                       return error;
-               }
-               __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
-       }
-       return 0;
-}
-
-/*
- * Initialize the minor version specific parts of an NFS4 client record
- */
-static int nfs4_init_client_minor_version(struct nfs_client *clp)
-{
-#if defined(CONFIG_NFS_V4_1)
-       if (clp->cl_mvops->minor_version) {
-               struct nfs4_session *session = NULL;
-               /*
-                * Create the session and mark it expired.
-                * When a SEQUENCE operation encounters the expired session
-                * it will do session recovery to initialize it.
-                */
-               session = nfs4_alloc_session(clp);
-               if (!session)
-                       return -ENOMEM;
-
-               clp->cl_session = session;
-               /*
-                * The create session reply races with the server back
-                * channel probe. Mark the client NFS_CS_SESSION_INITING
-                * so that the client back channel can find the
-                * nfs_client struct
-                */
-               nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING);
-       }
-#endif /* CONFIG_NFS_V4_1 */
-
-       return nfs4_init_callback(clp);
-}
-
-/**
- * nfs4_init_client - Initialise an NFS4 client record
- *
- * @clp: nfs_client to initialise
- * @timeparms: timeout parameters for underlying RPC transport
- * @ip_addr: callback IP address in presentation format
- * @authflavor: authentication flavor for underlying RPC transport
- *
- * Returns pointer to an NFS client, or an ERR_PTR value.
- */
-struct nfs_client *nfs4_init_client(struct nfs_client *clp,
-                                   const struct rpc_timeout *timeparms,
-                                   const char *ip_addr,
-                                   rpc_authflavor_t authflavour)
-{
-       char buf[INET6_ADDRSTRLEN + 1];
-       int error;
-
-       if (clp->cl_cons_state == NFS_CS_READY) {
-               /* the client is initialised already */
-               dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp);
-               return clp;
-       }
-
-       /* Check NFS protocol revision and initialize RPC op vector */
-       clp->rpc_ops = &nfs_v4_clientops;
-
-       __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
-       error = nfs_create_rpc_client(clp, timeparms, authflavour);
-       if (error < 0)
-               goto error;
-
-       /* If no clientaddr= option was specified, find a usable cb address */
-       if (ip_addr == NULL) {
-               struct sockaddr_storage cb_addr;
-               struct sockaddr *sap = (struct sockaddr *)&cb_addr;
-
-               error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr));
-               if (error < 0)
-                       goto error;
-               error = rpc_ntop(sap, buf, sizeof(buf));
-               if (error < 0)
-                       goto error;
-               ip_addr = (const char *)buf;
-       }
-       strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
-
-       error = nfs_idmap_new(clp);
-       if (error < 0) {
-               dprintk("%s: failed to create idmapper. Error = %d\n",
-                       __func__, error);
-               goto error;
-       }
-       __set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
-
-       error = nfs4_init_client_minor_version(clp);
-       if (error < 0)
-               goto error;
-
-       if (!nfs4_has_session(clp))
-               nfs_mark_client_ready(clp, NFS_CS_READY);
-       return clp;
-
-error:
-       nfs_mark_client_ready(clp, error);
-       nfs_put_client(clp);
-       dprintk("<-- nfs4_init_client() = xerror %d\n", error);
-       return ERR_PTR(error);
-}
-
-/*
- * Set up an NFS4 client
- */
-static int nfs4_set_client(struct nfs_server *server,
-               const char *hostname,
-               const struct sockaddr *addr,
-               const size_t addrlen,
-               const char *ip_addr,
-               rpc_authflavor_t authflavour,
-               int proto, const struct rpc_timeout *timeparms,
-               u32 minorversion, struct net *net)
-{
-       struct nfs_client_initdata cl_init = {
-               .hostname = hostname,
-               .addr = addr,
-               .addrlen = addrlen,
-               .rpc_ops = &nfs_v4_clientops,
-               .proto = proto,
-               .minorversion = minorversion,
-               .net = net,
-       };
-       struct nfs_client *clp;
-       int error;
-
-       dprintk("--> nfs4_set_client()\n");
-
-       if (server->flags & NFS_MOUNT_NORESVPORT)
-               set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
-
-       /* Allocate or find a client reference we can use */
-       clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour);
-       if (IS_ERR(clp)) {
-               error = PTR_ERR(clp);
-               goto error;
-       }
-
-       /*
-        * Query for the lease time on clientid setup or renewal
-        *
-        * Note that this will be set on nfs_clients that were created
-        * only for the DS role and did not set this bit, but now will
-        * serve a dual role.
-        */
-       set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state);
-
-       server->nfs_client = clp;
-       dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp);
-       return 0;
-error:
-       dprintk("<-- nfs4_set_client() = xerror %d\n", error);
-       return error;
-}
-
-/*
- * Set up a pNFS Data Server client.
- *
- * Return any existing nfs_client that matches server address,port,version
- * and minorversion.
- *
- * For a new nfs_client, use a soft mount (default), a low retrans and a
- * low timeout interval so that if a connection is lost, we retry through
- * the MDS.
- */
-struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
-               const struct sockaddr *ds_addr, int ds_addrlen,
-               int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans)
-{
-       struct nfs_client_initdata cl_init = {
-               .addr = ds_addr,
-               .addrlen = ds_addrlen,
-               .rpc_ops = &nfs_v4_clientops,
-               .proto = ds_proto,
-               .minorversion = mds_clp->cl_minorversion,
-               .net = mds_clp->cl_net,
-       };
-       struct rpc_timeout ds_timeout;
-       struct nfs_client *clp;
-
-       /*
-        * Set an authflavor equual to the MDS value. Use the MDS nfs_client
-        * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS
-        * (section 13.1 RFC 5661).
-        */
-       nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans);
-       clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr,
-                            mds_clp->cl_rpcclient->cl_auth->au_flavor);
-
-       dprintk("<-- %s %p\n", __func__, clp);
-       return clp;
-}
-EXPORT_SYMBOL_GPL(nfs4_set_ds_client);
-
-/*
- * Session has been established, and the client marked ready.
- * Set the mount rsize and wsize with negotiated fore channel
- * attributes which will be bound checked in nfs_server_set_fsinfo.
- */
-static void nfs4_session_set_rwsize(struct nfs_server *server)
-{
-#ifdef CONFIG_NFS_V4_1
-       struct nfs4_session *sess;
-       u32 server_resp_sz;
-       u32 server_rqst_sz;
-
-       if (!nfs4_has_session(server->nfs_client))
-               return;
-       sess = server->nfs_client->cl_session;
-       server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead;
-       server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead;
-
-       if (server->rsize > server_resp_sz)
-               server->rsize = server_resp_sz;
-       if (server->wsize > server_rqst_sz)
-               server->wsize = server_rqst_sz;
-#endif /* CONFIG_NFS_V4_1 */
-}
-
-static int nfs4_server_common_setup(struct nfs_server *server,
-               struct nfs_fh *mntfh)
-{
-       struct nfs_fattr *fattr;
-       int error;
-
-       BUG_ON(!server->nfs_client);
-       BUG_ON(!server->nfs_client->rpc_ops);
-       BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
-
-       /* data servers support only a subset of NFSv4.1 */
-       if (is_ds_only_client(server->nfs_client))
-               return -EPROTONOSUPPORT;
-
-       fattr = nfs_alloc_fattr();
-       if (fattr == NULL)
-               return -ENOMEM;
-
-       /* We must ensure the session is initialised first */
-       error = nfs4_init_session(server);
-       if (error < 0)
-               goto out;
-
-       /* Probe the root fh to retrieve its FSID and filehandle */
-       error = nfs4_get_rootfh(server, mntfh);
-       if (error < 0)
-               goto out;
-
-       dprintk("Server FSID: %llx:%llx\n",
-                       (unsigned long long) server->fsid.major,
-                       (unsigned long long) server->fsid.minor);
-       dprintk("Mount FH: %d\n", mntfh->size);
-
-       nfs4_session_set_rwsize(server);
-
-       error = nfs_probe_fsinfo(server, mntfh, fattr);
-       if (error < 0)
-               goto out;
-
-       if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
-               server->namelen = NFS4_MAXNAMLEN;
-
-       nfs_server_insert_lists(server);
-       server->mount_time = jiffies;
-       server->destroy = nfs4_destroy_server;
-out:
-       nfs_free_fattr(fattr);
-       return error;
-}
-
-/*
- * Create a version 4 volume record
- */
-static int nfs4_init_server(struct nfs_server *server,
-               const struct nfs_parsed_mount_data *data)
-{
-       struct rpc_timeout timeparms;
-       int error;
-
-       dprintk("--> nfs4_init_server()\n");
-
-       nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
-                       data->timeo, data->retrans);
-
-       /* Initialise the client representation from the mount data */
-       server->flags = data->flags;
-       server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|NFS_CAP_POSIX_LOCK;
-       if (!(data->flags & NFS_MOUNT_NORDIRPLUS))
-                       server->caps |= NFS_CAP_READDIRPLUS;
-       server->options = data->options;
-
-       /* Get a client record */
-       error = nfs4_set_client(server,
-                       data->nfs_server.hostname,
-                       (const struct sockaddr *)&data->nfs_server.address,
-                       data->nfs_server.addrlen,
-                       data->client_address,
-                       data->auth_flavors[0],
-                       data->nfs_server.protocol,
-                       &timeparms,
-                       data->minorversion,
-                       data->net);
-       if (error < 0)
-               goto error;
-
-       /*
-        * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
-        * authentication.
-        */
-       if (nfs4_disable_idmapping && data->auth_flavors[0] == RPC_AUTH_UNIX)
-               server->caps |= NFS_CAP_UIDGID_NOMAP;
-
-       if (data->rsize)
-               server->rsize = nfs_block_size(data->rsize, NULL);
-       if (data->wsize)
-               server->wsize = nfs_block_size(data->wsize, NULL);
-
-       server->acregmin = data->acregmin * HZ;
-       server->acregmax = data->acregmax * HZ;
-       server->acdirmin = data->acdirmin * HZ;
-       server->acdirmax = data->acdirmax * HZ;
-
-       server->port = data->nfs_server.port;
-
-       error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]);
-
-error:
-       /* Done */
-       dprintk("<-- nfs4_init_server() = %d\n", error);
-       return error;
-}
-
-/*
- * Create a version 4 volume record
- * - keyed on server and FSID
- */
-struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
-                                     struct nfs_fh *mntfh)
-{
-       struct nfs_server *server;
-       int error;
-
-       dprintk("--> nfs4_create_server()\n");
-
-       server = nfs_alloc_server();
-       if (!server)
-               return ERR_PTR(-ENOMEM);
-
-       /* set up the general RPC client */
-       error = nfs4_init_server(server, data);
-       if (error < 0)
-               goto error;
-
-       error = nfs4_server_common_setup(server, mntfh);
-       if (error < 0)
-               goto error;
-
-       dprintk("<-- nfs4_create_server() = %p\n", server);
-       return server;
-
-error:
-       nfs_free_server(server);
-       dprintk("<-- nfs4_create_server() = error %d\n", error);
-       return ERR_PTR(error);
-}
-
-/*
- * Create an NFS4 referral server record
- */
-struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
-                                              struct nfs_fh *mntfh)
-{
-       struct nfs_client *parent_client;
-       struct nfs_server *server, *parent_server;
-       int error;
-
-       dprintk("--> nfs4_create_referral_server()\n");
-
-       server = nfs_alloc_server();
-       if (!server)
-               return ERR_PTR(-ENOMEM);
-
-       parent_server = NFS_SB(data->sb);
-       parent_client = parent_server->nfs_client;
-
-       /* Initialise the client representation from the parent server */
-       nfs_server_copy_userdata(server, parent_server);
-       server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR;
-
-       /* Get a client representation.
-        * Note: NFSv4 always uses TCP, */
-       error = nfs4_set_client(server, data->hostname,
-                               data->addr,
-                               data->addrlen,
-                               parent_client->cl_ipaddr,
-                               data->authflavor,
-                               rpc_protocol(parent_server->client),
-                               parent_server->client->cl_timeout,
-                               parent_client->cl_mvops->minor_version,
-                               parent_client->cl_net);
-       if (error < 0)
-               goto error;
-
-       error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor);
-       if (error < 0)
-               goto error;
-
-       error = nfs4_server_common_setup(server, mntfh);
-       if (error < 0)
-               goto error;
-
-       dprintk("<-- nfs_create_referral_server() = %p\n", server);
-       return server;
-
-error:
-       nfs_free_server(server);
-       dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
-       return ERR_PTR(error);
-}
-
-#endif /* CONFIG_NFS_V4 */
-
 /*
  * Clone an NFS2, NFS3 or NFS4 server record
  */
@@ -2091,7 +1444,3 @@ void nfs_fs_proc_exit(void)
 }
 
 #endif /* CONFIG_PROC_FS */
-
-module_param(nfs4_disable_idmapping, bool, 0644);
-MODULE_PARM_DESC(nfs4_disable_idmapping,
-               "Turn off NFSv4 idmapping when using 'sec=sys'");
index bd3a9601d32d9915a70e1888ab5a710671e00aac..81c5eec3cf3803a610efee85e37d0f2276cbe108 100644 (file)
@@ -47,7 +47,7 @@ void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
  *
  * Returns one if inode has the indicated delegation, otherwise zero.
  */
-int nfs_have_delegation(struct inode *inode, fmode_t flags)
+int nfs4_have_delegation(struct inode *inode, fmode_t flags)
 {
        struct nfs_delegation *delegation;
        int ret = 0;
@@ -388,7 +388,7 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode)
  *
  * Returns zero on success, or a negative errno value.
  */
-int nfs_inode_return_delegation(struct inode *inode)
+int nfs4_inode_return_delegation(struct inode *inode)
 {
        struct nfs_server *server = NFS_SERVER(inode);
        struct nfs_inode *nfsi = NFS_I(inode);
@@ -417,9 +417,8 @@ static void nfs_mark_return_delegation(struct nfs_server *server,
  * @sb: sb to process
  *
  */
-void nfs_super_return_all_delegations(struct super_block *sb)
+void nfs_server_return_all_delegations(struct nfs_server *server)
 {
-       struct nfs_server *server = NFS_SB(sb);
        struct nfs_client *clp = server->nfs_client;
        struct nfs_delegation *delegation;
 
index 72709c4193fa28ac3afeba63f65e2f46e954eb23..1f3ccd934635dd4b3a03abc0831dcfbe7b6ab865 100644 (file)
@@ -33,12 +33,12 @@ enum {
 
 int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
 void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
-int nfs_inode_return_delegation(struct inode *inode);
+int nfs4_inode_return_delegation(struct inode *inode);
 int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
 void nfs_inode_return_delegation_noreclaim(struct inode *inode);
 
 struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
-void nfs_super_return_all_delegations(struct super_block *sb);
+void nfs_server_return_all_delegations(struct nfs_server *);
 void nfs_expire_all_delegations(struct nfs_client *clp);
 void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags);
 void nfs_expire_unreferenced_delegations(struct nfs_client *clp);
@@ -56,24 +56,13 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
 bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags);
 
 void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
-int nfs_have_delegation(struct inode *inode, fmode_t flags);
+int nfs4_have_delegation(struct inode *inode, fmode_t flags);
 
-#else
-static inline int nfs_have_delegation(struct inode *inode, fmode_t flags)
-{
-       return 0;
-}
-
-static inline int nfs_inode_return_delegation(struct inode *inode)
-{
-       nfs_wb_all(inode);
-       return 0;
-}
 #endif
 
 static inline int nfs_have_delegated_attributes(struct inode *inode)
 {
-       return nfs_have_delegation(inode, FMODE_READ) &&
+       return NFS_PROTO(inode)->have_delegation(inode, FMODE_READ) &&
                !(NFS_I(inode)->cache_validity & NFS_INO_REVAL_FORCED);
 }
 
index a6b1c7fb8232c0a3152f79175e2047421c896859..d49f1b9cd3fdc058e9863384629fc618ffb49314 100644 (file)
 static int nfs_opendir(struct inode *, struct file *);
 static int nfs_closedir(struct inode *, struct file *);
 static int nfs_readdir(struct file *, void *, filldir_t);
-static struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int);
-static int nfs_create(struct inode *, struct dentry *, umode_t, bool);
-static int nfs_mkdir(struct inode *, struct dentry *, umode_t);
-static int nfs_rmdir(struct inode *, struct dentry *);
-static int nfs_unlink(struct inode *, struct dentry *);
-static int nfs_symlink(struct inode *, struct dentry *, const char *);
-static int nfs_link(struct dentry *, struct inode *, struct dentry *);
-static int nfs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
-static int nfs_rename(struct inode *, struct dentry *,
-                     struct inode *, struct dentry *);
 static int nfs_fsync_dir(struct file *, loff_t, loff_t, int);
 static loff_t nfs_llseek_dir(struct file *, loff_t, int);
 static void nfs_readdir_clear_array(struct page*);
@@ -69,73 +59,10 @@ const struct file_operations nfs_dir_operations = {
        .fsync          = nfs_fsync_dir,
 };
 
-const struct inode_operations nfs_dir_inode_operations = {
-       .create         = nfs_create,
-       .lookup         = nfs_lookup,
-       .link           = nfs_link,
-       .unlink         = nfs_unlink,
-       .symlink        = nfs_symlink,
-       .mkdir          = nfs_mkdir,
-       .rmdir          = nfs_rmdir,
-       .mknod          = nfs_mknod,
-       .rename         = nfs_rename,
-       .permission     = nfs_permission,
-       .getattr        = nfs_getattr,
-       .setattr        = nfs_setattr,
-};
-
 const struct address_space_operations nfs_dir_aops = {
        .freepage = nfs_readdir_clear_array,
 };
 
-#ifdef CONFIG_NFS_V3
-const struct inode_operations nfs3_dir_inode_operations = {
-       .create         = nfs_create,
-       .lookup         = nfs_lookup,
-       .link           = nfs_link,
-       .unlink         = nfs_unlink,
-       .symlink        = nfs_symlink,
-       .mkdir          = nfs_mkdir,
-       .rmdir          = nfs_rmdir,
-       .mknod          = nfs_mknod,
-       .rename         = nfs_rename,
-       .permission     = nfs_permission,
-       .getattr        = nfs_getattr,
-       .setattr        = nfs_setattr,
-       .listxattr      = nfs3_listxattr,
-       .getxattr       = nfs3_getxattr,
-       .setxattr       = nfs3_setxattr,
-       .removexattr    = nfs3_removexattr,
-};
-#endif  /* CONFIG_NFS_V3 */
-
-#ifdef CONFIG_NFS_V4
-
-static int nfs_atomic_open(struct inode *, struct dentry *,
-                          struct file *, unsigned, umode_t,
-                          int *);
-const struct inode_operations nfs4_dir_inode_operations = {
-       .create         = nfs_create,
-       .lookup         = nfs_lookup,
-       .atomic_open    = nfs_atomic_open,
-       .link           = nfs_link,
-       .unlink         = nfs_unlink,
-       .symlink        = nfs_symlink,
-       .mkdir          = nfs_mkdir,
-       .rmdir          = nfs_rmdir,
-       .mknod          = nfs_mknod,
-       .rename         = nfs_rename,
-       .permission     = nfs_permission,
-       .getattr        = nfs_getattr,
-       .setattr        = nfs_setattr,
-       .getxattr       = generic_getxattr,
-       .setxattr       = generic_setxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
-};
-
-#endif /* CONFIG_NFS_V4 */
-
 static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred)
 {
        struct nfs_open_dir_context *ctx;
@@ -1128,7 +1055,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
                goto out_bad;
        }
 
-       if (nfs_have_delegation(inode, FMODE_READ))
+       if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ))
                goto out_set_verifier;
 
        /* Force a full look up iff the parent directory has changed */
@@ -1270,7 +1197,7 @@ const struct dentry_operations nfs_dentry_operations = {
        .d_release      = nfs_d_release,
 };
 
-static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
+struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
 {
        struct dentry *res;
        struct dentry *parent;
@@ -1398,9 +1325,9 @@ out:
        return err;
 }
 
-static int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
-                           struct file *file, unsigned open_flags,
-                           umode_t mode, int *opened)
+int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
+                   struct file *file, unsigned open_flags,
+                   umode_t mode, int *opened)
 {
        struct nfs_open_context *ctx;
        struct dentry *res;
@@ -1588,7 +1515,7 @@ out_error:
  * that the operation succeeded on the server, but an error in the
  * reply path made it appear to have failed.
  */
-static int nfs_create(struct inode *dir, struct dentry *dentry,
+int nfs_create(struct inode *dir, struct dentry *dentry,
                umode_t mode, bool excl)
 {
        struct iattr attr;
@@ -1613,7 +1540,7 @@ out_err:
 /*
  * See comments for nfs_proc_create regarding failed operations.
  */
-static int
+int
 nfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
 {
        struct iattr attr;
@@ -1640,7 +1567,7 @@ out_err:
 /*
  * See comments for nfs_proc_create regarding failed operations.
  */
-static int nfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+int nfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        struct iattr attr;
        int error;
@@ -1666,7 +1593,7 @@ static void nfs_dentry_handle_enoent(struct dentry *dentry)
                d_delete(dentry);
 }
 
-static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
+int nfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
        int error;
 
@@ -1706,7 +1633,7 @@ static int nfs_safe_remove(struct dentry *dentry)
        }
 
        if (inode != NULL) {
-               nfs_inode_return_delegation(inode);
+               NFS_PROTO(inode)->return_delegation(inode);
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
                /* The VFS may want to delete this inode */
                if (error == 0)
@@ -1725,7 +1652,7 @@ out:
  *
  *  If sillyrename() returns 0, we do nothing, otherwise we unlink.
  */
-static int nfs_unlink(struct inode *dir, struct dentry *dentry)
+int nfs_unlink(struct inode *dir, struct dentry *dentry)
 {
        int error;
        int need_rehash = 0;
@@ -1769,7 +1696,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
  * now have a new file handle and can instantiate an in-core NFS inode
  * and move the raw page into its mapping.
  */
-static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
        struct pagevec lru_pvec;
        struct page *page;
@@ -1824,7 +1751,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
        return 0;
 }
 
-static int 
+int
 nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 {
        struct inode *inode = old_dentry->d_inode;
@@ -1834,7 +1761,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
                old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
                dentry->d_parent->d_name.name, dentry->d_name.name);
 
-       nfs_inode_return_delegation(inode);
+       NFS_PROTO(inode)->return_delegation(inode);
 
        d_drop(dentry);
        error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
@@ -1869,7 +1796,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
  * If these conditions are met, we can drop the dentries before doing
  * the rename.
  */
-static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                      struct inode *new_dir, struct dentry *new_dentry)
 {
        struct inode *old_inode = old_dentry->d_inode;
@@ -1918,9 +1845,9 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                }
        }
 
-       nfs_inode_return_delegation(old_inode);
+       NFS_PROTO(old_inode)->return_delegation(old_inode);
        if (new_inode != NULL)
-               nfs_inode_return_delegation(new_inode);
+               NFS_PROTO(new_inode)->return_delegation(new_inode);
 
        error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
                                           new_dir, &new_dentry->d_name);
index 48253372ab1d115def0b81f56b097db6e98a0f88..42dce909ec70073509c33eabdf8b9784eda68faf 100644 (file)
@@ -393,7 +393,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
        size_t requested_bytes = 0;
        unsigned long seg;
 
-       nfs_pageio_init_read(&desc, dreq->inode,
+       NFS_PROTO(dreq->inode)->read_pageio_init(&desc, dreq->inode,
                             &nfs_direct_read_completion_ops);
        get_dreq(dreq);
        desc.pg_dreq = dreq;
@@ -478,7 +478,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
        dreq->count = 0;
        get_dreq(dreq);
 
-       nfs_pageio_init_write(&desc, dreq->inode, FLUSH_STABLE,
+       NFS_PROTO(dreq->inode)->write_pageio_init(&desc, dreq->inode, FLUSH_STABLE,
                              &nfs_direct_write_completion_ops);
        desc.pg_dreq = dreq;
 
@@ -782,7 +782,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
        size_t requested_bytes = 0;
        unsigned long seg;
 
-       nfs_pageio_init_write(&desc, inode, FLUSH_COND_STABLE,
+       NFS_PROTO(inode)->write_pageio_init(&desc, inode, FLUSH_COND_STABLE,
                              &nfs_direct_write_completion_ops);
        desc.pg_dreq = dreq;
        get_dreq(dreq);
index a6708e6b438dd55f2924e5bb78c809c1575a97a9..70d124a61b98d4e6b7fa3487e148de56c57406fb 100644 (file)
 #include "internal.h"
 #include "iostat.h"
 #include "fscache.h"
-#include "pnfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_FILE
 
 static const struct vm_operations_struct nfs_file_vm_ops;
 
-const struct inode_operations nfs_file_inode_operations = {
-       .permission     = nfs_permission,
-       .getattr        = nfs_getattr,
-       .setattr        = nfs_setattr,
-};
-
-#ifdef CONFIG_NFS_V3
-const struct inode_operations nfs3_file_inode_operations = {
-       .permission     = nfs_permission,
-       .getattr        = nfs_getattr,
-       .setattr        = nfs_setattr,
-       .listxattr      = nfs3_listxattr,
-       .getxattr       = nfs3_getxattr,
-       .setxattr       = nfs3_setxattr,
-       .removexattr    = nfs3_removexattr,
-};
-#endif  /* CONFIG_NFS_v3 */
-
 /* Hack for future NFS swap support */
 #ifndef IS_SWAPFILE
 # define IS_SWAPFILE(inode)    (0)
 #endif
 
-static int nfs_check_flags(int flags)
+int nfs_check_flags(int flags)
 {
        if ((flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT))
                return -EINVAL;
@@ -93,7 +74,7 @@ nfs_file_open(struct inode *inode, struct file *filp)
        return res;
 }
 
-static int
+int
 nfs_file_release(struct inode *inode, struct file *filp)
 {
        dprintk("NFS: release(%s/%s)\n",
@@ -135,7 +116,7 @@ force_reval:
        return __nfs_revalidate_inode(server, inode);
 }
 
-static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
+loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
 {
        dprintk("NFS: llseek file(%s/%s, %lld, %d)\n",
                        filp->f_path.dentry->d_parent->d_name.name,
@@ -160,7 +141,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
 /*
  * Flush all dirty pages, and check for write errors.
  */
-static int
+int
 nfs_file_flush(struct file *file, fl_owner_t id)
 {
        struct dentry   *dentry = file->f_path.dentry;
@@ -178,14 +159,14 @@ nfs_file_flush(struct file *file, fl_owner_t id)
         * If we're holding a write delegation, then just start the i/o
         * but don't wait for completion (or send a commit).
         */
-       if (nfs_have_delegation(inode, FMODE_WRITE))
+       if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))
                return filemap_fdatawrite(file->f_mapping);
 
        /* Flush writes to the server and return any errors */
        return vfs_fsync(file, 0);
 }
 
-static ssize_t
+ssize_t
 nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
                unsigned long nr_segs, loff_t pos)
 {
@@ -209,7 +190,7 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
        return result;
 }
 
-static ssize_t
+ssize_t
 nfs_file_splice_read(struct file *filp, loff_t *ppos,
                     struct pipe_inode_info *pipe, size_t count,
                     unsigned int flags)
@@ -231,7 +212,7 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,
        return res;
 }
 
-static int
+int
 nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
 {
        struct dentry *dentry = file->f_path.dentry;
@@ -264,8 +245,8 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
  * nfs_file_write() that a write error occurred, and hence cause it to
  * fall back to doing a synchronous write.
  */
-static int
-nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+int
+nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct dentry *dentry = file->f_path.dentry;
        struct nfs_open_context *ctx = nfs_file_open_context(file);
@@ -277,9 +258,6 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
                        dentry->d_parent->d_name.name, dentry->d_name.name,
                        datasync);
 
-       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
-       mutex_lock(&inode->i_mutex);
-
        nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
        have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
        status = nfs_commit_inode(inode, FLUSH_SYNC);
@@ -290,10 +268,20 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
                ret = xchg(&ctx->error, 0);
        if (!ret && status < 0)
                ret = status;
-       if (!ret && !datasync)
-               /* application has asked for meta-data sync */
-               ret = pnfs_layoutcommit_inode(inode, true);
+       return ret;
+}
+
+static int
+nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+       int ret;
+       struct inode *inode = file->f_path.dentry->d_inode;
+
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       mutex_lock(&inode->i_mutex);
+       ret = nfs_file_fsync_commit(file, start, end, datasync);
        mutex_unlock(&inode->i_mutex);
+
        return ret;
 }
 
@@ -572,8 +560,8 @@ static int nfs_need_sync_write(struct file *filp, struct inode *inode)
        return 0;
 }
 
-static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
-                               unsigned long nr_segs, loff_t pos)
+ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
+                      unsigned long nr_segs, loff_t pos)
 {
        struct dentry * dentry = iocb->ki_filp->f_path.dentry;
        struct inode * inode = dentry->d_inode;
@@ -624,9 +612,9 @@ out_swapfile:
        goto out;
 }
 
-static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
-                                    struct file *filp, loff_t *ppos,
-                                    size_t count, unsigned int flags)
+ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
+                             struct file *filp, loff_t *ppos,
+                             size_t count, unsigned int flags)
 {
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
@@ -670,7 +658,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
        }
        fl->fl_type = saved_type;
 
-       if (nfs_have_delegation(inode, FMODE_READ))
+       if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
                goto out_noconflict;
 
        if (is_local)
@@ -765,7 +753,7 @@ do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
         * This makes locking act as a cache coherency point.
         */
        nfs_sync_mapping(filp->f_mapping);
-       if (!nfs_have_delegation(inode, FMODE_READ)) {
+       if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) {
                if (is_time_granular(&NFS_SERVER(inode)->time_delta))
                        __nfs_revalidate_inode(NFS_SERVER(inode), inode);
                else
@@ -778,7 +766,7 @@ out:
 /*
  * Lock a (portion of) a file
  */
-static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
+int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
 {
        struct inode *inode = filp->f_mapping->host;
        int ret = -ENOLCK;
@@ -818,7 +806,7 @@ out_err:
 /*
  * Lock a (portion of) a file
  */
-static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
+int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
 {
        struct inode *inode = filp->f_mapping->host;
        int is_local = 0;
@@ -848,7 +836,7 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
  * There is no protocol support for leases, so we have no way to implement
  * them correctly in the face of opens by other clients.
  */
-static int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
+int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
 {
        dprintk("NFS: setlease(%s/%s, arg=%ld)\n",
                        file->f_path.dentry->d_parent->d_name.name,
@@ -874,104 +862,3 @@ const struct file_operations nfs_file_operations = {
        .check_flags    = nfs_check_flags,
        .setlease       = nfs_setlease,
 };
-
-#ifdef CONFIG_NFS_V4
-static int
-nfs4_file_open(struct inode *inode, struct file *filp)
-{
-       struct nfs_open_context *ctx;
-       struct dentry *dentry = filp->f_path.dentry;
-       struct dentry *parent = NULL;
-       struct inode *dir;
-       unsigned openflags = filp->f_flags;
-       struct iattr attr;
-       int err;
-
-       BUG_ON(inode != dentry->d_inode);
-       /*
-        * If no cached dentry exists or if it's negative, NFSv4 handled the
-        * opens in ->lookup() or ->create().
-        *
-        * We only get this far for a cached positive dentry.  We skipped
-        * revalidation, so handle it here by dropping the dentry and returning
-        * -EOPENSTALE.  The VFS will retry the lookup/create/open.
-        */
-
-       dprintk("NFS: open file(%s/%s)\n",
-               dentry->d_parent->d_name.name,
-               dentry->d_name.name);
-
-       if ((openflags & O_ACCMODE) == 3)
-               openflags--;
-
-       /* We can't create new files here */
-       openflags &= ~(O_CREAT|O_EXCL);
-
-       parent = dget_parent(dentry);
-       dir = parent->d_inode;
-
-       ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode);
-       err = PTR_ERR(ctx);
-       if (IS_ERR(ctx))
-               goto out;
-
-       attr.ia_valid = ATTR_OPEN;
-       if (openflags & O_TRUNC) {
-               attr.ia_valid |= ATTR_SIZE;
-               attr.ia_size = 0;
-               nfs_wb_all(inode);
-       }
-
-       inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
-       if (IS_ERR(inode)) {
-               err = PTR_ERR(inode);
-               switch (err) {
-               case -EPERM:
-               case -EACCES:
-               case -EDQUOT:
-               case -ENOSPC:
-               case -EROFS:
-                       goto out_put_ctx;
-               default:
-                       goto out_drop;
-               }
-       }
-       iput(inode);
-       if (inode != dentry->d_inode)
-               goto out_drop;
-
-       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-       nfs_file_set_open_context(filp, ctx);
-       err = 0;
-
-out_put_ctx:
-       put_nfs_open_context(ctx);
-out:
-       dput(parent);
-       return err;
-
-out_drop:
-       d_drop(dentry);
-       err = -EOPENSTALE;
-       goto out_put_ctx;
-}
-
-const struct file_operations nfs4_file_operations = {
-       .llseek         = nfs_file_llseek,
-       .read           = do_sync_read,
-       .write          = do_sync_write,
-       .aio_read       = nfs_file_read,
-       .aio_write      = nfs_file_write,
-       .mmap           = nfs_file_mmap,
-       .open           = nfs4_file_open,
-       .flush          = nfs_file_flush,
-       .release        = nfs_file_release,
-       .fsync          = nfs_file_fsync,
-       .lock           = nfs_lock,
-       .flock          = nfs_flock,
-       .splice_read    = nfs_file_splice_read,
-       .splice_write   = nfs_file_splice_write,
-       .check_flags    = nfs_check_flags,
-       .setlease       = nfs_setlease,
-};
-#endif /* CONFIG_NFS_V4 */
index a67990f90bd7d28bdea3310514e4a88275eadc14..4654ced096a644a50dbd0421eb68c7a76db9d791 100644 (file)
 #include <linux/sunrpc/stats.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
-#include <linux/nfs4_mount.h>
 #include <linux/lockd/bind.h>
 #include <linux/seq_file.h>
 #include <linux/mount.h>
-#include <linux/nfs_idmap.h>
 #include <linux/vfs.h>
 #include <linux/namei.h>
 #include <linux/security.h>
 
 #include <asm/uaccess.h>
 
-#include "nfs4_fs.h"
-#include "delegation.h"
-#include "internal.h"
-
 #define NFSDBG_FACILITY                NFSDBG_CLIENT
 
 /*
@@ -135,47 +129,3 @@ out:
        nfs_free_fattr(fsinfo.fattr);
        return ret;
 }
-
-#ifdef CONFIG_NFS_V4
-
-int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh)
-{
-       struct nfs_fsinfo fsinfo;
-       int ret = -ENOMEM;
-
-       dprintk("--> nfs4_get_rootfh()\n");
-
-       fsinfo.fattr = nfs_alloc_fattr();
-       if (fsinfo.fattr == NULL)
-               goto out;
-
-       /* Start by getting the root filehandle from the server */
-       ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo);
-       if (ret < 0) {
-               dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret);
-               goto out;
-       }
-
-       if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE)
-                       || !S_ISDIR(fsinfo.fattr->mode)) {
-               printk(KERN_ERR "nfs4_get_rootfh:"
-                      " getroot encountered non-directory\n");
-               ret = -ENOTDIR;
-               goto out;
-       }
-
-       if (fsinfo.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
-               printk(KERN_ERR "nfs4_get_rootfh:"
-                      " getroot obtained referral\n");
-               ret = -EREMOTE;
-               goto out;
-       }
-
-       memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid));
-out:
-       nfs_free_fattr(fsinfo.fattr);
-       dprintk("<-- nfs4_get_rootfh() = %d\n", ret);
-       return ret;
-}
-
-#endif /* CONFIG_NFS_V4 */
index f7296983eba60c5ea21f164600be800ea988977f..35f7e4bc680ed1205f4d846f8649c7f77b712c20 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/lockd/bind.h>
 #include <linux/seq_file.h>
 #include <linux/mount.h>
-#include <linux/nfs_idmap.h>
 #include <linux/vfs.h>
 #include <linux/inet.h>
 #include <linux/nfs_xdr.h>
@@ -430,7 +429,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
         * Return any delegations if we're going to change ACLs
         */
        if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0)
-               nfs_inode_return_delegation(inode);
+               NFS_PROTO(inode)->return_delegation(inode);
        error = NFS_PROTO(inode)->setattr(dentry, fattr, attr);
        if (error == 0)
                nfs_refresh_inode(inode, fattr);
@@ -1457,7 +1456,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
                                || S_ISLNK(inode->i_mode)))
                invalid &= ~NFS_INO_INVALID_DATA;
-       if (!nfs_have_delegation(inode, FMODE_READ) ||
+       if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ) ||
                        (save_cache_validity & NFS_INO_REVAL_FORCED))
                nfsi->cache_validity |= invalid;
 
@@ -1628,87 +1627,96 @@ static int __init init_nfs_fs(void)
 {
        int err;
 
-       err = nfs_idmap_init();
-       if (err < 0)
-               goto out10;
-
        err = nfs_dns_resolver_init();
        if (err < 0)
-               goto out9;
+               goto out11;
 
        err = register_pernet_subsys(&nfs_net_ops);
        if (err < 0)
-               goto out8;
+               goto out10;
 
        err = nfs_fscache_register();
        if (err < 0)
-               goto out7;
+               goto out9;
 
        err = nfsiod_start();
        if (err)
-               goto out6;
+               goto out8;
 
        err = nfs_fs_proc_init();
        if (err)
-               goto out5;
+               goto out7;
 
        err = nfs_init_nfspagecache();
        if (err)
-               goto out4;
+               goto out6;
 
        err = nfs_init_inodecache();
        if (err)
-               goto out3;
+               goto out5;
 
        err = nfs_init_readpagecache();
        if (err)
-               goto out2;
+               goto out4;
 
        err = nfs_init_writepagecache();
        if (err)
-               goto out1;
+               goto out3;
 
        err = nfs_init_directcache();
        if (err)
-               goto out0;
+               goto out2;
 
 #ifdef CONFIG_PROC_FS
        rpc_proc_register(&init_net, &nfs_rpcstat);
 #endif
+
+#ifdef CONFIG_NFS_V4
+       err = init_nfs_v4();
+       if (err)
+               goto out1;
+#endif
+
        if ((err = register_nfs_fs()) != 0)
-               goto out;
+               goto out0;
+
        return 0;
-out:
+out0:
+#ifdef CONFIG_NFS_V4
+       exit_nfs_v4();
+out1:
+#endif
 #ifdef CONFIG_PROC_FS
        rpc_proc_unregister(&init_net, "nfs");
 #endif
        nfs_destroy_directcache();
-out0:
-       nfs_destroy_writepagecache();
-out1:
-       nfs_destroy_readpagecache();
 out2:
-       nfs_destroy_inodecache();
+       nfs_destroy_writepagecache();
 out3:
-       nfs_destroy_nfspagecache();
+       nfs_destroy_readpagecache();
 out4:
-       nfs_fs_proc_exit();
+       nfs_destroy_inodecache();
 out5:
-       nfsiod_stop();
+       nfs_destroy_nfspagecache();
 out6:
-       nfs_fscache_unregister();
+       nfs_fs_proc_exit();
 out7:
-       unregister_pernet_subsys(&nfs_net_ops);
+       nfsiod_stop();
 out8:
-       nfs_dns_resolver_destroy();
+       nfs_fscache_unregister();
 out9:
-       nfs_idmap_quit();
+       unregister_pernet_subsys(&nfs_net_ops);
 out10:
+       nfs_dns_resolver_destroy();
+out11:
        return err;
 }
 
 static void __exit exit_nfs_fs(void)
 {
+#ifdef CONFIG_NFS_V4
+       exit_nfs_v4();
+#endif
        nfs_destroy_directcache();
        nfs_destroy_writepagecache();
        nfs_destroy_readpagecache();
@@ -1717,7 +1725,6 @@ static void __exit exit_nfs_fs(void)
        nfs_fscache_unregister();
        unregister_pernet_subsys(&nfs_net_ops);
        nfs_dns_resolver_destroy();
-       nfs_idmap_quit();
 #ifdef CONFIG_PROC_FS
        rpc_proc_unregister(&init_net, "nfs");
 #endif
index 18f99ef7134387128507e8ffd93fff6943b241d6..cfafd13b6fe96ed4646c8ee7da9b89629d392029 100644 (file)
@@ -85,6 +85,17 @@ struct nfs_clone_mount {
  */
 #define NFS_MAX_READDIR_PAGES 8
 
+struct nfs_client_initdata {
+       unsigned long init_flags;
+       const char *hostname;
+       const struct sockaddr *addr;
+       size_t addrlen;
+       const struct nfs_rpc_ops *rpc_ops;
+       int proto;
+       u32 minorversion;
+       struct net *net;
+};
+
 /*
  * In-kernel mount arguments
  */
@@ -142,15 +153,36 @@ struct nfs_mount_request {
        struct net              *net;
 };
 
+struct nfs_mount_info {
+       void (*fill_super)(struct super_block *, struct nfs_mount_info *);
+       int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *);
+       struct nfs_parsed_mount_data *parsed;
+       struct nfs_clone_mount *cloned;
+       struct nfs_fh *mntfh;
+};
+
 extern int nfs_mount(struct nfs_mount_request *info);
 extern void nfs_umount(const struct nfs_mount_request *info);
 
 /* client.c */
 extern const struct rpc_program nfs_program;
 extern void nfs_clients_init(struct net *net);
+extern struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *);
+int nfs_create_rpc_client(struct nfs_client *, const struct rpc_timeout *, rpc_authflavor_t);
+struct nfs_client *nfs_get_client(const struct nfs_client_initdata *,
+                                 const struct rpc_timeout *, const char *,
+                                 rpc_authflavor_t);
+int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *);
+void nfs_server_insert_lists(struct nfs_server *);
+void nfs_init_timeout_values(struct rpc_timeout *, int, unsigned int, unsigned int);
+int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t,
+               rpc_authflavor_t);
+struct nfs_server *nfs_alloc_server(void);
+void nfs_server_copy_userdata(struct nfs_server *, struct nfs_server *);
 
 extern void nfs_cleanup_cb_ident_idr(struct net *);
 extern void nfs_put_client(struct nfs_client *);
+extern void nfs_free_client(struct nfs_client *);
 extern struct nfs_client *nfs4_find_client_ident(struct net *, int);
 extern struct nfs_client *
 nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
@@ -188,6 +220,10 @@ static inline void nfs_fs_proc_exit(void)
 }
 #endif
 
+#ifdef CONFIG_NFS_V4_1
+int nfs_sockaddr_match_ipaddr(const struct sockaddr *, const struct sockaddr *);
+#endif
+
 /* callback_xdr.c */
 extern struct svc_version nfs4_callback_version1;
 extern struct svc_version nfs4_callback_version4;
@@ -245,6 +281,32 @@ extern struct nfs_client *nfs_init_client(struct nfs_client *clp,
 /* dir.c */
 extern int nfs_access_cache_shrinker(struct shrinker *shrink,
                                        struct shrink_control *sc);
+struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int);
+int nfs_create(struct inode *, struct dentry *, umode_t, bool);
+int nfs_mkdir(struct inode *, struct dentry *, umode_t);
+int nfs_rmdir(struct inode *, struct dentry *);
+int nfs_unlink(struct inode *, struct dentry *);
+int nfs_symlink(struct inode *, struct dentry *, const char *);
+int nfs_link(struct dentry *, struct inode *, struct dentry *);
+int nfs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
+int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+
+/* file.c */
+int nfs_file_fsync_commit(struct file *, loff_t, loff_t, int);
+loff_t nfs_file_llseek(struct file *, loff_t, int);
+int nfs_file_flush(struct file *, fl_owner_t);
+ssize_t nfs_file_read(struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ssize_t nfs_file_splice_read(struct file *, loff_t *, struct pipe_inode_info *,
+                            size_t, unsigned int);
+int nfs_file_mmap(struct file *, struct vm_area_struct *);
+ssize_t nfs_file_write(struct kiocb *, const struct iovec *, unsigned long, loff_t);
+int nfs_file_release(struct inode *, struct file *);
+int nfs_lock(struct file *, int, struct file_lock *);
+int nfs_flock(struct file *, int, struct file_lock *);
+ssize_t nfs_file_splice_write(struct pipe_inode_info *, struct file *, loff_t *,
+                             size_t, unsigned int);
+int nfs_check_flags(int);
+int nfs_setlease(struct file *, long, struct file_lock **);
 
 /* inode.c */
 extern struct workqueue_struct *nfsiod_workqueue;
@@ -264,6 +326,16 @@ extern struct file_system_type nfs_xdev_fs_type;
 extern struct file_system_type nfs4_xdev_fs_type;
 extern struct file_system_type nfs4_referral_fs_type;
 #endif
+void nfs_initialise_sb(struct super_block *);
+int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *);
+int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *);
+struct dentry *nfs_fs_mount_common(struct file_system_type *, struct nfs_server *,
+                                  int, const char *, struct nfs_mount_info *);
+struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *);
+struct dentry * nfs_xdev_mount_common(struct file_system_type *, int,
+               const char *, struct nfs_mount_info *);
+void nfs_kill_super(struct super_block *);
+void nfs_fill_super(struct super_block *, struct nfs_mount_info *);
 
 extern struct rpc_stat nfs_rpcstat;
 
@@ -304,12 +376,23 @@ extern int nfs_initiate_read(struct rpc_clnt *clnt,
 extern void nfs_read_prepare(struct rpc_task *task, void *calldata);
 extern int nfs_generic_pagein(struct nfs_pageio_descriptor *desc,
                              struct nfs_pgio_header *hdr);
-extern void nfs_pageio_init_read_mds(struct nfs_pageio_descriptor *pgio,
+extern void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
                        struct inode *inode,
                        const struct nfs_pgio_completion_ops *compl_ops);
 extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio);
 extern void nfs_readdata_release(struct nfs_read_data *rdata);
 
+/* super.c */
+void nfs_clone_super(struct super_block *, struct nfs_mount_info *);
+void nfs_umount_begin(struct super_block *);
+int  nfs_statfs(struct dentry *, struct kstatfs *);
+int  nfs_show_options(struct seq_file *, struct dentry *);
+int  nfs_show_devname(struct seq_file *, struct dentry *);
+int  nfs_show_path(struct seq_file *, struct dentry *);
+int  nfs_show_stats(struct seq_file *, struct dentry *);
+void nfs_put_super(struct super_block *);
+int nfs_remount(struct super_block *sb, int *flags, char *raw_data);
+
 /* write.c */
 extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
                        struct inode *inode, int ioflags,
@@ -318,7 +401,7 @@ extern struct nfs_write_header *nfs_writehdr_alloc(void);
 extern void nfs_writehdr_free(struct nfs_pgio_header *hdr);
 extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc,
                             struct nfs_pgio_header *hdr);
-extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio,
+extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
                        struct inode *inode, int ioflags,
                        const struct nfs_pgio_completion_ops *compl_ops);
 extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio);
index baf759bccd054d562d24d9adf43af18915da8267..d04f0df7be553db3aa89ce5637ff3c8ef3044d07 100644 (file)
@@ -106,19 +106,16 @@ static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
 static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result)
 {
        u32 recvd, count;
-       size_t hdrlen;
        __be32 *p;
 
        p = xdr_inline_decode(xdr, 4);
        if (unlikely(p == NULL))
                goto out_overflow;
        count = be32_to_cpup(p);
-       hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
-       recvd = xdr->buf->len - hdrlen;
+       recvd = xdr_read_pages(xdr, count);
        if (unlikely(count > recvd))
                goto out_cheating;
 out:
-       xdr_read_pages(xdr, count);
        result->eof = 0;        /* NFSv2 does not pass EOF flag on the wire. */
        result->count = count;
        return count;
@@ -440,7 +437,6 @@ static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
 static int decode_path(struct xdr_stream *xdr)
 {
        u32 length, recvd;
-       size_t hdrlen;
        __be32 *p;
 
        p = xdr_inline_decode(xdr, 4);
@@ -449,12 +445,9 @@ static int decode_path(struct xdr_stream *xdr)
        length = be32_to_cpup(p);
        if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
                goto out_size;
-       hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
-       recvd = xdr->buf->len - hdrlen;
+       recvd = xdr_read_pages(xdr, length);
        if (unlikely(length > recvd))
                goto out_cheating;
-
-       xdr_read_pages(xdr, length);
        xdr_terminate_string(xdr->buf, length);
        return 0;
 out_size:
@@ -972,22 +965,7 @@ out_overflow:
  */
 static int decode_readdirok(struct xdr_stream *xdr)
 {
-       u32 recvd, pglen;
-       size_t hdrlen;
-
-       pglen = xdr->buf->page_len;
-       hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
-       recvd = xdr->buf->len - hdrlen;
-       if (unlikely(pglen > recvd))
-               goto out_cheating;
-out:
-       xdr_read_pages(xdr, pglen);
-       return pglen;
-out_cheating:
-       dprintk("NFS: server cheating in readdir result: "
-               "pglen %u > recvd %u\n", pglen, recvd);
-       pglen = recvd;
-       goto out;
+       return xdr_read_pages(xdr, xdr->buf->page_len);
 }
 
 static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req,
index 3187e24e8f78f41ffa3f78b55ccf42ff29d167f0..65d23eb92fe03650dee0dda65d3e81d6e30ae0b7 100644 (file)
@@ -877,6 +877,46 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
        return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl);
 }
 
+static int nfs3_have_delegation(struct inode *inode, fmode_t flags)
+{
+       return 0;
+}
+
+static int nfs3_return_delegation(struct inode *inode)
+{
+       nfs_wb_all(inode);
+       return 0;
+}
+
+static const struct inode_operations nfs3_dir_inode_operations = {
+       .create         = nfs_create,
+       .lookup         = nfs_lookup,
+       .link           = nfs_link,
+       .unlink         = nfs_unlink,
+       .symlink        = nfs_symlink,
+       .mkdir          = nfs_mkdir,
+       .rmdir          = nfs_rmdir,
+       .mknod          = nfs_mknod,
+       .rename         = nfs_rename,
+       .permission     = nfs_permission,
+       .getattr        = nfs_getattr,
+       .setattr        = nfs_setattr,
+       .listxattr      = nfs3_listxattr,
+       .getxattr       = nfs3_getxattr,
+       .setxattr       = nfs3_setxattr,
+       .removexattr    = nfs3_removexattr,
+};
+
+static const struct inode_operations nfs3_file_inode_operations = {
+       .permission     = nfs_permission,
+       .getattr        = nfs_getattr,
+       .setattr        = nfs_setattr,
+       .listxattr      = nfs3_listxattr,
+       .getxattr       = nfs3_getxattr,
+       .setxattr       = nfs3_setxattr,
+       .removexattr    = nfs3_removexattr,
+};
+
 const struct nfs_rpc_ops nfs_v3_clientops = {
        .version        = 3,                    /* protocol version */
        .dentry_ops     = &nfs_dentry_operations,
@@ -910,9 +950,11 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
        .pathconf       = nfs3_proc_pathconf,
        .decode_dirent  = nfs3_decode_dirent,
        .read_setup     = nfs3_proc_read_setup,
+       .read_pageio_init = nfs_pageio_init_read,
        .read_rpc_prepare = nfs3_proc_read_rpc_prepare,
        .read_done      = nfs3_read_done,
        .write_setup    = nfs3_proc_write_setup,
+       .write_pageio_init = nfs_pageio_init_write,
        .write_rpc_prepare = nfs3_proc_write_rpc_prepare,
        .write_done     = nfs3_write_done,
        .commit_setup   = nfs3_proc_commit_setup,
@@ -921,5 +963,9 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
        .lock           = nfs3_proc_lock,
        .clear_acl_cache = nfs3_forget_cached_acls,
        .close_context  = nfs_close_context,
+       .have_delegation = nfs3_have_delegation,
+       .return_delegation = nfs3_return_delegation,
+       .alloc_client   = nfs_alloc_client,
        .init_client    = nfs_init_client,
+       .free_client    = nfs_free_client,
 };
index 902de489ec9bac793dd2e3fa65b663262879b271..6cbe89400dfcc134b9af58d6ad16ecf42bab911a 100644 (file)
@@ -246,7 +246,6 @@ static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
 static int decode_nfspath3(struct xdr_stream *xdr)
 {
        u32 recvd, count;
-       size_t hdrlen;
        __be32 *p;
 
        p = xdr_inline_decode(xdr, 4);
@@ -255,12 +254,9 @@ static int decode_nfspath3(struct xdr_stream *xdr)
        count = be32_to_cpup(p);
        if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN))
                goto out_nametoolong;
-       hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
-       recvd = xdr->buf->len - hdrlen;
+       recvd = xdr_read_pages(xdr, count);
        if (unlikely(count > recvd))
                goto out_cheating;
-
-       xdr_read_pages(xdr, count);
        xdr_terminate_string(xdr->buf, count);
        return 0;
 
@@ -329,14 +325,14 @@ static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
        memcpy(p, verifier, NFS3_CREATEVERFSIZE);
 }
 
-static int decode_writeverf3(struct xdr_stream *xdr, __be32 *verifier)
+static int decode_writeverf3(struct xdr_stream *xdr, struct nfs_write_verifier *verifier)
 {
        __be32 *p;
 
        p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE);
        if (unlikely(p == NULL))
                goto out_overflow;
-       memcpy(verifier, p, NFS3_WRITEVERFSIZE);
+       memcpy(verifier->data, p, NFS3_WRITEVERFSIZE);
        return 0;
 out_overflow:
        print_overflow_msg(__func__, xdr);
@@ -1587,7 +1583,6 @@ static int decode_read3resok(struct xdr_stream *xdr,
                             struct nfs_readres *result)
 {
        u32 eof, count, ocount, recvd;
-       size_t hdrlen;
        __be32 *p;
 
        p = xdr_inline_decode(xdr, 4 + 4 + 4);
@@ -1598,13 +1593,10 @@ static int decode_read3resok(struct xdr_stream *xdr,
        ocount = be32_to_cpup(p++);
        if (unlikely(ocount != count))
                goto out_mismatch;
-       hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
-       recvd = xdr->buf->len - hdrlen;
+       recvd = xdr_read_pages(xdr, count);
        if (unlikely(count > recvd))
                goto out_cheating;
-
 out:
-       xdr_read_pages(xdr, count);
        result->eof = eof;
        result->count = count;
        return count;
@@ -1676,20 +1668,22 @@ static int decode_write3resok(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       p = xdr_inline_decode(xdr, 4 + 4 + NFS3_WRITEVERFSIZE);
+       p = xdr_inline_decode(xdr, 4 + 4);
        if (unlikely(p == NULL))
                goto out_overflow;
        result->count = be32_to_cpup(p++);
        result->verf->committed = be32_to_cpup(p++);
        if (unlikely(result->verf->committed > NFS_FILE_SYNC))
                goto out_badvalue;
-       memcpy(result->verf->verifier, p, NFS3_WRITEVERFSIZE);
+       if (decode_writeverf3(xdr, &result->verf->verifier))
+               goto out_eio;
        return result->count;
 out_badvalue:
        dprintk("NFS: bad stable_how value: %u\n", result->verf->committed);
        return -EIO;
 out_overflow:
        print_overflow_msg(__func__, xdr);
+out_eio:
        return -EIO;
 }
 
@@ -2039,22 +2033,7 @@ out_truncated:
  */
 static int decode_dirlist3(struct xdr_stream *xdr)
 {
-       u32 recvd, pglen;
-       size_t hdrlen;
-
-       pglen = xdr->buf->page_len;
-       hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
-       recvd = xdr->buf->len - hdrlen;
-       if (unlikely(pglen > recvd))
-               goto out_cheating;
-out:
-       xdr_read_pages(xdr, pglen);
-       return pglen;
-out_cheating:
-       dprintk("NFS: server cheating in readdir result: "
-               "pglen %u > recvd %u\n", pglen, recvd);
-       pglen = recvd;
-       goto out;
+       return xdr_read_pages(xdr, xdr->buf->page_len);
 }
 
 static int decode_readdir3resok(struct xdr_stream *xdr,
@@ -2337,7 +2316,7 @@ static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
                goto out;
        if (status != NFS3_OK)
                goto out_status;
-       error = decode_writeverf3(xdr, result->verf->verifier);
+       error = decode_writeverf3(xdr, &result->verf->verifier);
 out:
        return error;
 out_status:
@@ -2364,7 +2343,7 @@ static inline int decode_getacl3resok(struct xdr_stream *xdr,
        if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
                goto out;
 
-       hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
+       hdrlen = xdr_stream_pos(xdr);
 
        acl = NULL;
        if (result->mask & NFS_ACL)
index cc5900ac61b584774de45f10c48906b3ff99de74..5511690de8a583aec9b6a79915eb049b8544ea49 100644 (file)
@@ -200,7 +200,13 @@ struct nfs4_state_maintenance_ops {
 };
 
 extern const struct dentry_operations nfs4_dentry_operations;
-extern const struct inode_operations nfs4_dir_inode_operations;
+
+/* dir.c */
+int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
+                   unsigned, umode_t, int *);
+
+/* write.c */
+int nfs4_write_inode(struct inode *, struct writeback_control *);
 
 /* nfs4namespace.c */
 rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *);
@@ -301,6 +307,10 @@ extern const u32 nfs4_pathconf_bitmap[2];
 extern const u32 nfs4_fsinfo_bitmap[3];
 extern const u32 nfs4_fs_locations_bitmap[2];
 
+void nfs4_free_client(struct nfs_client *);
+
+struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *);
+
 /* nfs4renewd.c */
 extern void nfs4_schedule_state_renewal(struct nfs_client *);
 extern void nfs4_renewd_prepare_shutdown(struct nfs_server *);
@@ -354,6 +364,27 @@ extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_sta
 
 extern const nfs4_stateid zero_stateid;
 
+/* nfs4super.c */
+struct nfs_mount_info;
+struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *);
+int init_nfs_v4(void);
+void exit_nfs_v4(void);
+
+/* nfs4sysctl.c */
+#ifdef CONFIG_SYSCTL
+int nfs4_register_sysctl(void);
+void nfs4_unregister_sysctl(void);
+#else
+static inline int nfs4_register_sysctl(void)
+{
+       return 0;
+}
+
+static inline void nfs4_unregister_sysctl(void)
+{
+}
+#endif
+
 /* nfs4xdr.c */
 extern struct rpc_procinfo nfs4_procedures[];
 
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
new file mode 100644 (file)
index 0000000..1c3f13c
--- /dev/null
@@ -0,0 +1,663 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+#include <linux/module.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_idmap.h>
+#include <linux/nfs_mount.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/xprt.h>
+#include <linux/sunrpc/bc_xprt.h>
+#include "internal.h"
+#include "callback.h"
+#include "delegation.h"
+#include "pnfs.h"
+#include "netns.h"
+
+#define NFSDBG_FACILITY                NFSDBG_CLIENT
+
+/*
+ * Turn off NFSv4 uid/gid mapping when using AUTH_SYS
+ */
+static bool nfs4_disable_idmapping = true;
+
+/*
+ * Get a unique NFSv4.0 callback identifier which will be used
+ * by the V4.0 callback service to lookup the nfs_client struct
+ */
+static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
+{
+       int ret = 0;
+       struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
+
+       if (clp->rpc_ops->version != 4 || minorversion != 0)
+               return ret;
+retry:
+       if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL))
+               return -ENOMEM;
+       spin_lock(&nn->nfs_client_lock);
+       ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident);
+       spin_unlock(&nn->nfs_client_lock);
+       if (ret == -EAGAIN)
+               goto retry;
+       return ret;
+}
+
+#ifdef CONFIG_NFS_V4_1
+static void nfs4_shutdown_session(struct nfs_client *clp)
+{
+       if (nfs4_has_session(clp)) {
+               nfs4_destroy_session(clp->cl_session);
+               nfs4_destroy_clientid(clp);
+       }
+
+}
+#else /* CONFIG_NFS_V4_1 */
+static void nfs4_shutdown_session(struct nfs_client *clp)
+{
+}
+#endif /* CONFIG_NFS_V4_1 */
+
+struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
+{
+       int err;
+       struct nfs_client *clp = nfs_alloc_client(cl_init);
+       if (IS_ERR(clp))
+               return clp;
+
+       err = nfs_get_cb_ident_idr(clp, cl_init->minorversion);
+       if (err)
+               goto error;
+
+       spin_lock_init(&clp->cl_lock);
+       INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
+       rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
+       clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
+       clp->cl_minorversion = cl_init->minorversion;
+       clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion];
+       return clp;
+
+error:
+       kfree(clp);
+       return ERR_PTR(err);
+}
+
+/*
+ * Destroy the NFS4 callback service
+ */
+static void nfs4_destroy_callback(struct nfs_client *clp)
+{
+       if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
+               nfs_callback_down(clp->cl_mvops->minor_version);
+}
+
+static void nfs4_shutdown_client(struct nfs_client *clp)
+{
+       if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
+               nfs4_kill_renewd(clp);
+       nfs4_shutdown_session(clp);
+       nfs4_destroy_callback(clp);
+       if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
+               nfs_idmap_delete(clp);
+
+       rpc_destroy_wait_queue(&clp->cl_rpcwaitq);
+       kfree(clp->cl_serverowner);
+       kfree(clp->cl_serverscope);
+       kfree(clp->cl_implid);
+}
+
+void nfs4_free_client(struct nfs_client *clp)
+{
+       nfs4_shutdown_client(clp);
+       nfs_free_client(clp);
+}
+
+/*
+ * Initialize the NFS4 callback service
+ */
+static int nfs4_init_callback(struct nfs_client *clp)
+{
+       int error;
+
+       if (clp->rpc_ops->version == 4) {
+               struct rpc_xprt *xprt;
+
+               xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
+
+               if (nfs4_has_session(clp)) {
+                       error = xprt_setup_backchannel(xprt,
+                                               NFS41_BC_MIN_CALLBACKS);
+                       if (error < 0)
+                               return error;
+               }
+
+               error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
+               if (error < 0) {
+                       dprintk("%s: failed to start callback. Error = %d\n",
+                               __func__, error);
+                       return error;
+               }
+               __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
+       }
+       return 0;
+}
+
+/*
+ * Initialize the minor version specific parts of an NFS4 client record
+ */
+static int nfs4_init_client_minor_version(struct nfs_client *clp)
+{
+#if defined(CONFIG_NFS_V4_1)
+       if (clp->cl_mvops->minor_version) {
+               struct nfs4_session *session = NULL;
+               /*
+                * Create the session and mark it expired.
+                * When a SEQUENCE operation encounters the expired session
+                * it will do session recovery to initialize it.
+                */
+               session = nfs4_alloc_session(clp);
+               if (!session)
+                       return -ENOMEM;
+
+               clp->cl_session = session;
+               /*
+                * The create session reply races with the server back
+                * channel probe. Mark the client NFS_CS_SESSION_INITING
+                * so that the client back channel can find the
+                * nfs_client struct
+                */
+               nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING);
+       }
+#endif /* CONFIG_NFS_V4_1 */
+
+       return nfs4_init_callback(clp);
+}
+
+/**
+ * nfs4_init_client - Initialise an NFS4 client record
+ *
+ * @clp: nfs_client to initialise
+ * @timeparms: timeout parameters for underlying RPC transport
+ * @ip_addr: callback IP address in presentation format
+ * @authflavor: authentication flavor for underlying RPC transport
+ *
+ * Returns pointer to an NFS client, or an ERR_PTR value.
+ */
+struct nfs_client *nfs4_init_client(struct nfs_client *clp,
+                                   const struct rpc_timeout *timeparms,
+                                   const char *ip_addr,
+                                   rpc_authflavor_t authflavour)
+{
+       char buf[INET6_ADDRSTRLEN + 1];
+       int error;
+
+       if (clp->cl_cons_state == NFS_CS_READY) {
+               /* the client is initialised already */
+               dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp);
+               return clp;
+       }
+
+       /* Check NFS protocol revision and initialize RPC op vector */
+       clp->rpc_ops = &nfs_v4_clientops;
+
+       __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
+       error = nfs_create_rpc_client(clp, timeparms, authflavour);
+       if (error < 0)
+               goto error;
+
+       /* If no clientaddr= option was specified, find a usable cb address */
+       if (ip_addr == NULL) {
+               struct sockaddr_storage cb_addr;
+               struct sockaddr *sap = (struct sockaddr *)&cb_addr;
+
+               error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr));
+               if (error < 0)
+                       goto error;
+               error = rpc_ntop(sap, buf, sizeof(buf));
+               if (error < 0)
+                       goto error;
+               ip_addr = (const char *)buf;
+       }
+       strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
+
+       error = nfs_idmap_new(clp);
+       if (error < 0) {
+               dprintk("%s: failed to create idmapper. Error = %d\n",
+                       __func__, error);
+               goto error;
+       }
+       __set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
+
+       error = nfs4_init_client_minor_version(clp);
+       if (error < 0)
+               goto error;
+
+       if (!nfs4_has_session(clp))
+               nfs_mark_client_ready(clp, NFS_CS_READY);
+       return clp;
+
+error:
+       nfs_mark_client_ready(clp, error);
+       nfs_put_client(clp);
+       dprintk("<-- nfs4_init_client() = xerror %d\n", error);
+       return ERR_PTR(error);
+}
+
+static void nfs4_destroy_server(struct nfs_server *server)
+{
+       nfs_server_return_all_delegations(server);
+       unset_pnfs_layoutdriver(server);
+       nfs4_purge_state_owners(server);
+}
+
+/*
+ * NFSv4.0 callback thread helper
+ *
+ * Find a client by callback identifier
+ */
+struct nfs_client *
+nfs4_find_client_ident(struct net *net, int cb_ident)
+{
+       struct nfs_client *clp;
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+       spin_lock(&nn->nfs_client_lock);
+       clp = idr_find(&nn->cb_ident_idr, cb_ident);
+       if (clp)
+               atomic_inc(&clp->cl_count);
+       spin_unlock(&nn->nfs_client_lock);
+       return clp;
+}
+
+#if defined(CONFIG_NFS_V4_1)
+/* Common match routine for v4.0 and v4.1 callback services */
+static bool nfs4_cb_match_client(const struct sockaddr *addr,
+               struct nfs_client *clp, u32 minorversion)
+{
+       struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
+
+       /* Don't match clients that failed to initialise */
+       if (!(clp->cl_cons_state == NFS_CS_READY ||
+           clp->cl_cons_state == NFS_CS_SESSION_INITING))
+               return false;
+
+       smp_rmb();
+
+       /* Match the version and minorversion */
+       if (clp->rpc_ops->version != 4 ||
+           clp->cl_minorversion != minorversion)
+               return false;
+
+       /* Match only the IP address, not the port number */
+       if (!nfs_sockaddr_match_ipaddr(addr, clap))
+               return false;
+
+       return true;
+}
+
+/*
+ * NFSv4.1 callback thread helper
+ * For CB_COMPOUND calls, find a client by IP address, protocol version,
+ * minorversion, and sessionID
+ *
+ * Returns NULL if no such client
+ */
+struct nfs_client *
+nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
+                          struct nfs4_sessionid *sid)
+{
+       struct nfs_client *clp;
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+       spin_lock(&nn->nfs_client_lock);
+       list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
+               if (nfs4_cb_match_client(addr, clp, 1) == false)
+                       continue;
+
+               if (!nfs4_has_session(clp))
+                       continue;
+
+               /* Match sessionid*/
+               if (memcmp(clp->cl_session->sess_id.data,
+                   sid->data, NFS4_MAX_SESSIONID_LEN) != 0)
+                       continue;
+
+               atomic_inc(&clp->cl_count);
+               spin_unlock(&nn->nfs_client_lock);
+               return clp;
+       }
+       spin_unlock(&nn->nfs_client_lock);
+       return NULL;
+}
+
+#else /* CONFIG_NFS_V4_1 */
+
+struct nfs_client *
+nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
+                          struct nfs4_sessionid *sid)
+{
+       return NULL;
+}
+#endif /* CONFIG_NFS_V4_1 */
+
+/*
+ * Set up an NFS4 client
+ */
+static int nfs4_set_client(struct nfs_server *server,
+               const char *hostname,
+               const struct sockaddr *addr,
+               const size_t addrlen,
+               const char *ip_addr,
+               rpc_authflavor_t authflavour,
+               int proto, const struct rpc_timeout *timeparms,
+               u32 minorversion, struct net *net)
+{
+       struct nfs_client_initdata cl_init = {
+               .hostname = hostname,
+               .addr = addr,
+               .addrlen = addrlen,
+               .rpc_ops = &nfs_v4_clientops,
+               .proto = proto,
+               .minorversion = minorversion,
+               .net = net,
+       };
+       struct nfs_client *clp;
+       int error;
+
+       dprintk("--> nfs4_set_client()\n");
+
+       if (server->flags & NFS_MOUNT_NORESVPORT)
+               set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
+
+       /* Allocate or find a client reference we can use */
+       clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour);
+       if (IS_ERR(clp)) {
+               error = PTR_ERR(clp);
+               goto error;
+       }
+
+       /*
+        * Query for the lease time on clientid setup or renewal
+        *
+        * Note that this will be set on nfs_clients that were created
+        * only for the DS role and did not set this bit, but now will
+        * serve a dual role.
+        */
+       set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state);
+
+       server->nfs_client = clp;
+       dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp);
+       return 0;
+error:
+       dprintk("<-- nfs4_set_client() = xerror %d\n", error);
+       return error;
+}
+
+/*
+ * Set up a pNFS Data Server client.
+ *
+ * Return any existing nfs_client that matches server address,port,version
+ * and minorversion.
+ *
+ * For a new nfs_client, use a soft mount (default), a low retrans and a
+ * low timeout interval so that if a connection is lost, we retry through
+ * the MDS.
+ */
+struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
+               const struct sockaddr *ds_addr, int ds_addrlen,
+               int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans)
+{
+       struct nfs_client_initdata cl_init = {
+               .addr = ds_addr,
+               .addrlen = ds_addrlen,
+               .rpc_ops = &nfs_v4_clientops,
+               .proto = ds_proto,
+               .minorversion = mds_clp->cl_minorversion,
+               .net = mds_clp->cl_net,
+       };
+       struct rpc_timeout ds_timeout;
+       struct nfs_client *clp;
+
+       /*
+        * Set an authflavor equual to the MDS value. Use the MDS nfs_client
+        * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS
+        * (section 13.1 RFC 5661).
+        */
+       nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans);
+       clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr,
+                            mds_clp->cl_rpcclient->cl_auth->au_flavor);
+
+       dprintk("<-- %s %p\n", __func__, clp);
+       return clp;
+}
+EXPORT_SYMBOL_GPL(nfs4_set_ds_client);
+
+/*
+ * Session has been established, and the client marked ready.
+ * Set the mount rsize and wsize with negotiated fore channel
+ * attributes which will be bound checked in nfs_server_set_fsinfo.
+ */
+static void nfs4_session_set_rwsize(struct nfs_server *server)
+{
+#ifdef CONFIG_NFS_V4_1
+       struct nfs4_session *sess;
+       u32 server_resp_sz;
+       u32 server_rqst_sz;
+
+       if (!nfs4_has_session(server->nfs_client))
+               return;
+       sess = server->nfs_client->cl_session;
+       server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead;
+       server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead;
+
+       if (server->rsize > server_resp_sz)
+               server->rsize = server_resp_sz;
+       if (server->wsize > server_rqst_sz)
+               server->wsize = server_rqst_sz;
+#endif /* CONFIG_NFS_V4_1 */
+}
+
+static int nfs4_server_common_setup(struct nfs_server *server,
+               struct nfs_fh *mntfh)
+{
+       struct nfs_fattr *fattr;
+       int error;
+
+       BUG_ON(!server->nfs_client);
+       BUG_ON(!server->nfs_client->rpc_ops);
+       BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
+
+       /* data servers support only a subset of NFSv4.1 */
+       if (is_ds_only_client(server->nfs_client))
+               return -EPROTONOSUPPORT;
+
+       fattr = nfs_alloc_fattr();
+       if (fattr == NULL)
+               return -ENOMEM;
+
+       /* We must ensure the session is initialised first */
+       error = nfs4_init_session(server);
+       if (error < 0)
+               goto out;
+
+       /* Probe the root fh to retrieve its FSID and filehandle */
+       error = nfs4_get_rootfh(server, mntfh);
+       if (error < 0)
+               goto out;
+
+       dprintk("Server FSID: %llx:%llx\n",
+                       (unsigned long long) server->fsid.major,
+                       (unsigned long long) server->fsid.minor);
+       dprintk("Mount FH: %d\n", mntfh->size);
+
+       nfs4_session_set_rwsize(server);
+
+       error = nfs_probe_fsinfo(server, mntfh, fattr);
+       if (error < 0)
+               goto out;
+
+       if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
+               server->namelen = NFS4_MAXNAMLEN;
+
+       nfs_server_insert_lists(server);
+       server->mount_time = jiffies;
+       server->destroy = nfs4_destroy_server;
+out:
+       nfs_free_fattr(fattr);
+       return error;
+}
+
+/*
+ * Create a version 4 volume record
+ */
+static int nfs4_init_server(struct nfs_server *server,
+               const struct nfs_parsed_mount_data *data)
+{
+       struct rpc_timeout timeparms;
+       int error;
+
+       dprintk("--> nfs4_init_server()\n");
+
+       nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
+                       data->timeo, data->retrans);
+
+       /* Initialise the client representation from the mount data */
+       server->flags = data->flags;
+       server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|NFS_CAP_POSIX_LOCK;
+       if (!(data->flags & NFS_MOUNT_NORDIRPLUS))
+                       server->caps |= NFS_CAP_READDIRPLUS;
+       server->options = data->options;
+
+       /* Get a client record */
+       error = nfs4_set_client(server,
+                       data->nfs_server.hostname,
+                       (const struct sockaddr *)&data->nfs_server.address,
+                       data->nfs_server.addrlen,
+                       data->client_address,
+                       data->auth_flavors[0],
+                       data->nfs_server.protocol,
+                       &timeparms,
+                       data->minorversion,
+                       data->net);
+       if (error < 0)
+               goto error;
+
+       /*
+        * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
+        * authentication.
+        */
+       if (nfs4_disable_idmapping && data->auth_flavors[0] == RPC_AUTH_UNIX)
+               server->caps |= NFS_CAP_UIDGID_NOMAP;
+
+       if (data->rsize)
+               server->rsize = nfs_block_size(data->rsize, NULL);
+       if (data->wsize)
+               server->wsize = nfs_block_size(data->wsize, NULL);
+
+       server->acregmin = data->acregmin * HZ;
+       server->acregmax = data->acregmax * HZ;
+       server->acdirmin = data->acdirmin * HZ;
+       server->acdirmax = data->acdirmax * HZ;
+
+       server->port = data->nfs_server.port;
+
+       error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]);
+
+error:
+       /* Done */
+       dprintk("<-- nfs4_init_server() = %d\n", error);
+       return error;
+}
+
+/*
+ * Create a version 4 volume record
+ * - keyed on server and FSID
+ */
+struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
+                                     struct nfs_fh *mntfh)
+{
+       struct nfs_server *server;
+       int error;
+
+       dprintk("--> nfs4_create_server()\n");
+
+       server = nfs_alloc_server();
+       if (!server)
+               return ERR_PTR(-ENOMEM);
+
+       /* set up the general RPC client */
+       error = nfs4_init_server(server, data);
+       if (error < 0)
+               goto error;
+
+       error = nfs4_server_common_setup(server, mntfh);
+       if (error < 0)
+               goto error;
+
+       dprintk("<-- nfs4_create_server() = %p\n", server);
+       return server;
+
+error:
+       nfs_free_server(server);
+       dprintk("<-- nfs4_create_server() = error %d\n", error);
+       return ERR_PTR(error);
+}
+
+/*
+ * Create an NFS4 referral server record
+ */
+struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
+                                              struct nfs_fh *mntfh)
+{
+       struct nfs_client *parent_client;
+       struct nfs_server *server, *parent_server;
+       int error;
+
+       dprintk("--> nfs4_create_referral_server()\n");
+
+       server = nfs_alloc_server();
+       if (!server)
+               return ERR_PTR(-ENOMEM);
+
+       parent_server = NFS_SB(data->sb);
+       parent_client = parent_server->nfs_client;
+
+       /* Initialise the client representation from the parent server */
+       nfs_server_copy_userdata(server, parent_server);
+       server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR;
+
+       /* Get a client representation.
+        * Note: NFSv4 always uses TCP, */
+       error = nfs4_set_client(server, data->hostname,
+                               data->addr,
+                               data->addrlen,
+                               parent_client->cl_ipaddr,
+                               data->authflavor,
+                               rpc_protocol(parent_server->client),
+                               parent_server->client->cl_timeout,
+                               parent_client->cl_mvops->minor_version,
+                               parent_client->cl_net);
+       if (error < 0)
+               goto error;
+
+       error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor);
+       if (error < 0)
+               goto error;
+
+       error = nfs4_server_common_setup(server, mntfh);
+       if (error < 0)
+               goto error;
+
+       dprintk("<-- nfs_create_referral_server() = %p\n", server);
+       return server;
+
+error:
+       nfs_free_server(server);
+       dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
+       return ERR_PTR(error);
+}
+
+module_param(nfs4_disable_idmapping, bool, 0644);
+MODULE_PARM_DESC(nfs4_disable_idmapping,
+               "Turn off NFSv4 idmapping when using 'sec=sys'");
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
new file mode 100644 (file)
index 0000000..acb65e7
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *  linux/fs/nfs/file.c
+ *
+ *  Copyright (C) 1992  Rick Sladkey
+ */
+#include <linux/nfs_fs.h>
+#include "internal.h"
+#include "pnfs.h"
+
+#define NFSDBG_FACILITY                NFSDBG_FILE
+
+static int
+nfs4_file_open(struct inode *inode, struct file *filp)
+{
+       struct nfs_open_context *ctx;
+       struct dentry *dentry = filp->f_path.dentry;
+       struct dentry *parent = NULL;
+       struct inode *dir;
+       unsigned openflags = filp->f_flags;
+       struct iattr attr;
+       int err;
+
+       BUG_ON(inode != dentry->d_inode);
+       /*
+        * If no cached dentry exists or if it's negative, NFSv4 handled the
+        * opens in ->lookup() or ->create().
+        *
+        * We only get this far for a cached positive dentry.  We skipped
+        * revalidation, so handle it here by dropping the dentry and returning
+        * -EOPENSTALE.  The VFS will retry the lookup/create/open.
+        */
+
+       dprintk("NFS: open file(%s/%s)\n",
+               dentry->d_parent->d_name.name,
+               dentry->d_name.name);
+
+       if ((openflags & O_ACCMODE) == 3)
+               openflags--;
+
+       /* We can't create new files here */
+       openflags &= ~(O_CREAT|O_EXCL);
+
+       parent = dget_parent(dentry);
+       dir = parent->d_inode;
+
+       ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode);
+       err = PTR_ERR(ctx);
+       if (IS_ERR(ctx))
+               goto out;
+
+       attr.ia_valid = ATTR_OPEN;
+       if (openflags & O_TRUNC) {
+               attr.ia_valid |= ATTR_SIZE;
+               attr.ia_size = 0;
+               nfs_wb_all(inode);
+       }
+
+       inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
+       if (IS_ERR(inode)) {
+               err = PTR_ERR(inode);
+               switch (err) {
+               case -EPERM:
+               case -EACCES:
+               case -EDQUOT:
+               case -ENOSPC:
+               case -EROFS:
+                       goto out_put_ctx;
+               default:
+                       goto out_drop;
+               }
+       }
+       iput(inode);
+       if (inode != dentry->d_inode)
+               goto out_drop;
+
+       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+       nfs_file_set_open_context(filp, ctx);
+       err = 0;
+
+out_put_ctx:
+       put_nfs_open_context(ctx);
+out:
+       dput(parent);
+       return err;
+
+out_drop:
+       d_drop(dentry);
+       err = -EOPENSTALE;
+       goto out_put_ctx;
+}
+
+static int
+nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+       int ret;
+       struct inode *inode = file->f_path.dentry->d_inode;
+
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       mutex_lock(&inode->i_mutex);
+       ret = nfs_file_fsync_commit(file, start, end, datasync);
+       if (!ret && !datasync)
+               /* application has asked for meta-data sync */
+               ret = pnfs_layoutcommit_inode(inode, true);
+       mutex_unlock(&inode->i_mutex);
+
+       return ret;
+}
+
+const struct file_operations nfs4_file_operations = {
+       .llseek         = nfs_file_llseek,
+       .read           = do_sync_read,
+       .write          = do_sync_write,
+       .aio_read       = nfs_file_read,
+       .aio_write      = nfs_file_write,
+       .mmap           = nfs_file_mmap,
+       .open           = nfs4_file_open,
+       .flush          = nfs_file_flush,
+       .release        = nfs_file_release,
+       .fsync          = nfs4_file_fsync,
+       .lock           = nfs_lock,
+       .flock          = nfs_flock,
+       .splice_read    = nfs_file_splice_read,
+       .splice_write   = nfs_file_splice_write,
+       .check_flags    = nfs_check_flags,
+       .setlease       = nfs_setlease,
+};
index e1340293872c7a70e747d051888e5ab603db905e..53f94d915bd18ce77c4cf542ebc25378c56f2add 100644 (file)
@@ -205,9 +205,9 @@ static int filelayout_async_handle_error(struct rpc_task *task,
        case -EPIPE:
                dprintk("%s DS connection error %d\n", __func__,
                        task->tk_status);
-               if (!filelayout_test_devid_invalid(devid))
-                       _pnfs_return_layout(inode);
                filelayout_mark_devid_invalid(devid);
+               clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags);
+               _pnfs_return_layout(inode);
                rpc_wake_up(&tbl->slot_tbl_waitq);
                nfs4_ds_disconnect(clp);
                /* fall through */
@@ -351,9 +351,9 @@ static void prepare_to_resend_writes(struct nfs_commit_data *data)
        struct nfs_page *first = nfs_list_entry(data->pages.next);
 
        data->task.tk_status = 0;
-       memcpy(data->verf.verifier, first->wb_verf.verifier,
-              sizeof(first->wb_verf.verifier));
-       data->verf.verifier[0]++; /* ensure verifier mismatch */
+       memcpy(&data->verf.verifier, &first->wb_verf,
+              sizeof(data->verf.verifier));
+       data->verf.verifier.data[0]++; /* ensure verifier mismatch */
 }
 
 static int filelayout_commit_done_cb(struct rpc_task *task,
index a1fab8da7f03c8819951af81d95e6268a71dc80f..f81231f30d949aa5d6b8a328cce91b792c656004 100644 (file)
@@ -728,7 +728,7 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_fla
        pdev->layout_type = LAYOUT_NFSV4_1_FILES;
        pdev->pages = pages;
        pdev->pgbase = 0;
-       pdev->pglen = PAGE_SIZE * max_pages;
+       pdev->pglen = max_resp_sz;
        pdev->mincount = 0;
 
        rc = nfs4_proc_getdeviceinfo(server, pdev);
diff --git a/fs/nfs/nfs4getroot.c b/fs/nfs/nfs4getroot.c
new file mode 100644 (file)
index 0000000..6a83780
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+* Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+* Written by David Howells (dhowells@redhat.com)
+*/
+
+#include <linux/nfs_fs.h>
+#include "nfs4_fs.h"
+
+#define NFSDBG_FACILITY                NFSDBG_CLIENT
+
+int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh)
+{
+       struct nfs_fsinfo fsinfo;
+       int ret = -ENOMEM;
+
+       dprintk("--> nfs4_get_rootfh()\n");
+
+       fsinfo.fattr = nfs_alloc_fattr();
+       if (fsinfo.fattr == NULL)
+               goto out;
+
+       /* Start by getting the root filehandle from the server */
+       ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo);
+       if (ret < 0) {
+               dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret);
+               goto out;
+       }
+
+       if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE)
+                       || !S_ISDIR(fsinfo.fattr->mode)) {
+               printk(KERN_ERR "nfs4_get_rootfh:"
+                      " getroot encountered non-directory\n");
+               ret = -ENOTDIR;
+               goto out;
+       }
+
+       if (fsinfo.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
+               printk(KERN_ERR "nfs4_get_rootfh:"
+                      " getroot obtained referral\n");
+               ret = -EREMOTE;
+               goto out;
+       }
+
+       memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid));
+out:
+       nfs_free_fattr(fsinfo.fattr);
+       dprintk("<-- nfs4_get_rootfh() = %d\n", ret);
+       return ret;
+}
index c157b2089b475c22c046a15f293236f7725a4ee7..6843e0a37de8eb900421ae118d76c889afe041ef 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/printk.h>
 #include <linux/slab.h>
 #include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/gss_api.h>
 #include <linux/nfs.h>
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
@@ -259,7 +258,12 @@ static int nfs4_wait_clnt_recover(struct nfs_client *clp)
 
        res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
                        nfs_wait_bit_killable, TASK_KILLABLE);
-       return res;
+       if (res)
+               return res;
+
+       if (clp->cl_cons_state < 0)
+               return clp->cl_cons_state;
+       return 0;
 }
 
 static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
@@ -294,8 +298,8 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
                case 0:
                        return 0;
                case -NFS4ERR_OPENMODE:
-                       if (inode && nfs_have_delegation(inode, FMODE_READ)) {
-                               nfs_inode_return_delegation(inode);
+                       if (inode && nfs4_have_delegation(inode, FMODE_READ)) {
+                               nfs4_inode_return_delegation(inode);
                                exception->retry = 1;
                                return 0;
                        }
@@ -1065,7 +1069,7 @@ static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmo
                return;
        }
        rcu_read_unlock();
-       nfs_inode_return_delegation(inode);
+       nfs4_inode_return_delegation(inode);
 }
 
 static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
@@ -1756,33 +1760,70 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
 }
 
 #if defined(CONFIG_NFS_V4_1)
-static int nfs41_check_expired_stateid(struct nfs4_state *state, nfs4_stateid *stateid, unsigned int flags)
+static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
 {
-       int status = NFS_OK;
        struct nfs_server *server = NFS_SERVER(state->inode);
+       nfs4_stateid *stateid = &state->stateid;
+       int status;
+
+       /* If a state reset has been done, test_stateid is unneeded */
+       if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
+               return;
 
-       if (state->flags & flags) {
-               status = nfs41_test_stateid(server, stateid);
-               if (status != NFS_OK) {
+       status = nfs41_test_stateid(server, stateid);
+       if (status != NFS_OK) {
+               /* Free the stateid unless the server explicitly
+                * informs us the stateid is unrecognized. */
+               if (status != -NFS4ERR_BAD_STATEID)
                        nfs41_free_stateid(server, stateid);
-                       state->flags &= ~flags;
-               }
+
+               clear_bit(NFS_DELEGATED_STATE, &state->flags);
+       }
+}
+
+/**
+ * nfs41_check_open_stateid - possibly free an open stateid
+ *
+ * @state: NFSv4 state for an inode
+ *
+ * Returns NFS_OK if recovery for this stateid is now finished.
+ * Otherwise a negative NFS4ERR value is returned.
+ */
+static int nfs41_check_open_stateid(struct nfs4_state *state)
+{
+       struct nfs_server *server = NFS_SERVER(state->inode);
+       nfs4_stateid *stateid = &state->stateid;
+       int status;
+
+       /* If a state reset has been done, test_stateid is unneeded */
+       if ((test_bit(NFS_O_RDONLY_STATE, &state->flags) == 0) &&
+           (test_bit(NFS_O_WRONLY_STATE, &state->flags) == 0) &&
+           (test_bit(NFS_O_RDWR_STATE, &state->flags) == 0))
+               return -NFS4ERR_BAD_STATEID;
+
+       status = nfs41_test_stateid(server, stateid);
+       if (status != NFS_OK) {
+               /* Free the stateid unless the server explicitly
+                * informs us the stateid is unrecognized. */
+               if (status != -NFS4ERR_BAD_STATEID)
+                       nfs41_free_stateid(server, stateid);
+
+               clear_bit(NFS_O_RDONLY_STATE, &state->flags);
+               clear_bit(NFS_O_WRONLY_STATE, &state->flags);
+               clear_bit(NFS_O_RDWR_STATE, &state->flags);
        }
        return status;
 }
 
 static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
 {
-       int deleg_status, open_status;
-       int deleg_flags = 1 << NFS_DELEGATED_STATE;
-       int open_flags = (1 << NFS_O_RDONLY_STATE) | (1 << NFS_O_WRONLY_STATE) | (1 << NFS_O_RDWR_STATE);
-
-       deleg_status = nfs41_check_expired_stateid(state, &state->stateid, deleg_flags);
-       open_status = nfs41_check_expired_stateid(state,  &state->open_stateid, open_flags);
+       int status;
 
-       if ((deleg_status == NFS_OK) && (open_status == NFS_OK))
-               return NFS_OK;
-       return nfs4_open_expired(sp, state);
+       nfs41_clear_delegation_stateid(state);
+       status = nfs41_check_open_stateid(state);
+       if (status != NFS_OK)
+               status = nfs4_open_expired(sp, state);
+       return status;
 }
 #endif
 
@@ -2375,11 +2416,15 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
        int i, len, status = 0;
        rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS];
 
-       len = gss_mech_list_pseudoflavors(&flav_array[0]);
-       flav_array[len] = RPC_AUTH_NULL;
-       len += 1;
+       len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array));
+       BUG_ON(len < 0);
 
        for (i = 0; i < len; i++) {
+               /* AUTH_UNIX is the default flavor if none was specified,
+                * thus has already been tried. */
+               if (flav_array[i] == RPC_AUTH_UNIX)
+                       continue;
+
                status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
                if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
                        continue;
@@ -2766,9 +2811,7 @@ static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
  *
  * In the case of WRITE, we also want to put the GETATTR after
  * the operation -- in this case because we want to make sure
- * we get the post-operation mtime and size.  This means that
- * we can't use xdr_encode_pages() as written: we need a variant
- * of it which would leave room in the 'tail' iovec.
+ * we get the post-operation mtime and size.
  *
  * Both of these changes to the XDR layer would in fact be quite
  * minor, but I decided to leave them for a subsequent patch.
@@ -2821,7 +2864,9 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                return PTR_ERR(ctx);
 
        sattr->ia_mode &= ~current_umask();
-       state = nfs4_do_open(dir, dentry, ctx->mode, flags, sattr, ctx->cred, NULL);
+       state = nfs4_do_open(dir, dentry, ctx->mode,
+                       flags, sattr, ctx->cred,
+                       &ctx->mdsthreshold);
        d_drop(dentry);
        if (IS_ERR(state)) {
                status = PTR_ERR(state);
@@ -3315,8 +3360,14 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, str
 
 static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
 {
+       int error;
+
        nfs_fattr_init(fsinfo->fattr);
-       return nfs4_do_fsinfo(server, fhandle, fsinfo);
+       error = nfs4_do_fsinfo(server, fhandle, fsinfo);
+       if (error == 0)
+               set_pnfs_layoutdriver(server, fhandle, fsinfo->layouttype);
+
+       return error;
 }
 
 static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
@@ -3443,7 +3494,7 @@ bool nfs4_write_need_cache_consistency_data(const struct nfs_write_data *data)
        /* Otherwise, request attributes if and only if we don't hold
         * a delegation
         */
-       return nfs_have_delegation(hdr->inode, FMODE_READ) == 0;
+       return nfs4_have_delegation(hdr->inode, FMODE_READ) == 0;
 }
 
 static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg)
@@ -3732,7 +3783,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       int ret = -ENOMEM, npages, i, acl_len = 0;
+       int ret = -ENOMEM, npages, i;
+       size_t acl_len = 0;
 
        npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
        /* As long as we're doing a round trip to the server anyway,
@@ -3847,7 +3899,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
        i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
        if (i < 0)
                return i;
-       nfs_inode_return_delegation(inode);
+       nfs4_inode_return_delegation(inode);
        ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
 
        /*
@@ -3961,6 +4013,16 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
        memcpy(bootverf->data, verf, sizeof(bootverf->data));
 }
 
+/**
+ * nfs4_proc_setclientid - Negotiate client ID
+ * @clp: state data structure
+ * @program: RPC program for NFSv4 callback service
+ * @port: IP port number for NFS4 callback service
+ * @cred: RPC credential to use for this call
+ * @res: where to place the result
+ *
+ * Returns zero, a negative errno, or a negative NFS4ERR status code.
+ */
 int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                unsigned short port, struct rpc_cred *cred,
                struct nfs4_setclientid_res *res)
@@ -3977,44 +4039,44 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                .rpc_resp = res,
                .rpc_cred = cred,
        };
-       int loop = 0;
        int status;
 
+       /* nfs_client_id4 */
        nfs4_init_boot_verifier(clp, &sc_verifier);
-
-       for(;;) {
-               rcu_read_lock();
-               setclientid.sc_name_len = scnprintf(setclientid.sc_name,
-                               sizeof(setclientid.sc_name), "%s/%s %s %s %u",
-                               clp->cl_ipaddr,
-                               rpc_peeraddr2str(clp->cl_rpcclient,
-                                                       RPC_DISPLAY_ADDR),
-                               rpc_peeraddr2str(clp->cl_rpcclient,
-                                                       RPC_DISPLAY_PROTO),
-                               clp->cl_rpcclient->cl_auth->au_ops->au_name,
-                               clp->cl_id_uniquifier);
-               setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
+       rcu_read_lock();
+       setclientid.sc_name_len = scnprintf(setclientid.sc_name,
+                       sizeof(setclientid.sc_name), "%s/%s %s",
+                       clp->cl_ipaddr,
+                       rpc_peeraddr2str(clp->cl_rpcclient,
+                                               RPC_DISPLAY_ADDR),
+                       rpc_peeraddr2str(clp->cl_rpcclient,
+                                               RPC_DISPLAY_PROTO));
+       /* cb_client4 */
+       setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
                                sizeof(setclientid.sc_netid),
                                rpc_peeraddr2str(clp->cl_rpcclient,
                                                        RPC_DISPLAY_NETID));
-               setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
+       rcu_read_unlock();
+       setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
                                sizeof(setclientid.sc_uaddr), "%s.%u.%u",
                                clp->cl_ipaddr, port >> 8, port & 255);
-               rcu_read_unlock();
 
-               status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
-               if (status != -NFS4ERR_CLID_INUSE)
-                       break;
-               if (loop != 0) {
-                       ++clp->cl_id_uniquifier;
-                       break;
-               }
-               ++loop;
-               ssleep(clp->cl_lease_time / HZ + 1);
-       }
+       dprintk("NFS call  setclientid auth=%s, '%.*s'\n",
+               clp->cl_rpcclient->cl_auth->au_ops->au_name,
+               setclientid.sc_name_len, setclientid.sc_name);
+       status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       dprintk("NFS reply setclientid: %d\n", status);
        return status;
 }
 
+/**
+ * nfs4_proc_setclientid_confirm - Confirm client ID
+ * @clp: state data structure
+ * @res: result of a previous SETCLIENTID
+ * @cred: RPC credential to use for this call
+ *
+ * Returns zero, a negative errno, or a negative NFS4ERR status code.
+ */
 int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
                struct nfs4_setclientid_res *arg,
                struct rpc_cred *cred)
@@ -4029,6 +4091,9 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
        unsigned long now;
        int status;
 
+       dprintk("NFS call  setclientid_confirm auth=%s, (client ID %llx)\n",
+               clp->cl_rpcclient->cl_auth->au_ops->au_name,
+               clp->cl_clientid);
        now = jiffies;
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
        if (status == 0) {
@@ -4037,6 +4102,7 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
                clp->cl_last_renewal = now;
                spin_unlock(&clp->cl_lock);
        }
+       dprintk("NFS reply setclientid_confirm: %d\n", status);
        return status;
 }
 
@@ -4681,9 +4747,17 @@ out:
 }
 
 #if defined(CONFIG_NFS_V4_1)
+/**
+ * nfs41_check_expired_locks - possibly free a lock stateid
+ *
+ * @state: NFSv4 state for an inode
+ *
+ * Returns NFS_OK if recovery for this stateid is now finished.
+ * Otherwise a negative NFS4ERR value is returned.
+ */
 static int nfs41_check_expired_locks(struct nfs4_state *state)
 {
-       int status, ret = NFS_OK;
+       int status, ret = -NFS4ERR_BAD_STATEID;
        struct nfs4_lock_state *lsp;
        struct nfs_server *server = NFS_SERVER(state->inode);
 
@@ -4691,7 +4765,11 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
                if (lsp->ls_flags & NFS_LOCK_INITIALIZED) {
                        status = nfs41_test_stateid(server, &lsp->ls_stateid);
                        if (status != NFS_OK) {
-                               nfs41_free_stateid(server, &lsp->ls_stateid);
+                               /* Free the stateid unless the server
+                                * informs us the stateid is unrecognized. */
+                               if (status != -NFS4ERR_BAD_STATEID)
+                                       nfs41_free_stateid(server,
+                                                       &lsp->ls_stateid);
                                lsp->ls_flags &= ~NFS_LOCK_INITIALIZED;
                                ret = status;
                        }
@@ -4707,9 +4785,9 @@ static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *reques
 
        if (test_bit(LK_STATE_IN_USE, &state->flags))
                status = nfs41_check_expired_locks(state);
-       if (status == NFS_OK)
-               return status;
-       return nfs4_lock_expired(state, request);
+       if (status != NFS_OK)
+               status = nfs4_lock_expired(state, request);
+       return status;
 }
 #endif
 
@@ -4807,7 +4885,7 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
         * Don't rely on the VFS having checked the file open mode,
         * since it won't do this for flock() locks.
         */
-       switch (request->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) {
+       switch (request->fl_type) {
        case F_RDLCK:
                if (!(filp->f_mode & FMODE_READ))
                        return -EBADF;
@@ -5168,6 +5246,8 @@ out:
 /*
  * nfs4_proc_exchange_id()
  *
+ * Returns zero, a negative errno, or a negative NFS4ERR status code.
+ *
  * Since the clientid has expired, all compounds using sessions
  * associated with the stale clientid will be returning
  * NFS4ERR_BADSESSION in the sequence operation, and will therefore
@@ -5192,16 +5272,14 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
                .rpc_cred = cred,
        };
 
-       dprintk("--> %s\n", __func__);
-       BUG_ON(clp == NULL);
-
        nfs4_init_boot_verifier(clp, &verifier);
-
        args.id_len = scnprintf(args.id, sizeof(args.id),
-                               "%s/%s/%u",
+                               "%s/%s",
                                clp->cl_ipaddr,
-                               clp->cl_rpcclient->cl_nodename,
-                               clp->cl_rpcclient->cl_auth->au_flavor);
+                               clp->cl_rpcclient->cl_nodename);
+       dprintk("NFS call  exchange_id auth=%s, '%.*s'\n",
+               clp->cl_rpcclient->cl_auth->au_ops->au_name,
+               args.id_len, args.id);
 
        res.server_owner = kzalloc(sizeof(struct nfs41_server_owner),
                                        GFP_NOFS);
@@ -5264,12 +5342,12 @@ out_server_scope:
        kfree(res.server_scope);
 out:
        if (clp->cl_implid != NULL)
-               dprintk("%s: Server Implementation ID: "
+               dprintk("NFS reply exchange_id: Server Implementation ID: "
                        "domain: %s, name: %s, date: %llu,%u\n",
-                       __func__, clp->cl_implid->domain, clp->cl_implid->name,
+                       clp->cl_implid->domain, clp->cl_implid->name,
                        clp->cl_implid->date.seconds,
                        clp->cl_implid->date.nseconds);
-       dprintk("<-- %s status= %d\n", __func__, status);
+       dprintk("NFS reply exchange_id: %d\n", status);
        return status;
 }
 
@@ -6570,22 +6648,36 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
                .rpc_resp = &res,
        };
 
+       dprintk("NFS call  test_stateid %p\n", stateid);
        nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
        status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
-
-       if (status == NFS_OK)
-               return res.status;
-       return status;
+       if (status != NFS_OK) {
+               dprintk("NFS reply test_stateid: failed, %d\n", status);
+               return status;
+       }
+       dprintk("NFS reply test_stateid: succeeded, %d\n", -res.status);
+       return -res.status;
 }
 
+/**
+ * nfs41_test_stateid - perform a TEST_STATEID operation
+ *
+ * @server: server / transport on which to perform the operation
+ * @stateid: state ID to test
+ *
+ * Returns NFS_OK if the server recognizes that "stateid" is valid.
+ * Otherwise a negative NFS4ERR value is returned if the operation
+ * failed or the state ID is not currently valid.
+ */
 static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 {
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(server,
-                               _nfs41_test_stateid(server, stateid),
-                               &exception);
+               err = _nfs41_test_stateid(server, stateid);
+               if (err != -NFS4ERR_DELAY)
+                       break;
+               nfs4_handle_exception(server, err, &exception);
        } while (exception.retry);
        return err;
 }
@@ -6601,19 +6693,34 @@ static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
+       int status;
 
+       dprintk("NFS call  free_stateid %p\n", stateid);
        nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
-       return nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
+       status = nfs4_call_sync_sequence(server->client, server, &msg,
+                                        &args.seq_args, &res.seq_res, 1);
+       dprintk("NFS reply free_stateid: %d\n", status);
+       return status;
 }
 
+/**
+ * nfs41_free_stateid - perform a FREE_STATEID operation
+ *
+ * @server: server / transport on which to perform the operation
+ * @stateid: state ID to release
+ *
+ * Returns NFS_OK if the server freed "stateid".  Otherwise a
+ * negative NFS4ERR value is returned.
+ */
 static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 {
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(server,
-                               _nfs4_free_stateid(server, stateid),
-                               &exception);
+               err = _nfs4_free_stateid(server, stateid);
+               if (err != -NFS4ERR_DELAY)
+                       break;
+               nfs4_handle_exception(server, err, &exception);
        } while (exception.retry);
        return err;
 }
@@ -6725,6 +6832,26 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
 #endif
 };
 
+const struct inode_operations nfs4_dir_inode_operations = {
+       .create         = nfs_create,
+       .lookup         = nfs_lookup,
+       .atomic_open    = nfs_atomic_open,
+       .link           = nfs_link,
+       .unlink         = nfs_unlink,
+       .symlink        = nfs_symlink,
+       .mkdir          = nfs_mkdir,
+       .rmdir          = nfs_rmdir,
+       .mknod          = nfs_mknod,
+       .rename         = nfs_rename,
+       .permission     = nfs_permission,
+       .getattr        = nfs_getattr,
+       .setattr        = nfs_setattr,
+       .getxattr       = generic_getxattr,
+       .setxattr       = generic_setxattr,
+       .listxattr      = generic_listxattr,
+       .removexattr    = generic_removexattr,
+};
+
 static const struct inode_operations nfs4_file_inode_operations = {
        .permission     = nfs_permission,
        .getattr        = nfs_getattr,
@@ -6769,9 +6896,11 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .set_capabilities = nfs4_server_capabilities,
        .decode_dirent  = nfs4_decode_dirent,
        .read_setup     = nfs4_proc_read_setup,
+       .read_pageio_init = pnfs_pageio_init_read,
        .read_rpc_prepare = nfs4_proc_read_rpc_prepare,
        .read_done      = nfs4_read_done,
        .write_setup    = nfs4_proc_write_setup,
+       .write_pageio_init = pnfs_pageio_init_write,
        .write_rpc_prepare = nfs4_proc_write_rpc_prepare,
        .write_done     = nfs4_write_done,
        .commit_setup   = nfs4_proc_commit_setup,
@@ -6781,7 +6910,11 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .clear_acl_cache = nfs4_zap_acl_attr,
        .close_context  = nfs4_close_context,
        .open_context   = nfs4_atomic_open,
+       .have_delegation = nfs4_have_delegation,
+       .return_delegation = nfs4_inode_return_delegation,
+       .alloc_client   = nfs4_alloc_client,
        .init_client    = nfs4_init_client,
+       .free_client    = nfs4_free_client,
 };
 
 static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
index f38300e9f171646aeb414c704e26bb5302f380fa..55148def5540f325d3a13bea73aa713960ffcd1e 100644 (file)
@@ -1606,10 +1606,15 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
                        return -ESERVERFAULT;
                /* Lease confirmation error: retry after purging the lease */
                ssleep(1);
-       case -NFS4ERR_CLID_INUSE:
        case -NFS4ERR_STALE_CLIENTID:
                clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
                break;
+       case -NFS4ERR_CLID_INUSE:
+               pr_err("NFS: Server %s reports our clientid is in use\n",
+                       clp->cl_hostname);
+               nfs_mark_client_ready(clp, -EPERM);
+               clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
+               return -EPERM;
        case -EACCES:
                if (clp->cl_machine_cred == NULL)
                        return -EACCES;
@@ -1642,7 +1647,7 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
        return 0;
 }
 
-static int nfs4_reclaim_lease(struct nfs_client *clp)
+static int nfs4_establish_lease(struct nfs_client *clp)
 {
        struct rpc_cred *cred;
        const struct nfs4_state_recovery_ops *ops =
@@ -1655,7 +1660,41 @@ static int nfs4_reclaim_lease(struct nfs_client *clp)
        status = ops->establish_clid(clp, cred);
        put_rpccred(cred);
        if (status != 0)
+               return status;
+       pnfs_destroy_all_layouts(clp);
+       return 0;
+}
+
+/*
+ * Returns zero or a negative errno.  NFS4ERR values are converted
+ * to local errno values.
+ */
+static int nfs4_reclaim_lease(struct nfs_client *clp)
+{
+       int status;
+
+       status = nfs4_establish_lease(clp);
+       if (status < 0)
+               return nfs4_handle_reclaim_lease_error(clp, status);
+       if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state))
+               nfs4_state_start_reclaim_nograce(clp);
+       if (!test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state))
+               set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
+       clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
+       clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+       return 0;
+}
+
+static int nfs4_purge_lease(struct nfs_client *clp)
+{
+       int status;
+
+       status = nfs4_establish_lease(clp);
+       if (status < 0)
                return nfs4_handle_reclaim_lease_error(clp, status);
+       clear_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
+       set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+       nfs4_state_start_reclaim_nograce(clp);
        return 0;
 }
 
@@ -1764,6 +1803,8 @@ static int nfs4_reset_session(struct nfs_client *clp)
        struct rpc_cred *cred;
        int status;
 
+       if (!nfs4_has_session(clp))
+               return 0;
        nfs4_begin_drain_session(clp);
        cred = nfs4_get_exchange_id_cred(clp);
        status = nfs4_proc_destroy_session(clp->cl_session, cred);
@@ -1792,12 +1833,14 @@ out:
 
 static int nfs4_recall_slot(struct nfs_client *clp)
 {
-       struct nfs4_slot_table *fc_tbl = &clp->cl_session->fc_slot_table;
-       struct nfs4_channel_attrs *fc_attrs = &clp->cl_session->fc_attrs;
+       struct nfs4_slot_table *fc_tbl;
        struct nfs4_slot *new, *old;
        int i;
 
+       if (!nfs4_has_session(clp))
+               return 0;
        nfs4_begin_drain_session(clp);
+       fc_tbl = &clp->cl_session->fc_slot_table;
        new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot),
                      GFP_NOFS);
         if (!new)
@@ -1810,11 +1853,10 @@ static int nfs4_recall_slot(struct nfs_client *clp)
        fc_tbl->slots = new;
        fc_tbl->max_slots = fc_tbl->target_max_slots;
        fc_tbl->target_max_slots = 0;
-       fc_attrs->max_reqs = fc_tbl->max_slots;
+       clp->cl_session->fc_attrs.max_reqs = fc_tbl->max_slots;
        spin_unlock(&fc_tbl->slot_tbl_lock);
 
        kfree(old);
-       nfs4_end_drain_session(clp);
        return 0;
 }
 
@@ -1823,6 +1865,8 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp)
        struct rpc_cred *cred;
        int ret;
 
+       if (!nfs4_has_session(clp))
+               return 0;
        nfs4_begin_drain_session(clp);
        cred = nfs4_get_exchange_id_cred(clp);
        ret = nfs4_proc_bind_conn_to_session(clp, cred);
@@ -1857,37 +1901,29 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 static void nfs4_state_manager(struct nfs_client *clp)
 {
        int status = 0;
+       const char *section = "", *section_sep = "";
 
        /* Ensure exclusive access to NFSv4 state */
        do {
                if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
-                       status = nfs4_reclaim_lease(clp);
+                       section = "purge state";
+                       status = nfs4_purge_lease(clp);
                        if (status < 0)
                                goto out_error;
-                       clear_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
-                       set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+                       continue;
                }
 
-               if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
+               if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
+                       section = "lease expired";
                        /* We're going to have to re-establish a clientid */
                        status = nfs4_reclaim_lease(clp);
                        if (status < 0)
                                goto out_error;
-                       if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
-                               continue;
-                       clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
-
-                       if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH,
-                                              &clp->cl_state))
-                               nfs4_state_start_reclaim_nograce(clp);
-                       else
-                               set_bit(NFS4CLNT_RECLAIM_REBOOT,
-                                       &clp->cl_state);
-
-                       pnfs_destroy_all_layouts(clp);
+                       continue;
                }
 
                if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
+                       section = "check lease";
                        status = nfs4_check_lease(clp);
                        if (status < 0)
                                goto out_error;
@@ -1896,8 +1932,8 @@ static void nfs4_state_manager(struct nfs_client *clp)
                }
 
                /* Initialize or reset the session */
-               if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)
-                  && nfs4_has_session(clp)) {
+               if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) {
+                       section = "reset session";
                        status = nfs4_reset_session(clp);
                        if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
                                continue;
@@ -1907,15 +1943,26 @@ static void nfs4_state_manager(struct nfs_client *clp)
 
                /* Send BIND_CONN_TO_SESSION */
                if (test_and_clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION,
-                               &clp->cl_state) && nfs4_has_session(clp)) {
+                               &clp->cl_state)) {
+                       section = "bind conn to session";
                        status = nfs4_bind_conn_to_session(clp);
                        if (status < 0)
                                goto out_error;
                        continue;
                }
 
+               /* Recall session slots */
+               if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state)) {
+                       section = "recall slot";
+                       status = nfs4_recall_slot(clp);
+                       if (status < 0)
+                               goto out_error;
+                       continue;
+               }
+
                /* First recover reboot state... */
                if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
+                       section = "reclaim reboot";
                        status = nfs4_do_reclaim(clp,
                                clp->cl_mvops->reboot_recovery_ops);
                        if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
@@ -1930,6 +1977,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
 
                /* Now recover expired state... */
                if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
+                       section = "reclaim nograce";
                        status = nfs4_do_reclaim(clp,
                                clp->cl_mvops->nograce_recovery_ops);
                        if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
@@ -1945,15 +1993,6 @@ static void nfs4_state_manager(struct nfs_client *clp)
                        nfs_client_return_marked_delegations(clp);
                        continue;
                }
-               /* Recall session slots */
-               if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state)
-                  && nfs4_has_session(clp)) {
-                       status = nfs4_recall_slot(clp);
-                       if (status < 0)
-                               goto out_error;
-                       continue;
-               }
-
 
                nfs4_clear_state_manager_bit(clp);
                /* Did we race with an attempt to give us more work? */
@@ -1964,8 +2003,11 @@ static void nfs4_state_manager(struct nfs_client *clp)
        } while (atomic_read(&clp->cl_count) > 1);
        return;
 out_error:
-       pr_warn_ratelimited("NFS: state manager failed on NFSv4 server %s"
-                       " with error %d\n", clp->cl_hostname, -status);
+       if (strlen(section))
+               section_sep = ": ";
+       pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s"
+                       " with error %d\n", section_sep, section,
+                       clp->cl_hostname, -status);
        nfs4_end_drain_session(clp);
        nfs4_clear_state_manager_bit(clp);
 }
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
new file mode 100644 (file)
index 0000000..59264fb
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2012 Bryan Schumaker <bjschuma@netapp.com>
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/nfs_idmap.h>
+#include <linux/nfs4_mount.h>
+#include <linux/nfs_fs.h>
+#include "internal.h"
+#include "nfs4_fs.h"
+
+#define NFSDBG_FACILITY                NFSDBG_VFS
+
+static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *raw_data);
+static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *raw_data);
+static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *raw_data);
+static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *raw_data);
+
+static struct file_system_type nfs4_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "nfs4",
+       .mount          = nfs_fs_mount,
+       .kill_sb        = nfs_kill_super,
+       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+static struct file_system_type nfs4_remote_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "nfs4",
+       .mount          = nfs4_remote_mount,
+       .kill_sb        = nfs_kill_super,
+       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+struct file_system_type nfs4_xdev_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "nfs4",
+       .mount          = nfs4_xdev_mount,
+       .kill_sb        = nfs_kill_super,
+       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+static struct file_system_type nfs4_remote_referral_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "nfs4",
+       .mount          = nfs4_remote_referral_mount,
+       .kill_sb        = nfs_kill_super,
+       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+struct file_system_type nfs4_referral_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "nfs4",
+       .mount          = nfs4_referral_mount,
+       .kill_sb        = nfs_kill_super,
+       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+
+static const struct super_operations nfs4_sops = {
+       .alloc_inode    = nfs_alloc_inode,
+       .destroy_inode  = nfs_destroy_inode,
+       .write_inode    = nfs4_write_inode,
+       .put_super      = nfs_put_super,
+       .statfs         = nfs_statfs,
+       .evict_inode    = nfs4_evict_inode,
+       .umount_begin   = nfs_umount_begin,
+       .show_options   = nfs_show_options,
+       .show_devname   = nfs_show_devname,
+       .show_path      = nfs_show_path,
+       .show_stats     = nfs_show_stats,
+       .remount_fs     = nfs_remount,
+};
+
+/*
+ * Set up an NFS4 superblock
+ */
+static void nfs4_fill_super(struct super_block *sb,
+                           struct nfs_mount_info *mount_info)
+{
+       sb->s_time_gran = 1;
+       sb->s_op = &nfs4_sops;
+       /*
+        * The VFS shouldn't apply the umask to mode bits. We will do
+        * so ourselves when necessary.
+        */
+       sb->s_flags  |= MS_POSIXACL;
+       sb->s_xattr = nfs4_xattr_handlers;
+       nfs_initialise_sb(sb);
+}
+
+/*
+ * Get the superblock for the NFS4 root partition
+ */
+static struct dentry *
+nfs4_remote_mount(struct file_system_type *fs_type, int flags,
+                 const char *dev_name, void *info)
+{
+       struct nfs_mount_info *mount_info = info;
+       struct nfs_server *server;
+       struct dentry *mntroot = ERR_PTR(-ENOMEM);
+
+       mount_info->fill_super = nfs4_fill_super;
+       mount_info->set_security = nfs_set_sb_security;
+
+       /* Get a volume representation */
+       server = nfs4_create_server(mount_info->parsed, mount_info->mntfh);
+       if (IS_ERR(server)) {
+               mntroot = ERR_CAST(server);
+               goto out;
+       }
+
+       mntroot = nfs_fs_mount_common(fs_type, server, flags, dev_name, mount_info);
+
+out:
+       return mntroot;
+}
+
+static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
+               int flags, void *data, const char *hostname)
+{
+       struct vfsmount *root_mnt;
+       char *root_devname;
+       size_t len;
+
+       len = strlen(hostname) + 5;
+       root_devname = kmalloc(len, GFP_KERNEL);
+       if (root_devname == NULL)
+               return ERR_PTR(-ENOMEM);
+       /* Does hostname needs to be enclosed in brackets? */
+       if (strchr(hostname, ':'))
+               snprintf(root_devname, len, "[%s]:/", hostname);
+       else
+               snprintf(root_devname, len, "%s:/", hostname);
+       root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data);
+       kfree(root_devname);
+       return root_mnt;
+}
+
+struct nfs_referral_count {
+       struct list_head list;
+       const struct task_struct *task;
+       unsigned int referral_count;
+};
+
+static LIST_HEAD(nfs_referral_count_list);
+static DEFINE_SPINLOCK(nfs_referral_count_list_lock);
+
+static struct nfs_referral_count *nfs_find_referral_count(void)
+{
+       struct nfs_referral_count *p;
+
+       list_for_each_entry(p, &nfs_referral_count_list, list) {
+               if (p->task == current)
+                       return p;
+       }
+       return NULL;
+}
+
+#define NFS_MAX_NESTED_REFERRALS 2
+
+static int nfs_referral_loop_protect(void)
+{
+       struct nfs_referral_count *p, *new;
+       int ret = -ENOMEM;
+
+       new = kmalloc(sizeof(*new), GFP_KERNEL);
+       if (!new)
+               goto out;
+       new->task = current;
+       new->referral_count = 1;
+
+       ret = 0;
+       spin_lock(&nfs_referral_count_list_lock);
+       p = nfs_find_referral_count();
+       if (p != NULL) {
+               if (p->referral_count >= NFS_MAX_NESTED_REFERRALS)
+                       ret = -ELOOP;
+               else
+                       p->referral_count++;
+       } else {
+               list_add(&new->list, &nfs_referral_count_list);
+               new = NULL;
+       }
+       spin_unlock(&nfs_referral_count_list_lock);
+       kfree(new);
+out:
+       return ret;
+}
+
+static void nfs_referral_loop_unprotect(void)
+{
+       struct nfs_referral_count *p;
+
+       spin_lock(&nfs_referral_count_list_lock);
+       p = nfs_find_referral_count();
+       p->referral_count--;
+       if (p->referral_count == 0)
+               list_del(&p->list);
+       else
+               p = NULL;
+       spin_unlock(&nfs_referral_count_list_lock);
+       kfree(p);
+}
+
+static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt,
+               const char *export_path)
+{
+       struct dentry *dentry;
+       int err;
+
+       if (IS_ERR(root_mnt))
+               return ERR_CAST(root_mnt);
+
+       err = nfs_referral_loop_protect();
+       if (err) {
+               mntput(root_mnt);
+               return ERR_PTR(err);
+       }
+
+       dentry = mount_subtree(root_mnt, export_path);
+       nfs_referral_loop_unprotect();
+
+       return dentry;
+}
+
+struct dentry *nfs4_try_mount(int flags, const char *dev_name,
+                        struct nfs_mount_info *mount_info)
+{
+       char *export_path;
+       struct vfsmount *root_mnt;
+       struct dentry *res;
+       struct nfs_parsed_mount_data *data = mount_info->parsed;
+
+       dfprintk(MOUNT, "--> nfs4_try_mount()\n");
+
+       mount_info->fill_super = nfs4_fill_super;
+
+       export_path = data->nfs_server.export_path;
+       data->nfs_server.export_path = "/";
+       root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
+                       data->nfs_server.hostname);
+       data->nfs_server.export_path = export_path;
+
+       res = nfs_follow_remote_path(root_mnt, export_path);
+
+       dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n",
+                       IS_ERR(res) ? PTR_ERR(res) : 0,
+                       IS_ERR(res) ? " [error]" : "");
+       return res;
+}
+
+/*
+ * Clone an NFS4 server record on xdev traversal (FSID-change)
+ */
+static struct dentry *
+nfs4_xdev_mount(struct file_system_type *fs_type, int flags,
+                const char *dev_name, void *raw_data)
+{
+       struct nfs_mount_info mount_info = {
+               .fill_super = nfs_clone_super,
+               .set_security = nfs_clone_sb_security,
+               .cloned = raw_data,
+       };
+       return nfs_xdev_mount_common(&nfs4_fs_type, flags, dev_name, &mount_info);
+}
+
+static struct dentry *
+nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
+                          const char *dev_name, void *raw_data)
+{
+       struct nfs_mount_info mount_info = {
+               .fill_super = nfs4_fill_super,
+               .set_security = nfs_clone_sb_security,
+               .cloned = raw_data,
+       };
+       struct nfs_server *server;
+       struct dentry *mntroot = ERR_PTR(-ENOMEM);
+
+       dprintk("--> nfs4_referral_get_sb()\n");
+
+       mount_info.mntfh = nfs_alloc_fhandle();
+       if (mount_info.cloned == NULL || mount_info.mntfh == NULL)
+               goto out;
+
+       /* create a new volume representation */
+       server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh);
+       if (IS_ERR(server)) {
+               mntroot = ERR_CAST(server);
+               goto out;
+       }
+
+       mntroot = nfs_fs_mount_common(&nfs4_fs_type, server, flags, dev_name, &mount_info);
+out:
+       nfs_free_fhandle(mount_info.mntfh);
+       return mntroot;
+}
+
+/*
+ * Create an NFS4 server record on referral traversal
+ */
+static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
+               int flags, const char *dev_name, void *raw_data)
+{
+       struct nfs_clone_mount *data = raw_data;
+       char *export_path;
+       struct vfsmount *root_mnt;
+       struct dentry *res;
+
+       dprintk("--> nfs4_referral_mount()\n");
+
+       export_path = data->mnt_path;
+       data->mnt_path = "/";
+
+       root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type,
+                       flags, data, data->hostname);
+       data->mnt_path = export_path;
+
+       res = nfs_follow_remote_path(root_mnt, export_path);
+       dprintk("<-- nfs4_referral_mount() = %ld%s\n",
+                       IS_ERR(res) ? PTR_ERR(res) : 0,
+                       IS_ERR(res) ? " [error]" : "");
+       return res;
+}
+
+
+int __init init_nfs_v4(void)
+{
+       int err;
+
+       err = nfs_idmap_init();
+       if (err)
+               goto out;
+
+       err = nfs4_register_sysctl();
+       if (err)
+               goto out1;
+
+       err = register_filesystem(&nfs4_fs_type);
+       if (err < 0)
+               goto out2;
+
+       return 0;
+out2:
+       nfs4_unregister_sysctl();
+out1:
+       nfs_idmap_quit();
+out:
+       return err;
+}
+
+void exit_nfs_v4(void)
+{
+       unregister_filesystem(&nfs4_fs_type);
+       nfs4_unregister_sysctl();
+       nfs_idmap_quit();
+}
diff --git a/fs/nfs/nfs4sysctl.c b/fs/nfs/nfs4sysctl.c
new file mode 100644 (file)
index 0000000..5729bc8
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * linux/fs/nfs/nfs4sysctl.c
+ *
+ * Sysctl interface to NFS v4 parameters
+ *
+ * Copyright (c) 2006 Trond Myklebust <Trond.Myklebust@netapp.com>
+ */
+#include <linux/sysctl.h>
+#include <linux/nfs_idmap.h>
+#include <linux/nfs_fs.h>
+
+#include "callback.h"
+
+static const int nfs_set_port_min = 0;
+static const int nfs_set_port_max = 65535;
+static struct ctl_table_header *nfs4_callback_sysctl_table;
+
+static ctl_table nfs4_cb_sysctls[] = {
+       {
+               .procname = "nfs_callback_tcpport",
+               .data = &nfs_callback_set_tcpport,
+               .maxlen = sizeof(int),
+               .mode = 0644,
+               .proc_handler = proc_dointvec_minmax,
+               .extra1 = (int *)&nfs_set_port_min,
+               .extra2 = (int *)&nfs_set_port_max,
+       },
+       {
+               .procname = "idmap_cache_timeout",
+               .data = &nfs_idmap_cache_timeout,
+               .maxlen = sizeof(int),
+               .mode = 0644,
+               .proc_handler = proc_dointvec_jiffies,
+       },
+       { }
+};
+
+static ctl_table nfs4_cb_sysctl_dir[] = {
+       {
+               .procname = "nfs",
+               .mode = 0555,
+               .child = nfs4_cb_sysctls,
+       },
+       { }
+};
+
+static ctl_table nfs4_cb_sysctl_root[] = {
+       {
+               .procname = "fs",
+               .mode = 0555,
+               .child = nfs4_cb_sysctl_dir,
+       },
+       { }
+};
+
+int nfs4_register_sysctl(void)
+{
+       nfs4_callback_sysctl_table = register_sysctl_table(nfs4_cb_sysctl_root);
+       if (nfs4_callback_sysctl_table == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+void nfs4_unregister_sysctl(void)
+{
+       unregister_sysctl_table(nfs4_callback_sysctl_table);
+       nfs4_callback_sysctl_table = NULL;
+}
index 18fae29b0301c38a09fcb30a1345375780393f5c..6cbd602e26d5c1c04b809143d1600914564881a6 100644 (file)
@@ -1236,7 +1236,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct
 
 static inline int nfs4_lock_type(struct file_lock *fl, int block)
 {
-       if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK)
+       if (fl->fl_type == F_RDLCK)
                return block ? NFS4_READW_LT : NFS4_READ_LT;
        return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
 }
@@ -3078,7 +3078,7 @@ out_overflow:
        return -EIO;
 }
 
-static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
+static int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, unsigned int *savep)
 {
        __be32 *p;
 
@@ -3086,7 +3086,7 @@ static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen,
        if (unlikely(!p))
                goto out_overflow;
        *attrlen = be32_to_cpup(p);
-       *savep = xdr->p;
+       *savep = xdr_stream_pos(xdr);
        return 0;
 out_overflow:
        print_overflow_msg(__func__, xdr);
@@ -4068,10 +4068,10 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
        return status;
 }
 
-static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
+static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep, uint32_t attrlen)
 {
        unsigned int attrwords = XDR_QUADLEN(attrlen);
-       unsigned int nwords = xdr->p - savep;
+       unsigned int nwords = (xdr_stream_pos(xdr) - savep) >> 2;
 
        if (unlikely(attrwords != nwords)) {
                dprintk("%s: server returned incorrect attribute length: "
@@ -4158,13 +4158,18 @@ static int decode_verifier(struct xdr_stream *xdr, void *verifier)
        return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE);
 }
 
+static int decode_write_verifier(struct xdr_stream *xdr, struct nfs_write_verifier *verifier)
+{
+       return decode_opaque_fixed(xdr, verifier->data, NFS4_VERIFIER_SIZE);
+}
+
 static int decode_commit(struct xdr_stream *xdr, struct nfs_commitres *res)
 {
        int status;
 
        status = decode_op_hdr(xdr, OP_COMMIT);
        if (!status)
-               status = decode_verifier(xdr, res->verf->verifier);
+               status = decode_write_verifier(xdr, &res->verf->verifier);
        return status;
 }
 
@@ -4193,7 +4198,7 @@ out_overflow:
 
 static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
 {
-       __be32 *savep;
+       unsigned int savep;
        uint32_t attrlen, bitmap[3] = {0};
        int status;
 
@@ -4222,7 +4227,7 @@ xdr_error:
 
 static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
 {
-       __be32 *savep;
+       unsigned int savep;
        uint32_t attrlen, bitmap[3] = {0};
        int status;
 
@@ -4254,7 +4259,7 @@ xdr_error:
 
 static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
 {
-       __be32 *savep;
+       unsigned int savep;
        uint32_t attrlen, bitmap[3] = {0};
        int status;
 
@@ -4299,7 +4304,8 @@ out_overflow:
 static int decode_first_threshold_item4(struct xdr_stream *xdr,
                                        struct nfs4_threshold *res)
 {
-       __be32 *p, *savep;
+       __be32 *p;
+       unsigned int savep;
        uint32_t bitmap[3] = {0,}, attrlen;
        int status;
 
@@ -4503,7 +4509,7 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
                struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc,
                const struct nfs_server *server)
 {
-       __be32 *savep;
+       unsigned int savep;
        uint32_t attrlen,
                 bitmap[3] = {0};
        int status;
@@ -4615,7 +4621,7 @@ static int decode_attr_layout_blksize(struct xdr_stream *xdr, uint32_t *bitmap,
 
 static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
 {
-       __be32 *savep;
+       unsigned int savep;
        uint32_t attrlen, bitmap[3];
        int status;
 
@@ -4920,9 +4926,8 @@ static int decode_putrootfh(struct xdr_stream *xdr)
 
 static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
 {
-       struct kvec *iov = req->rq_rcv_buf.head;
        __be32 *p;
-       uint32_t count, eof, recvd, hdrlen;
+       uint32_t count, eof, recvd;
        int status;
 
        status = decode_op_hdr(xdr, OP_READ);
@@ -4933,15 +4938,13 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_
                goto out_overflow;
        eof = be32_to_cpup(p++);
        count = be32_to_cpup(p);
-       hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base;
-       recvd = req->rq_rcv_buf.len - hdrlen;
+       recvd = xdr_read_pages(xdr, count);
        if (count > recvd) {
                dprintk("NFS: server cheating in read reply: "
                                "count %u > recvd %u\n", count, recvd);
                count = recvd;
                eof = 0;
        }
-       xdr_read_pages(xdr, count);
        res->eof = eof;
        res->count = count;
        return 0;
@@ -4952,10 +4955,6 @@ out_overflow:
 
 static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
 {
-       struct xdr_buf  *rcvbuf = &req->rq_rcv_buf;
-       struct kvec     *iov = rcvbuf->head;
-       size_t          hdrlen;
-       u32             recvd, pglen = rcvbuf->page_len;
        int             status;
        __be32          verf[2];
 
@@ -4967,22 +4966,12 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
        memcpy(verf, readdir->verifier.data, sizeof(verf));
        dprintk("%s: verifier = %08x:%08x\n",
                        __func__, verf[0], verf[1]);
-
-       hdrlen = (char *) xdr->p - (char *) iov->iov_base;
-       recvd = rcvbuf->len - hdrlen;
-       if (pglen > recvd)
-               pglen = recvd;
-       xdr_read_pages(xdr, pglen);
-
-
-       return pglen;
+       return xdr_read_pages(xdr, xdr->buf->page_len);
 }
 
 static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
 {
        struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
-       struct kvec *iov = rcvbuf->head;
-       size_t hdrlen;
        u32 len, recvd;
        __be32 *p;
        int status;
@@ -5000,14 +4989,12 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
                dprintk("nfs: server returned giant symlink!\n");
                return -ENAMETOOLONG;
        }
-       hdrlen = (char *) xdr->p - (char *) iov->iov_base;
-       recvd = req->rq_rcv_buf.len - hdrlen;
+       recvd = xdr_read_pages(xdr, len);
        if (recvd < len) {
                dprintk("NFS: server cheating in readlink reply: "
                                "count %u > recvd %u\n", len, recvd);
                return -EIO;
        }
-       xdr_read_pages(xdr, len);
        /*
         * The XDR encode routine has set things up so that
         * the link text will be copied directly into the
@@ -5063,10 +5050,10 @@ decode_restorefh(struct xdr_stream *xdr)
 static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
                         struct nfs_getaclres *res)
 {
-       __be32 *savep, *bm_p;
+       unsigned int savep;
+       __be32 *bm_p;
        uint32_t attrlen,
                 bitmap[3] = {0};
-       struct kvec *iov = req->rq_rcv_buf.head;
        int status;
        size_t page_len = xdr->buf->page_len;
 
@@ -5089,7 +5076,6 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
        if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
                return -EIO;
        if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
-               size_t hdrlen;
 
                /* The bitmap (xdr len + bitmaps) and the attr xdr len words
                 * are stored with the acl data to handle the problem of
@@ -5098,7 +5084,6 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
 
                /* We ignore &savep and don't do consistency checks on
                 * the attr length.  Let userspace figure it out.... */
-               hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
                attrlen += res->acl_data_offset;
                if (attrlen > page_len) {
                        if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
@@ -5212,13 +5197,12 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
        if (status)
                return status;
 
-       p = xdr_inline_decode(xdr, 16);
+       p = xdr_inline_decode(xdr, 8);
        if (unlikely(!p))
                goto out_overflow;
        res->count = be32_to_cpup(p++);
        res->verf->committed = be32_to_cpup(p++);
-       memcpy(res->verf->verifier, p, NFS4_VERIFIER_SIZE);
-       return 0;
+       return decode_write_verifier(xdr, &res->verf->verifier);
 out_overflow:
        print_overflow_msg(__func__, xdr);
        return -EIO;
@@ -5599,7 +5583,7 @@ static int decode_getdevicelist(struct xdr_stream *xdr,
 {
        __be32 *p;
        int status, i;
-       struct nfs_writeverf verftemp;
+       nfs4_verifier verftemp;
 
        status = decode_op_hdr(xdr, OP_GETDEVICELIST);
        if (status)
@@ -5613,7 +5597,7 @@ static int decode_getdevicelist(struct xdr_stream *xdr,
        p += 2;
 
        /* Read verifier */
-       p = xdr_decode_opaque_fixed(p, verftemp.verifier, NFS4_VERIFIER_SIZE);
+       p = xdr_decode_opaque_fixed(p, verftemp.data, NFS4_VERIFIER_SIZE);
 
        res->num_devs = be32_to_cpup(p);
 
@@ -5707,9 +5691,7 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
        __be32 *p;
        int status;
        u32 layout_count;
-       struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
-       struct kvec *iov = rcvbuf->head;
-       u32 hdrlen, recvd;
+       u32 recvd;
 
        status = decode_op_hdr(xdr, OP_LAYOUTGET);
        if (status)
@@ -5746,8 +5728,7 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
                res->type,
                res->layoutp->len);
 
-       hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base;
-       recvd = req->rq_rcv_buf.len - hdrlen;
+       recvd = xdr_read_pages(xdr, res->layoutp->len);
        if (res->layoutp->len > recvd) {
                dprintk("NFS: server cheating in layoutget reply: "
                                "layout len %u > recvd %u\n",
@@ -5755,8 +5736,6 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
                return -EINVAL;
        }
 
-       xdr_read_pages(xdr, res->layoutp->len);
-
        if (layout_count > 1) {
                /* We only handle a length one array at the moment.  Any
                 * further entries are just ignored.  Note that this means
@@ -7103,6 +7082,7 @@ out:
 int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                       int plus)
 {
+       unsigned int savep;
        uint32_t bitmap[3] = {0};
        uint32_t len;
        __be32 *p = xdr_inline_decode(xdr, 4);
@@ -7141,7 +7121,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
        if (decode_attr_bitmap(xdr, bitmap) < 0)
                goto out_overflow;
 
-       if (decode_attr_length(xdr, &len, &p) < 0)
+       if (decode_attr_length(xdr, &len, &savep) < 0)
                goto out_overflow;
 
        if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
index bbc49caa7a82810ac497e7475997262f4da14be4..7fbd25afe418af4b749a78febb78b125cdf1fe07 100644 (file)
@@ -651,7 +651,14 @@ out_err_free:
        return NULL;
 }
 
-/* Initiates a LAYOUTRETURN(FILE) */
+/*
+ * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr
+ * when the layout segment list is empty.
+ *
+ * Note that a pnfs_layout_hdr can exist with an empty layout segment
+ * list when LAYOUTGET has failed, or when LAYOUTGET succeeded, but the
+ * deviceid is marked invalid.
+ */
 int
 _pnfs_return_layout(struct inode *ino)
 {
@@ -660,22 +667,31 @@ _pnfs_return_layout(struct inode *ino)
        LIST_HEAD(tmp_list);
        struct nfs4_layoutreturn *lrp;
        nfs4_stateid stateid;
-       int status = 0;
+       int status = 0, empty;
 
-       dprintk("--> %s\n", __func__);
+       dprintk("NFS: %s for inode %lu\n", __func__, ino->i_ino);
 
        spin_lock(&ino->i_lock);
        lo = nfsi->layout;
-       if (!lo) {
+       if (!lo || pnfs_test_layout_returned(lo)) {
                spin_unlock(&ino->i_lock);
-               dprintk("%s: no layout to return\n", __func__);
-               return status;
+               dprintk("NFS: %s no layout to return\n", __func__);
+               goto out;
        }
        stateid = nfsi->layout->plh_stateid;
        /* Reference matched in nfs4_layoutreturn_release */
        get_layout_hdr(lo);
+       empty = list_empty(&lo->plh_segs);
        mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
+       /* Don't send a LAYOUTRETURN if list was initially empty */
+       if (empty) {
+               spin_unlock(&ino->i_lock);
+               put_layout_hdr(lo);
+               dprintk("NFS: %s no layout segments to return\n", __func__);
+               goto out;
+       }
        lo->plh_block_lgets++;
+       pnfs_mark_layout_returned(lo);
        spin_unlock(&ino->i_lock);
        pnfs_free_lseg_list(&tmp_list);
 
@@ -686,6 +702,7 @@ _pnfs_return_layout(struct inode *ino)
                status = -ENOMEM;
                set_bit(NFS_LAYOUT_RW_FAILED, &lo->plh_flags);
                set_bit(NFS_LAYOUT_RO_FAILED, &lo->plh_flags);
+               pnfs_clear_layout_returned(lo);
                put_layout_hdr(lo);
                goto out;
        }
@@ -1075,6 +1092,10 @@ pnfs_update_layout(struct inode *ino,
        get_layout_hdr(lo);
        if (list_empty(&lo->plh_segs))
                first = true;
+
+       /* Enable LAYOUTRETURNs */
+       pnfs_clear_layout_returned(lo);
+
        spin_unlock(&ino->i_lock);
        if (first) {
                /* The lo must be on the clp list if there is any
@@ -1209,7 +1230,7 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *
 }
 EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write);
 
-bool
+void
 pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode,
                      const struct nfs_pgio_completion_ops *compl_ops)
 {
@@ -1217,13 +1238,12 @@ pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode,
        struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld;
 
        if (ld == NULL)
-               return false;
-       nfs_pageio_init(pgio, inode, ld->pg_read_ops, compl_ops,
-                       server->rsize, 0);
-       return true;
+               nfs_pageio_init_read(pgio, inode, compl_ops);
+       else
+               nfs_pageio_init(pgio, inode, ld->pg_read_ops, compl_ops, server->rsize, 0);
 }
 
-bool
+void
 pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode,
                       int ioflags,
                       const struct nfs_pgio_completion_ops *compl_ops)
@@ -1232,10 +1252,9 @@ pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode,
        struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld;
 
        if (ld == NULL)
-               return false;
-       nfs_pageio_init(pgio, inode, ld->pg_write_ops, compl_ops,
-                       server->wsize, ioflags);
-       return true;
+               nfs_pageio_init_write(pgio, inode, ioflags, compl_ops);
+       else
+               nfs_pageio_init(pgio, inode, ld->pg_write_ops, compl_ops, server->wsize, ioflags);
 }
 
 bool
@@ -1272,7 +1291,7 @@ int pnfs_write_done_resend_to_mds(struct inode *inode,
        LIST_HEAD(failed);
 
        /* Resend all requests through the MDS */
-       nfs_pageio_init_write_mds(&pgio, inode, FLUSH_STABLE, compl_ops);
+       nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, compl_ops);
        while (!list_empty(head)) {
                struct nfs_page *req = nfs_list_entry(head->next);
 
@@ -1427,7 +1446,7 @@ int pnfs_read_done_resend_to_mds(struct inode *inode,
        LIST_HEAD(failed);
 
        /* Resend all requests through the MDS */
-       nfs_pageio_init_read_mds(&pgio, inode, compl_ops);
+       nfs_pageio_init_read(&pgio, inode, compl_ops);
        while (!list_empty(head)) {
                struct nfs_page *req = nfs_list_entry(head->next);
 
index 64f90d845f6a95cd8752e5b4e1c9b3895f1a1e66..2c6c80503ba4851ed1e69c253293684c540b2c32 100644 (file)
@@ -64,6 +64,7 @@ enum {
        NFS_LAYOUT_ROC,                 /* some lseg had roc bit set */
        NFS_LAYOUT_DESTROYED,           /* no new use of layout allowed */
        NFS_LAYOUT_INVALID,             /* layout is being destroyed */
+       NFS_LAYOUT_RETURNED,            /* layout has already been returned */
 };
 
 enum layoutdriver_policy_flags {
@@ -178,9 +179,9 @@ extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp);
 void get_layout_hdr(struct pnfs_layout_hdr *lo);
 void put_lseg(struct pnfs_layout_segment *lseg);
 
-bool pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *,
+void pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *,
                           const struct nfs_pgio_completion_ops *);
-bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *,
+void pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *,
                            int, const struct nfs_pgio_completion_ops *);
 
 void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32);
@@ -255,6 +256,24 @@ struct nfs4_deviceid_node *nfs4_insert_deviceid_node(struct nfs4_deviceid_node *
 bool nfs4_put_deviceid_node(struct nfs4_deviceid_node *);
 void nfs4_deviceid_purge_client(const struct nfs_client *);
 
+static inline void
+pnfs_mark_layout_returned(struct pnfs_layout_hdr *lo)
+{
+       set_bit(NFS_LAYOUT_RETURNED, &lo->plh_flags);
+}
+
+static inline void
+pnfs_clear_layout_returned(struct pnfs_layout_hdr *lo)
+{
+       clear_bit(NFS_LAYOUT_RETURNED, &lo->plh_flags);
+}
+
+static inline bool
+pnfs_test_layout_returned(struct pnfs_layout_hdr *lo)
+{
+       return test_bit(NFS_LAYOUT_RETURNED, &lo->plh_flags);
+}
+
 static inline int lo_fail_bit(u32 iomode)
 {
        return iomode == IOMODE_RW ?
@@ -438,16 +457,16 @@ static inline void unset_pnfs_layoutdriver(struct nfs_server *s)
 {
 }
 
-static inline bool pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode,
+static inline void pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode,
                                         const struct nfs_pgio_completion_ops *compl_ops)
 {
-       return false;
+       nfs_pageio_init_read(pgio, inode, compl_ops);
 }
 
-static inline bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, int ioflags,
+static inline void pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, int ioflags,
                                          const struct nfs_pgio_completion_ops *compl_ops)
 {
-       return false;
+       nfs_pageio_init_write(pgio, inode, ioflags, compl_ops);
 }
 
 static inline int
index 4433806e116f9a4b26f605c4ef986a1633eb3efd..4d3356af330975b38491d89e6ea32bb37cda5523 100644 (file)
@@ -734,6 +734,38 @@ out_einval:
        return -EINVAL;
 }
 
+static int nfs_have_delegation(struct inode *inode, fmode_t flags)
+{
+       return 0;
+}
+
+static int nfs_return_delegation(struct inode *inode)
+{
+       nfs_wb_all(inode);
+       return 0;
+}
+
+static const struct inode_operations nfs_dir_inode_operations = {
+       .create         = nfs_create,
+       .lookup         = nfs_lookup,
+       .link           = nfs_link,
+       .unlink         = nfs_unlink,
+       .symlink        = nfs_symlink,
+       .mkdir          = nfs_mkdir,
+       .rmdir          = nfs_rmdir,
+       .mknod          = nfs_mknod,
+       .rename         = nfs_rename,
+       .permission     = nfs_permission,
+       .getattr        = nfs_getattr,
+       .setattr        = nfs_setattr,
+};
+
+static const struct inode_operations nfs_file_inode_operations = {
+       .permission     = nfs_permission,
+       .getattr        = nfs_getattr,
+       .setattr        = nfs_setattr,
+};
+
 const struct nfs_rpc_ops nfs_v2_clientops = {
        .version        = 2,                   /* protocol version */
        .dentry_ops     = &nfs_dentry_operations,
@@ -767,9 +799,11 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
        .pathconf       = nfs_proc_pathconf,
        .decode_dirent  = nfs2_decode_dirent,
        .read_setup     = nfs_proc_read_setup,
+       .read_pageio_init = nfs_pageio_init_read,
        .read_rpc_prepare = nfs_proc_read_rpc_prepare,
        .read_done      = nfs_read_done,
        .write_setup    = nfs_proc_write_setup,
+       .write_pageio_init = nfs_pageio_init_write,
        .write_rpc_prepare = nfs_proc_write_rpc_prepare,
        .write_done     = nfs_write_done,
        .commit_setup   = nfs_proc_commit_setup,
@@ -777,5 +811,9 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
        .lock           = nfs_proc_lock,
        .lock_check_bounds = nfs_lock_check_bounds,
        .close_context  = nfs_close_context,
+       .have_delegation = nfs_have_delegation,
+       .return_delegation = nfs_return_delegation,
+       .alloc_client   = nfs_alloc_client,
        .init_client    = nfs_init_client,
+       .free_client    = nfs_free_client,
 };
index 86ced78362142119328ad827138c0c716668aeac..6267b873bbcbc8f4b13ec887a29d5e5cdbae06d6 100644 (file)
@@ -20,8 +20,6 @@
 #include <linux/nfs_page.h>
 #include <linux/module.h>
 
-#include "pnfs.h"
-
 #include "nfs4_fs.h"
 #include "internal.h"
 #include "iostat.h"
@@ -108,7 +106,7 @@ int nfs_return_empty_page(struct page *page)
        return 0;
 }
 
-void nfs_pageio_init_read_mds(struct nfs_pageio_descriptor *pgio,
+void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
                              struct inode *inode,
                              const struct nfs_pgio_completion_ops *compl_ops)
 {
@@ -123,14 +121,6 @@ void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio)
 }
 EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds);
 
-void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
-                         struct inode *inode,
-                         const struct nfs_pgio_completion_ops *compl_ops)
-{
-       if (!pnfs_pageio_init_read(pgio, inode, compl_ops))
-               nfs_pageio_init_read_mds(pgio, inode, compl_ops);
-}
-
 int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
                       struct page *page)
 {
@@ -149,7 +139,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
        if (len < PAGE_CACHE_SIZE)
                zero_user_segment(page, len, PAGE_CACHE_SIZE);
 
-       nfs_pageio_init_read(&pgio, inode, &nfs_async_read_completion_ops);
+       NFS_PROTO(inode)->read_pageio_init(&pgio, inode, &nfs_async_read_completion_ops);
        nfs_pageio_add_request(&pgio, new);
        nfs_pageio_complete(&pgio);
        NFS_I(inode)->read_io += pgio.pg_bytes_written;
@@ -652,7 +642,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
        if (ret == 0)
                goto read_complete; /* all pages were read */
 
-       nfs_pageio_init_read(&pgio, inode, &nfs_async_read_completion_ops);
+       NFS_PROTO(inode)->read_pageio_init(&pgio, inode, &nfs_async_read_completion_ops);
 
        ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
 
index 8b2a2977b720729f2a63a4d7bb8e5e4b7de5522e..95866a8c21bb5e651e7ba9c01e9d45c9dcb92c79 100644 (file)
@@ -278,29 +278,8 @@ static match_table_t nfs_vers_tokens = {
        { Opt_vers_err, NULL }
 };
 
-struct nfs_mount_info {
-       void (*fill_super)(struct super_block *, struct nfs_mount_info *);
-       int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *);
-       struct nfs_parsed_mount_data *parsed;
-       struct nfs_clone_mount *cloned;
-       struct nfs_fh *mntfh;
-};
-
-static void nfs_umount_begin(struct super_block *);
-static int  nfs_statfs(struct dentry *, struct kstatfs *);
-static int  nfs_show_options(struct seq_file *, struct dentry *);
-static int  nfs_show_devname(struct seq_file *, struct dentry *);
-static int  nfs_show_path(struct seq_file *, struct dentry *);
-static int  nfs_show_stats(struct seq_file *, struct dentry *);
-static struct dentry *nfs_fs_mount_common(struct file_system_type *,
-               struct nfs_server *, int, const char *, struct nfs_mount_info *);
-static struct dentry *nfs_fs_mount(struct file_system_type *,
-               int, const char *, void *);
 static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type,
                int flags, const char *dev_name, void *raw_data);
-static void nfs_put_super(struct super_block *);
-static void nfs_kill_super(struct super_block *);
-static int nfs_remount(struct super_block *sb, int *flags, char *raw_data);
 
 static struct file_system_type nfs_fs_type = {
        .owner          = THIS_MODULE,
@@ -337,72 +316,6 @@ static const struct super_operations nfs_sops = {
 static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *);
 static int nfs4_validate_mount_data(void *options,
        struct nfs_parsed_mount_data *args, const char *dev_name);
-static struct dentry *nfs4_try_mount(int flags, const char *dev_name,
-       struct nfs_mount_info *mount_info);
-static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *raw_data);
-static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *raw_data);
-static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *raw_data);
-static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *raw_data);
-static void nfs4_kill_super(struct super_block *sb);
-
-static struct file_system_type nfs4_fs_type = {
-       .owner          = THIS_MODULE,
-       .name           = "nfs4",
-       .mount          = nfs_fs_mount,
-       .kill_sb        = nfs4_kill_super,
-       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
-};
-
-static struct file_system_type nfs4_remote_fs_type = {
-       .owner          = THIS_MODULE,
-       .name           = "nfs4",
-       .mount          = nfs4_remote_mount,
-       .kill_sb        = nfs4_kill_super,
-       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
-};
-
-struct file_system_type nfs4_xdev_fs_type = {
-       .owner          = THIS_MODULE,
-       .name           = "nfs4",
-       .mount          = nfs4_xdev_mount,
-       .kill_sb        = nfs4_kill_super,
-       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
-};
-
-static struct file_system_type nfs4_remote_referral_fs_type = {
-       .owner          = THIS_MODULE,
-       .name           = "nfs4",
-       .mount          = nfs4_remote_referral_mount,
-       .kill_sb        = nfs4_kill_super,
-       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
-};
-
-struct file_system_type nfs4_referral_fs_type = {
-       .owner          = THIS_MODULE,
-       .name           = "nfs4",
-       .mount          = nfs4_referral_mount,
-       .kill_sb        = nfs4_kill_super,
-       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
-};
-
-static const struct super_operations nfs4_sops = {
-       .alloc_inode    = nfs_alloc_inode,
-       .destroy_inode  = nfs_destroy_inode,
-       .write_inode    = nfs_write_inode,
-       .put_super      = nfs_put_super,
-       .statfs         = nfs_statfs,
-       .evict_inode    = nfs4_evict_inode,
-       .umount_begin   = nfs_umount_begin,
-       .show_options   = nfs_show_options,
-       .show_devname   = nfs_show_devname,
-       .show_path      = nfs_show_path,
-       .show_stats     = nfs_show_stats,
-       .remount_fs     = nfs_remount,
-};
 #endif
 
 static struct shrinker acl_shrinker = {
@@ -424,18 +337,9 @@ int __init register_nfs_fs(void)
        ret = nfs_register_sysctl();
        if (ret < 0)
                goto error_1;
-#ifdef CONFIG_NFS_V4
-       ret = register_filesystem(&nfs4_fs_type);
-       if (ret < 0)
-               goto error_2;
-#endif
        register_shrinker(&acl_shrinker);
        return 0;
 
-#ifdef CONFIG_NFS_V4
-error_2:
-       nfs_unregister_sysctl();
-#endif
 error_1:
        unregister_filesystem(&nfs_fs_type);
 error_0:
@@ -448,9 +352,6 @@ error_0:
 void __exit unregister_nfs_fs(void)
 {
        unregister_shrinker(&acl_shrinker);
-#ifdef CONFIG_NFS_V4
-       unregister_filesystem(&nfs4_fs_type);
-#endif
        nfs_unregister_sysctl();
        unregister_filesystem(&nfs_fs_type);
 }
@@ -474,7 +375,7 @@ void nfs_sb_deactive(struct super_block *sb)
 /*
  * Deliver file system statistics to userspace
  */
-static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct nfs_server *server = NFS_SB(dentry->d_sb);
        unsigned char blockbits;
@@ -757,7 +658,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
 /*
  * Describe the mount options on this VFS mountpoint
  */
-static int nfs_show_options(struct seq_file *m, struct dentry *root)
+int nfs_show_options(struct seq_file *m, struct dentry *root)
 {
        struct nfs_server *nfss = NFS_SB(root->d_sb);
 
@@ -815,7 +716,7 @@ static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss)
 }
 #endif
 
-static int nfs_show_devname(struct seq_file *m, struct dentry *root)
+int nfs_show_devname(struct seq_file *m, struct dentry *root)
 {
        char *page = (char *) __get_free_page(GFP_KERNEL);
        char *devname, *dummy;
@@ -831,7 +732,7 @@ static int nfs_show_devname(struct seq_file *m, struct dentry *root)
        return err;
 }
 
-static int nfs_show_path(struct seq_file *m, struct dentry *dentry)
+int nfs_show_path(struct seq_file *m, struct dentry *dentry)
 {
        seq_puts(m, "/");
        return 0;
@@ -840,7 +741,7 @@ static int nfs_show_path(struct seq_file *m, struct dentry *dentry)
 /*
  * Present statistical information for this VFS mountpoint
  */
-static int nfs_show_stats(struct seq_file *m, struct dentry *root)
+int nfs_show_stats(struct seq_file *m, struct dentry *root)
 {
        int i, cpu;
        struct nfs_server *nfss = NFS_SB(root->d_sb);
@@ -933,7 +834,7 @@ static int nfs_show_stats(struct seq_file *m, struct dentry *root)
  * Begin unmount by attempting to remove all automounted mountpoints we added
  * in response to xdev traversals and referrals
  */
-static void nfs_umount_begin(struct super_block *sb)
+void nfs_umount_begin(struct super_block *sb)
 {
        struct nfs_server *server;
        struct rpc_clnt *rpc;
@@ -2108,7 +2009,7 @@ nfs_compare_remount_data(struct nfs_server *nfss,
        return 0;
 }
 
-static int
+int
 nfs_remount(struct super_block *sb, int *flags, char *raw_data)
 {
        int error;
@@ -2173,7 +2074,7 @@ out:
 /*
  * Initialise the common bits of the superblock
  */
-static inline void nfs_initialise_sb(struct super_block *sb)
+inline void nfs_initialise_sb(struct super_block *sb)
 {
        struct nfs_server *server = NFS_SB(sb);
 
@@ -2195,8 +2096,7 @@ static inline void nfs_initialise_sb(struct super_block *sb)
 /*
  * Finish setting up an NFS2/3 superblock
  */
-static void nfs_fill_super(struct super_block *sb,
-                          struct nfs_mount_info *mount_info)
+void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
 {
        struct nfs_parsed_mount_data *data = mount_info->parsed;
        struct nfs_server *server = NFS_SB(sb);
@@ -2219,10 +2119,9 @@ static void nfs_fill_super(struct super_block *sb,
 }
 
 /*
- * Finish setting up a cloned NFS2/3 superblock
+ * Finish setting up a cloned NFS2/3/4 superblock
  */
-static void nfs_clone_super(struct super_block *sb,
-                           struct nfs_mount_info *mount_info)
+void nfs_clone_super(struct super_block *sb, struct nfs_mount_info *mount_info)
 {
        const struct super_block *old_sb = mount_info->cloned->sb;
        struct nfs_server *server = NFS_SB(sb);
@@ -2230,16 +2129,17 @@ static void nfs_clone_super(struct super_block *sb,
        sb->s_blocksize_bits = old_sb->s_blocksize_bits;
        sb->s_blocksize = old_sb->s_blocksize;
        sb->s_maxbytes = old_sb->s_maxbytes;
+       sb->s_xattr = old_sb->s_xattr;
+       sb->s_op = old_sb->s_op;
+       sb->s_time_gran = 1;
 
-       if (server->nfs_client->rpc_ops->version == 3) {
+       if (server->nfs_client->rpc_ops->version != 2) {
                /* The VFS shouldn't apply the umask to mode bits. We will do
                 * so ourselves when necessary.
                 */
                sb->s_flags |= MS_POSIXACL;
-               sb->s_time_gran = 1;
        }
 
-       sb->s_op = old_sb->s_op;
        nfs_initialise_sb(sb);
 }
 
@@ -2381,14 +2281,14 @@ static int nfs_bdi_register(struct nfs_server *server)
        return bdi_register_dev(&server->backing_dev_info, server->s_dev);
 }
 
-static int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot,
-                              struct nfs_mount_info *mount_info)
+int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot,
+                       struct nfs_mount_info *mount_info)
 {
        return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts);
 }
 
-static int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
-                                struct nfs_mount_info *mount_info)
+int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
+                         struct nfs_mount_info *mount_info)
 {
        /* clone any lsm security options from the parent to the new sb */
        security_sb_clone_mnt_opts(mount_info->cloned->sb, s);
@@ -2397,10 +2297,10 @@ static int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
        return 0;
 }
 
-static struct dentry *nfs_fs_mount_common(struct file_system_type *fs_type,
-                                         struct nfs_server *server,
-                                         int flags, const char *dev_name,
-                                         struct nfs_mount_info *mount_info)
+struct dentry *nfs_fs_mount_common(struct file_system_type *fs_type,
+                                  struct nfs_server *server,
+                                  int flags, const char *dev_name,
+                                  struct nfs_mount_info *mount_info)
 {
        struct super_block *s;
        struct dentry *mntroot = ERR_PTR(-ENOMEM);
@@ -2470,7 +2370,7 @@ error_splat_bdi:
        goto out;
 }
 
-static struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
+struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *raw_data)
 {
        struct nfs_mount_info mount_info = {
@@ -2511,7 +2411,7 @@ out:
  * Ensure that we unregister the bdi before kill_anon_super
  * releases the device name
  */
-static void nfs_put_super(struct super_block *s)
+void nfs_put_super(struct super_block *s)
 {
        struct nfs_server *server = NFS_SB(s);
 
@@ -2521,7 +2421,7 @@ static void nfs_put_super(struct super_block *s)
 /*
  * Destroy an NFS2/3 superblock
  */
-static void nfs_kill_super(struct super_block *s)
+void nfs_kill_super(struct super_block *s)
 {
        struct nfs_server *server = NFS_SB(s);
 
@@ -2533,7 +2433,7 @@ static void nfs_kill_super(struct super_block *s)
 /*
  * Clone an NFS2/3/4 server record on xdev traversal (FSID-change)
  */
-static struct dentry *
+struct dentry *
 nfs_xdev_mount_common(struct file_system_type *fs_type, int flags,
                const char *dev_name, struct nfs_mount_info *mount_info)
 {
@@ -2580,44 +2480,6 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags,
 
 #ifdef CONFIG_NFS_V4
 
-/*
- * Finish setting up a cloned NFS4 superblock
- */
-static void nfs4_clone_super(struct super_block *sb,
-                            struct nfs_mount_info *mount_info)
-{
-       const struct super_block *old_sb = mount_info->cloned->sb;
-       sb->s_blocksize_bits = old_sb->s_blocksize_bits;
-       sb->s_blocksize = old_sb->s_blocksize;
-       sb->s_maxbytes = old_sb->s_maxbytes;
-       sb->s_time_gran = 1;
-       sb->s_op = old_sb->s_op;
-       /*
-        * The VFS shouldn't apply the umask to mode bits. We will do
-        * so ourselves when necessary.
-        */
-       sb->s_flags  |= MS_POSIXACL;
-       sb->s_xattr  = old_sb->s_xattr;
-       nfs_initialise_sb(sb);
-}
-
-/*
- * Set up an NFS4 superblock
- */
-static void nfs4_fill_super(struct super_block *sb,
-                           struct nfs_mount_info *mount_info)
-{
-       sb->s_time_gran = 1;
-       sb->s_op = &nfs4_sops;
-       /*
-        * The VFS shouldn't apply the umask to mode bits. We will do
-        * so ourselves when necessary.
-        */
-       sb->s_flags  |= MS_POSIXACL;
-       sb->s_xattr = nfs4_xattr_handlers;
-       nfs_initialise_sb(sb);
-}
-
 static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
 {
        args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
@@ -2715,250 +2577,4 @@ out_no_address:
        return -EINVAL;
 }
 
-/*
- * Get the superblock for the NFS4 root partition
- */
-static struct dentry *
-nfs4_remote_mount(struct file_system_type *fs_type, int flags,
-                 const char *dev_name, void *info)
-{
-       struct nfs_mount_info *mount_info = info;
-       struct nfs_server *server;
-       struct dentry *mntroot = ERR_PTR(-ENOMEM);
-
-       mount_info->fill_super = nfs4_fill_super;
-       mount_info->set_security = nfs_set_sb_security;
-
-       /* Get a volume representation */
-       server = nfs4_create_server(mount_info->parsed, mount_info->mntfh);
-       if (IS_ERR(server)) {
-               mntroot = ERR_CAST(server);
-               goto out;
-       }
-
-       mntroot = nfs_fs_mount_common(fs_type, server, flags, dev_name, mount_info);
-
-out:
-       return mntroot;
-}
-
-static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
-               int flags, void *data, const char *hostname)
-{
-       struct vfsmount *root_mnt;
-       char *root_devname;
-       size_t len;
-
-       len = strlen(hostname) + 5;
-       root_devname = kmalloc(len, GFP_KERNEL);
-       if (root_devname == NULL)
-               return ERR_PTR(-ENOMEM);
-       /* Does hostname needs to be enclosed in brackets? */
-       if (strchr(hostname, ':'))
-               snprintf(root_devname, len, "[%s]:/", hostname);
-       else
-               snprintf(root_devname, len, "%s:/", hostname);
-       root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data);
-       kfree(root_devname);
-       return root_mnt;
-}
-
-struct nfs_referral_count {
-       struct list_head list;
-       const struct task_struct *task;
-       unsigned int referral_count;
-};
-
-static LIST_HEAD(nfs_referral_count_list);
-static DEFINE_SPINLOCK(nfs_referral_count_list_lock);
-
-static struct nfs_referral_count *nfs_find_referral_count(void)
-{
-       struct nfs_referral_count *p;
-
-       list_for_each_entry(p, &nfs_referral_count_list, list) {
-               if (p->task == current)
-                       return p;
-       }
-       return NULL;
-}
-
-#define NFS_MAX_NESTED_REFERRALS 2
-
-static int nfs_referral_loop_protect(void)
-{
-       struct nfs_referral_count *p, *new;
-       int ret = -ENOMEM;
-
-       new = kmalloc(sizeof(*new), GFP_KERNEL);
-       if (!new)
-               goto out;
-       new->task = current;
-       new->referral_count = 1;
-
-       ret = 0;
-       spin_lock(&nfs_referral_count_list_lock);
-       p = nfs_find_referral_count();
-       if (p != NULL) {
-               if (p->referral_count >= NFS_MAX_NESTED_REFERRALS)
-                       ret = -ELOOP;
-               else
-                       p->referral_count++;
-       } else {
-               list_add(&new->list, &nfs_referral_count_list);
-               new = NULL;
-       }
-       spin_unlock(&nfs_referral_count_list_lock);
-       kfree(new);
-out:
-       return ret;
-}
-
-static void nfs_referral_loop_unprotect(void)
-{
-       struct nfs_referral_count *p;
-
-       spin_lock(&nfs_referral_count_list_lock);
-       p = nfs_find_referral_count();
-       p->referral_count--;
-       if (p->referral_count == 0)
-               list_del(&p->list);
-       else
-               p = NULL;
-       spin_unlock(&nfs_referral_count_list_lock);
-       kfree(p);
-}
-
-static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt,
-               const char *export_path)
-{
-       struct dentry *dentry;
-       int err;
-
-       if (IS_ERR(root_mnt))
-               return ERR_CAST(root_mnt);
-
-       err = nfs_referral_loop_protect();
-       if (err) {
-               mntput(root_mnt);
-               return ERR_PTR(err);
-       }
-
-       dentry = mount_subtree(root_mnt, export_path);
-       nfs_referral_loop_unprotect();
-
-       return dentry;
-}
-
-static struct dentry *nfs4_try_mount(int flags, const char *dev_name,
-                        struct nfs_mount_info *mount_info)
-{
-       char *export_path;
-       struct vfsmount *root_mnt;
-       struct dentry *res;
-       struct nfs_parsed_mount_data *data = mount_info->parsed;
-
-       dfprintk(MOUNT, "--> nfs4_try_mount()\n");
-
-       mount_info->fill_super = nfs4_fill_super;
-
-       export_path = data->nfs_server.export_path;
-       data->nfs_server.export_path = "/";
-       root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
-                       data->nfs_server.hostname);
-       data->nfs_server.export_path = export_path;
-
-       res = nfs_follow_remote_path(root_mnt, export_path);
-
-       dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n",
-                       IS_ERR(res) ? PTR_ERR(res) : 0,
-                       IS_ERR(res) ? " [error]" : "");
-       return res;
-}
-
-static void nfs4_kill_super(struct super_block *sb)
-{
-       struct nfs_server *server = NFS_SB(sb);
-
-       dprintk("--> %s\n", __func__);
-       nfs_super_return_all_delegations(sb);
-       kill_anon_super(sb);
-       nfs_fscache_release_super_cookie(sb);
-       nfs_free_server(server);
-       dprintk("<-- %s\n", __func__);
-}
-
-/*
- * Clone an NFS4 server record on xdev traversal (FSID-change)
- */
-static struct dentry *
-nfs4_xdev_mount(struct file_system_type *fs_type, int flags,
-                const char *dev_name, void *raw_data)
-{
-       struct nfs_mount_info mount_info = {
-               .fill_super = nfs4_clone_super,
-               .set_security = nfs_clone_sb_security,
-               .cloned = raw_data,
-       };
-       return nfs_xdev_mount_common(&nfs4_fs_type, flags, dev_name, &mount_info);
-}
-
-static struct dentry *
-nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
-                          const char *dev_name, void *raw_data)
-{
-       struct nfs_mount_info mount_info = {
-               .fill_super = nfs4_fill_super,
-               .set_security = nfs_clone_sb_security,
-               .cloned = raw_data,
-       };
-       struct nfs_server *server;
-       struct dentry *mntroot = ERR_PTR(-ENOMEM);
-
-       dprintk("--> nfs4_referral_get_sb()\n");
-
-       mount_info.mntfh = nfs_alloc_fhandle();
-       if (mount_info.cloned == NULL || mount_info.mntfh == NULL)
-               goto out;
-
-       /* create a new volume representation */
-       server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh);
-       if (IS_ERR(server)) {
-               mntroot = ERR_CAST(server);
-               goto out;
-       }
-
-       mntroot = nfs_fs_mount_common(&nfs4_fs_type, server, flags, dev_name, &mount_info);
-out:
-       nfs_free_fhandle(mount_info.mntfh);
-       return mntroot;
-}
-
-/*
- * Create an NFS4 server record on referral traversal
- */
-static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
-               int flags, const char *dev_name, void *raw_data)
-{
-       struct nfs_clone_mount *data = raw_data;
-       char *export_path;
-       struct vfsmount *root_mnt;
-       struct dentry *res;
-
-       dprintk("--> nfs4_referral_mount()\n");
-
-       export_path = data->mnt_path;
-       data->mnt_path = "/";
-
-       root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type,
-                       flags, data, data->hostname);
-       data->mnt_path = export_path;
-
-       res = nfs_follow_remote_path(root_mnt, export_path);
-       dprintk("<-- nfs4_referral_mount() = %ld%s\n",
-                       IS_ERR(res) ? PTR_ERR(res) : 0,
-                       IS_ERR(res) ? " [error]" : "");
-       return res;
-}
-
 #endif /* CONFIG_NFS_V4 */
index ad4d2e787b2041d17eaacc4a1ce8097f0cc13aca..6b3f2535a3ec7ae5c840696956288c41dac84021 100644 (file)
@@ -9,37 +9,11 @@
 #include <linux/fs.h>
 #include <linux/sysctl.h>
 #include <linux/module.h>
-#include <linux/nfs4.h>
-#include <linux/nfs_idmap.h>
 #include <linux/nfs_fs.h>
 
-#include "callback.h"
-
-#ifdef CONFIG_NFS_V4
-static const int nfs_set_port_min = 0;
-static const int nfs_set_port_max = 65535;
-#endif
 static struct ctl_table_header *nfs_callback_sysctl_table;
 
 static ctl_table nfs_cb_sysctls[] = {
-#ifdef CONFIG_NFS_V4
-       {
-               .procname = "nfs_callback_tcpport",
-               .data = &nfs_callback_set_tcpport,
-               .maxlen = sizeof(int),
-               .mode = 0644,
-               .proc_handler = proc_dointvec_minmax,
-               .extra1 = (int *)&nfs_set_port_min,
-               .extra2 = (int *)&nfs_set_port_max,
-       },
-       {
-               .procname = "idmap_cache_timeout",
-               .data = &nfs_idmap_cache_timeout,
-               .maxlen = sizeof(int),
-               .mode = 0644,
-               .proc_handler = proc_dointvec_jiffies,
-       },
-#endif
        {
                .procname       = "nfs_mountpoint_timeout",
                .data           = &nfs_mountpoint_expiry_timeout,
index 3210a03342f924e886e5c7f174c9147de54911a4..13cea637eff82288f2f5508023a592e60db3fa7a 100644 (file)
@@ -501,7 +501,7 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)
                (unsigned long long)NFS_FILEID(dentry->d_inode));
 
        /* Return delegation in anticipation of the rename */
-       nfs_inode_return_delegation(dentry->d_inode);
+       NFS_PROTO(dentry->d_inode)->return_delegation(dentry->d_inode);
 
        sdentry = NULL;
        do {
index 4d6861c0dc142a5ec41e5da405012b661aeb3bc4..f312860c15d0e7ce5e9b9e8b2254ce41387edbf3 100644 (file)
@@ -336,8 +336,10 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
        struct nfs_pageio_descriptor pgio;
        int err;
 
-       nfs_pageio_init_write(&pgio, page->mapping->host, wb_priority(wbc),
-                             &nfs_async_write_completion_ops);
+       NFS_PROTO(page->mapping->host)->write_pageio_init(&pgio,
+                                                         page->mapping->host,
+                                                         wb_priority(wbc),
+                                                         &nfs_async_write_completion_ops);
        err = nfs_do_writepage(page, wbc, &pgio);
        nfs_pageio_complete(&pgio);
        if (err < 0)
@@ -380,8 +382,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
 
        nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
 
-       nfs_pageio_init_write(&pgio, inode, wb_priority(wbc),
-                             &nfs_async_write_completion_ops);
+       NFS_PROTO(inode)->write_pageio_init(&pgio, inode, wb_priority(wbc), &nfs_async_write_completion_ops);
        err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
        nfs_pageio_complete(&pgio);
 
@@ -410,7 +411,7 @@ static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
        nfs_lock_request(req);
 
        spin_lock(&inode->i_lock);
-       if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE))
+       if (!nfsi->npages && NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))
                inode->i_version++;
        set_bit(PG_MAPPED, &req->wb_flags);
        SetPagePrivate(req->wb_page);
@@ -620,7 +621,7 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr)
                        goto next;
                }
                if (test_bit(NFS_IOHDR_NEED_COMMIT, &hdr->flags)) {
-                       memcpy(&req->wb_verf, hdr->verf, sizeof(req->wb_verf));
+                       memcpy(&req->wb_verf, &hdr->verf->verifier, sizeof(req->wb_verf));
                        nfs_mark_request_commit(req, hdr->lseg, &cinfo);
                        goto next;
                }
@@ -1202,7 +1203,7 @@ static const struct nfs_pageio_ops nfs_pageio_write_ops = {
        .pg_doio = nfs_generic_pg_writepages,
 };
 
-void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio,
+void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
                               struct inode *inode, int ioflags,
                               const struct nfs_pgio_completion_ops *compl_ops)
 {
@@ -1217,13 +1218,6 @@ void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio)
 }
 EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds);
 
-void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
-                          struct inode *inode, int ioflags,
-                          const struct nfs_pgio_completion_ops *compl_ops)
-{
-       if (!pnfs_pageio_init_write(pgio, inode, ioflags, compl_ops))
-               nfs_pageio_init_write_mds(pgio, inode, ioflags, compl_ops);
-}
 
 void nfs_write_prepare(struct rpc_task *task, void *calldata)
 {
@@ -1547,7 +1541,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
 
                /* Okay, COMMIT succeeded, apparently. Check the verifier
                 * returned by the server against all stored verfs. */
-               if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) {
+               if (!memcmp(&req->wb_verf, &data->verf.verifier, sizeof(req->wb_verf))) {
                        /* We have a match */
                        nfs_inode_remove_request(req);
                        dprintk(" OK\n");
@@ -1677,9 +1671,14 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr
 
 int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
 {
-       int ret;
+       return nfs_commit_unstable_pages(inode, wbc);
+}
+
+#ifdef CONFIG_NFS_V4
+int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc)
+{
+       int ret = nfs_write_inode(inode, wbc);
 
-       ret = nfs_commit_unstable_pages(inode, wbc);
        if (ret >= 0 && test_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags)) {
                int status;
                bool sync = true;
@@ -1693,6 +1692,7 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
        }
        return ret;
 }
+#endif
 
 /*
  * flush the inode to disk.
index ba233499b9a5fc1b374bc7d79ad8f636f01135b0..a3946cf13fc8373d6234c64d4316505364914ca3 100644 (file)
@@ -398,7 +398,7 @@ fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
        int migrated, i, err;
 
        /* listsize */
-       err = get_int(mesg, &fsloc->locations_count);
+       err = get_uint(mesg, &fsloc->locations_count);
        if (err)
                return err;
        if (fsloc->locations_count > MAX_FS_LOCATIONS)
@@ -456,7 +456,7 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
                return -EINVAL;
 
        for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
-               err = get_int(mesg, &f->pseudoflavor);
+               err = get_uint(mesg, &f->pseudoflavor);
                if (err)
                        return err;
                /*
@@ -465,7 +465,7 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
                 * problem at export time instead of when a client fails
                 * to authenticate.
                 */
-               err = get_int(mesg, &f->flags);
+               err = get_uint(mesg, &f->flags);
                if (err)
                        return err;
                /* Only some flags are allowed to differ between flavors: */
@@ -929,7 +929,7 @@ struct svc_export *
 rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
 {
        struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
-       struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
        struct cache_detail *cd = nn->svc_export_cache;
 
        if (rqstp->rq_client == NULL)
@@ -960,7 +960,7 @@ struct svc_export *
 rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
 {
        struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
-       struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
        struct cache_detail *cd = nn->svc_export_cache;
 
        if (rqstp->rq_client == NULL)
index 39365636b244fbfc7aaac3a794f83f87d7ea69a6..65c2431ea32fa6638cc34b8f240b351328bad751 100644 (file)
@@ -34,6 +34,10 @@ struct nfsd_net {
 
        struct cache_detail *idtoname_cache;
        struct cache_detail *nametoid_cache;
+
+       struct lock_manager nfsd4_manager;
+       bool grace_ended;
+       time_t boot_time;
 };
 
 extern int nfsd_net_id;
index a5fd6b982f277ce648bbd528947964ea2ef63c73..cbaf4f8bb7b712be7e92db2a7bf102c1f8c2dc6f 100644 (file)
@@ -756,7 +756,6 @@ static void do_probe_callback(struct nfs4_client *clp)
  */
 void nfsd4_probe_callback(struct nfs4_client *clp)
 {
-       /* XXX: atomicity?  Also, should we be using cl_flags? */
        clp->cl_cb_state = NFSD4_CB_UNKNOWN;
        set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags);
        do_probe_callback(clp);
index dae36f1dee95e68defce943bedf01efc46d61a54..fdc91a6fc9c4e3d50bea67386c463bd50d8c4c12 100644 (file)
@@ -546,7 +546,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
                .type = type,
        };
        int ret;
-       struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        if (namelen + 1 > sizeof(key.name))
                return nfserr_badowner;
@@ -571,7 +571,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
                .type = type,
        };
        int ret;
-       struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
        ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item);
index 987e719fbae8c64f2776f914e7f4104ee04be492..c9c1c0a254170ebc1de0bc70cdcdcce6c8ff5b6d 100644 (file)
@@ -354,10 +354,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        /* Openowner is now set, so sequence id will get bumped.  Now we need
         * these checks before we do any creates: */
        status = nfserr_grace;
-       if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+       if (locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
                goto out;
        status = nfserr_no_grace;
-       if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+       if (!locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
                goto out;
 
        switch (open->op_claim_type) {
@@ -686,7 +686,8 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        nfs4_lock_state();
        /* check stateid */
-       if ((status = nfs4_preprocess_stateid_op(cstate, &read->rd_stateid,
+       if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp),
+                                                cstate, &read->rd_stateid,
                                                 RD_STATE, &read->rd_filp))) {
                dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
                goto out;
@@ -741,7 +742,7 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
        __be32 status;
 
-       if (locks_in_grace())
+       if (locks_in_grace(SVC_NET(rqstp)))
                return nfserr_grace;
        status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
                             remove->rm_name, remove->rm_namelen);
@@ -760,8 +761,8 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        if (!cstate->save_fh.fh_dentry)
                return status;
-       if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags
-                                       & NFSEXP_NOSUBTREECHECK))
+       if (locks_in_grace(SVC_NET(rqstp)) &&
+               !(cstate->save_fh.fh_export->ex_flags & NFSEXP_NOSUBTREECHECK))
                return nfserr_grace;
        status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
                             rename->rn_snamelen, &cstate->current_fh,
@@ -845,7 +846,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
                nfs4_lock_state();
-               status = nfs4_preprocess_stateid_op(cstate,
+               status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate,
                        &setattr->sa_stateid, WR_STATE, NULL);
                nfs4_unlock_state();
                if (status) {
@@ -890,7 +891,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                return nfserr_inval;
 
        nfs4_lock_state();
-       status = nfs4_preprocess_stateid_op(cstate, stateid, WR_STATE, &filp);
+       status = nfs4_preprocess_stateid_op(SVC_NET(rqstp),
+                                       cstate, stateid, WR_STATE, &filp);
        if (filp)
                get_file(filp);
        nfs4_unlock_state();
index 94effd5bc4a107086ef53515ac2bb9dc39950b88..cc894eda385a48d0ecb98f2687ef566815648d75 100644 (file)
 #include <linux/namei.h>
 #include <linux/swap.h>
 #include <linux/pagemap.h>
+#include <linux/ratelimit.h>
 #include <linux/sunrpc/svcauth_gss.h>
 #include <linux/sunrpc/clnt.h>
 #include "xdr4.h"
 #include "vfs.h"
 #include "current_stateid.h"
+#include "fault_inject.h"
+
+#include "netns.h"
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
 /* Globals */
 time_t nfsd4_lease = 90;     /* default lease time */
 time_t nfsd4_grace = 90;
-static time_t boot_time;
 
 #define all_ones {{~0,~0},~0}
 static const stateid_t one_stateid = {
@@ -862,6 +865,11 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses,
        if (ret)
                /* oops; xprt is already down: */
                nfsd4_conn_lost(&conn->cn_xpt_user);
+       if (ses->se_client->cl_cb_state == NFSD4_CB_DOWN &&
+               dir & NFS4_CDFC4_BACK) {
+               /* callback channel may be back up */
+               nfsd4_probe_callback(ses->se_client);
+       }
        return nfs_ok;
 }
 
@@ -1047,12 +1055,12 @@ renew_client(struct nfs4_client *clp)
 
 /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
 static int
-STALE_CLIENTID(clientid_t *clid)
+STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn)
 {
-       if (clid->cl_boot == boot_time)
+       if (clid->cl_boot == nn->boot_time)
                return 0;
        dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n",
-               clid->cl_boot, clid->cl_id, boot_time);
+               clid->cl_boot, clid->cl_id, nn->boot_time);
        return 1;
 }
 
@@ -1215,7 +1223,7 @@ static bool groups_equal(struct group_info *g1, struct group_info *g2)
        return true;
 }
 
-static int
+static bool
 same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
 {
        if ((cr1->cr_flavor != cr2->cr_flavor)
@@ -1227,14 +1235,15 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
                return true;
        if (!cr1->cr_principal || !cr2->cr_principal)
                return false;
-       return 0 == strcmp(cr1->cr_principal, cr1->cr_principal);
+       return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
 }
 
 static void gen_clid(struct nfs4_client *clp)
 {
        static u32 current_clientid = 1;
+       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
 
-       clp->cl_clientid.cl_boot = boot_time;
+       clp->cl_clientid.cl_boot = nn->boot_time;
        clp->cl_clientid.cl_id = current_clientid++; 
 }
 
@@ -2217,8 +2226,9 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
        nfs4_verifier confirm = setclientid_confirm->sc_confirm; 
        clientid_t * clid = &setclientid_confirm->sc_clientid;
        __be32 status;
+       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
 
-       if (STALE_CLIENTID(clid))
+       if (STALE_CLIENTID(clid, nn))
                return nfserr_stale_clientid;
        nfs4_lock_state();
 
@@ -2577,8 +2587,9 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
        unsigned int strhashval;
        struct nfs4_openowner *oo = NULL;
        __be32 status;
+       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
 
-       if (STALE_CLIENTID(&open->op_clientid))
+       if (STALE_CLIENTID(&open->op_clientid, nn))
                return nfserr_stale_clientid;
        /*
         * In case we need it later, after we've already created the
@@ -2876,7 +2887,8 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
  * Attempt to hand out a delegation.
  */
 static void
-nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
+nfs4_open_delegation(struct net *net, struct svc_fh *fh,
+                    struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
 {
        struct nfs4_delegation *dp;
        struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
@@ -2897,7 +2909,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_
                case NFS4_OPEN_CLAIM_NULL:
                        /* Let's not give out any delegations till everyone's
                         * had the chance to reclaim theirs.... */
-                       if (locks_in_grace())
+                       if (locks_in_grace(net))
                                goto out;
                        if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
                                goto out;
@@ -3005,16 +3017,14 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
                        goto out;
        } else {
                status = nfs4_get_vfs_file(rqstp, fp, current_fh, open);
+               if (status)
+                       goto out;
+               status = nfsd4_truncate(rqstp, current_fh, open);
                if (status)
                        goto out;
                stp = open->op_stp;
                open->op_stp = NULL;
                init_open_stateid(stp, fp, open);
-               status = nfsd4_truncate(rqstp, current_fh, open);
-               if (status) {
-                       release_open_stateid(stp);
-                       goto out;
-               }
        }
        update_stateid(&stp->st_stid.sc_stateid);
        memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
@@ -3033,7 +3043,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
        * Attempt to hand out a delegation. No error return, because the
        * OPEN succeeds even if we fail.
        */
-       nfs4_open_delegation(current_fh, open, stp);
+       nfs4_open_delegation(SVC_NET(rqstp), current_fh, open, stp);
 nodeleg:
        status = nfs_ok;
 
@@ -3087,12 +3097,13 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
        struct nfs4_client *clp;
        __be32 status;
+       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
 
        nfs4_lock_state();
        dprintk("process_renew(%08x/%08x): starting\n", 
                        clid->cl_boot, clid->cl_id);
        status = nfserr_stale_clientid;
-       if (STALE_CLIENTID(clid))
+       if (STALE_CLIENTID(clid, nn))
                goto out;
        clp = find_confirmed_client(clid);
        status = nfserr_expired;
@@ -3111,22 +3122,19 @@ out:
        return status;
 }
 
-static struct lock_manager nfsd4_manager = {
-};
-
-static bool grace_ended;
-
 static void
-nfsd4_end_grace(void)
+nfsd4_end_grace(struct net *net)
 {
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
        /* do nothing if grace period already ended */
-       if (grace_ended)
+       if (nn->grace_ended)
                return;
 
        dprintk("NFSD: end of grace period\n");
-       grace_ended = true;
-       nfsd4_record_grace_done(&init_net, boot_time);
-       locks_end_grace(&nfsd4_manager);
+       nn->grace_ended = true;
+       nfsd4_record_grace_done(net, nn->boot_time);
+       locks_end_grace(&nn->nfsd4_manager);
        /*
         * Now that every NFSv4 client has had the chance to recover and
         * to see the (possibly new, possibly shorter) lease time, we
@@ -3149,7 +3157,7 @@ nfs4_laundromat(void)
        nfs4_lock_state();
 
        dprintk("NFSD: laundromat service - starting\n");
-       nfsd4_end_grace();
+       nfsd4_end_grace(&init_net);
        INIT_LIST_HEAD(&reaplist);
        spin_lock(&client_lock);
        list_for_each_safe(pos, next, &client_lru) {
@@ -3231,9 +3239,9 @@ static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *s
 }
 
 static int
-STALE_STATEID(stateid_t *stateid)
+STALE_STATEID(stateid_t *stateid, struct nfsd_net *nn)
 {
-       if (stateid->si_opaque.so_clid.cl_boot == boot_time)
+       if (stateid->si_opaque.so_clid.cl_boot == nn->boot_time)
                return 0;
        dprintk("NFSD: stale stateid " STATEID_FMT "!\n",
                STATEID_VAL(stateid));
@@ -3273,11 +3281,11 @@ out:
 }
 
 static inline __be32
-check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
+check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags)
 {
        if (ONE_STATEID(stateid) && (flags & RD_STATE))
                return nfs_ok;
-       else if (locks_in_grace()) {
+       else if (locks_in_grace(net)) {
                /* Answer in remaining cases depends on existence of
                 * conflicting state; so we must wait out the grace period. */
                return nfserr_grace;
@@ -3294,9 +3302,9 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
  * that are not able to provide mandatory locking.
  */
 static inline int
-grace_disallows_io(struct inode *inode)
+grace_disallows_io(struct net *net, struct inode *inode)
 {
-       return locks_in_grace() && mandatory_lock(inode);
+       return locks_in_grace(net) && mandatory_lock(inode);
 }
 
 /* Returns true iff a is later than b: */
@@ -3333,18 +3341,26 @@ static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_s
        return nfserr_old_stateid;
 }
 
-__be32 nfs4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
+static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 {
        struct nfs4_stid *s;
        struct nfs4_ol_stateid *ols;
        __be32 status;
 
-       if (STALE_STATEID(stateid))
-               return nfserr_stale_stateid;
-
+       if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
+               return nfserr_bad_stateid;
+       /* Client debugging aid. */
+       if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
+               char addr_str[INET6_ADDRSTRLEN];
+               rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str,
+                                sizeof(addr_str));
+               pr_warn_ratelimited("NFSD: client %s testing state ID "
+                                       "with incorrect client ID\n", addr_str);
+               return nfserr_bad_stateid;
+       }
        s = find_stateid(cl, stateid);
        if (!s)
-                return nfserr_stale_stateid;
+               return nfserr_bad_stateid;
        status = check_stateid_generation(stateid, &s->sc_stateid, 1);
        if (status)
                return status;
@@ -3360,10 +3376,11 @@ __be32 nfs4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s)
 {
        struct nfs4_client *cl;
+       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
 
        if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
                return nfserr_bad_stateid;
-       if (STALE_STATEID(stateid))
+       if (STALE_STATEID(stateid, nn))
                return nfserr_stale_stateid;
        cl = find_confirmed_client(&stateid->si_opaque.so_clid);
        if (!cl)
@@ -3379,7 +3396,7 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, s
 * Checks for stateid operations
 */
 __be32
-nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
+nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
                           stateid_t *stateid, int flags, struct file **filpp)
 {
        struct nfs4_stid *s;
@@ -3392,11 +3409,11 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
        if (filpp)
                *filpp = NULL;
 
-       if (grace_disallows_io(ino))
+       if (grace_disallows_io(net, ino))
                return nfserr_grace;
 
        if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
-               return check_special_stateids(current_fh, stateid, flags);
+               return check_special_stateids(net, current_fh, stateid, flags);
 
        status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s);
        if (status)
@@ -3463,7 +3480,8 @@ nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        nfs4_lock_state();
        list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
-               stateid->ts_id_status = nfs4_validate_stateid(cl, &stateid->ts_id_stateid);
+               stateid->ts_id_status =
+                       nfsd4_validate_stateid(cl, &stateid->ts_id_stateid);
        nfs4_unlock_state();
 
        return nfs_ok;
@@ -3750,12 +3768,19 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        nfsd4_close_open_stateid(stp);
        oo->oo_last_closed_stid = stp;
 
-       /* place unused nfs4_stateowners on so_close_lru list to be
-        * released by the laundromat service after the lease period
-        * to enable us to handle CLOSE replay
-        */
-       if (list_empty(&oo->oo_owner.so_stateids))
-               move_to_close_lru(oo);
+       if (list_empty(&oo->oo_owner.so_stateids)) {
+               if (cstate->minorversion) {
+                       release_openowner(oo);
+                       cstate->replay_owner = NULL;
+               } else {
+                       /*
+                        * In the 4.0 case we need to keep the owners around a
+                        * little while to handle CLOSE replay.
+                        */
+                       if (list_empty(&oo->oo_owner.so_stateids))
+                               move_to_close_lru(oo);
+               }
+       }
 out:
        if (!cstate->replay_owner)
                nfs4_unlock_state();
@@ -4027,6 +4052,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        bool new_state = false;
        int lkflg;
        int err;
+       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
 
        dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
                (long long) lock->lk_offset,
@@ -4044,11 +4070,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        nfs4_lock_state();
 
        if (lock->lk_is_new) {
-               /*
-                * Client indicates that this is a new lockowner.
-                * Use open owner and open stateid to create lock owner and
-                * lock stateid.
-                */
                struct nfs4_ol_stateid *open_stp = NULL;
 
                if (nfsd4_has_session(cstate))
@@ -4058,7 +4079,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                                sizeof(clientid_t));
 
                status = nfserr_stale_clientid;
-               if (STALE_CLIENTID(&lock->lk_new_clientid))
+               if (STALE_CLIENTID(&lock->lk_new_clientid, nn))
                        goto out;
 
                /* validate and update open stateid and open seqid */
@@ -4075,17 +4096,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        goto out;
                status = lookup_or_create_lock_state(cstate, open_stp, lock,
                                                        &lock_stp, &new_state);
-               if (status)
-                       goto out;
-       } else {
-               /* lock (lock owner + lock stateid) already exists */
+       } else
                status = nfs4_preprocess_seqid_op(cstate,
                                       lock->lk_old_lock_seqid,
                                       &lock->lk_old_lock_stateid,
                                       NFS4_LOCK_STID, &lock_stp);
-               if (status)
-                       goto out;
-       }
+       if (status)
+               goto out;
        lock_sop = lockowner(lock_stp->st_stateowner);
 
        lkflg = setlkflg(lock->lk_type);
@@ -4094,10 +4111,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                goto out;
 
        status = nfserr_grace;
-       if (locks_in_grace() && !lock->lk_reclaim)
+       if (locks_in_grace(SVC_NET(rqstp)) && !lock->lk_reclaim)
                goto out;
        status = nfserr_no_grace;
-       if (!locks_in_grace() && lock->lk_reclaim)
+       if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim)
                goto out;
 
        locks_init_lock(&file_lock);
@@ -4196,8 +4213,9 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        struct file_lock file_lock;
        struct nfs4_lockowner *lo;
        __be32 status;
+       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
 
-       if (locks_in_grace())
+       if (locks_in_grace(SVC_NET(rqstp)))
                return nfserr_grace;
 
        if (check_lock_length(lockt->lt_offset, lockt->lt_length))
@@ -4206,7 +4224,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        nfs4_lock_state();
 
        status = nfserr_stale_clientid;
-       if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid))
+       if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid, nn))
                goto out;
 
        if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
@@ -4355,6 +4373,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
        struct list_head matches;
        unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
        __be32 status;
+       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
 
        dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
                clid->cl_boot, clid->cl_id);
@@ -4362,7 +4381,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
        /* XXX check for lease expiration */
 
        status = nfserr_stale_clientid;
-       if (STALE_CLIENTID(clid))
+       if (STALE_CLIENTID(clid, nn))
                return status;
 
        nfs4_lock_state();
@@ -4564,7 +4583,7 @@ void nfsd_forget_openowners(u64 num)
        printk(KERN_INFO "NFSD: Forgot %d open owners", count);
 }
 
-int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegation *))
+int nfsd_process_n_delegations(u64 num, struct list_head *list)
 {
        int i, count = 0;
        struct nfs4_file *fp, *fnext;
@@ -4573,7 +4592,7 @@ int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegatio
        for (i = 0; i < FILE_HASH_SIZE; i++) {
                list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) {
                        list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) {
-                               deleg_func(dp);
+                               list_move(&dp->dl_recall_lru, list);
                                if (++count == num)
                                        return count;
                        }
@@ -4586,9 +4605,16 @@ int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegatio
 void nfsd_forget_delegations(u64 num)
 {
        unsigned int count;
+       LIST_HEAD(victims);
+       struct nfs4_delegation *dp, *dnext;
+
+       spin_lock(&recall_lock);
+       count = nfsd_process_n_delegations(num, &victims);
+       spin_unlock(&recall_lock);
 
        nfs4_lock_state();
-       count = nfsd_process_n_delegations(num, unhash_delegation);
+       list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru)
+               unhash_delegation(dp);
        nfs4_unlock_state();
 
        printk(KERN_INFO "NFSD: Forgot %d delegations", count);
@@ -4597,12 +4623,16 @@ void nfsd_forget_delegations(u64 num)
 void nfsd_recall_delegations(u64 num)
 {
        unsigned int count;
+       LIST_HEAD(victims);
+       struct nfs4_delegation *dp, *dnext;
 
-       nfs4_lock_state();
        spin_lock(&recall_lock);
-       count = nfsd_process_n_delegations(num, nfsd_break_one_deleg);
+       count = nfsd_process_n_delegations(num, &victims);
+       list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru) {
+               list_del(&dp->dl_recall_lru);
+               nfsd_break_one_deleg(dp);
+       }
        spin_unlock(&recall_lock);
-       nfs4_unlock_state();
 
        printk(KERN_INFO "NFSD: Recalled %d delegations", count);
 }
@@ -4665,6 +4695,8 @@ set_max_delegations(void)
 int
 nfs4_state_start(void)
 {
+       struct net *net = &init_net;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
        int ret;
 
        /*
@@ -4674,11 +4706,11 @@ nfs4_state_start(void)
         * to that instead and then do most of the rest of this on a per-net
         * basis.
         */
-       get_net(&init_net);
-       nfsd4_client_tracking_init(&init_net);
-       boot_time = get_seconds();
-       locks_start_grace(&nfsd4_manager);
-       grace_ended = false;
+       get_net(net);
+       nfsd4_client_tracking_init(net);
+       nn->boot_time = get_seconds();
+       locks_start_grace(net, &nn->nfsd4_manager);
+       nn->grace_ended = false;
        printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
               nfsd4_grace);
        ret = set_callback_cred();
@@ -4700,8 +4732,8 @@ nfs4_state_start(void)
 out_free_laundry:
        destroy_workqueue(laundry_wq);
 out_recovery:
-       nfsd4_client_tracking_exit(&init_net);
-       put_net(&init_net);
+       nfsd4_client_tracking_exit(net);
+       put_net(net);
        return ret;
 }
 
@@ -4742,9 +4774,12 @@ __nfs4_state_shutdown(void)
 void
 nfs4_state_shutdown(void)
 {
+       struct net *net = &init_net;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
        cancel_delayed_work_sync(&laundromat_work);
        destroy_workqueue(laundry_wq);
-       locks_end_grace(&nfsd4_manager);
+       locks_end_grace(&nn->nfsd4_manager);
        nfs4_lock_state();
        __nfs4_state_shutdown();
        nfs4_unlock_state();
index 4949667c84ea0c3d687a46faf0a455c410c39b6f..6322df36031f34c62f273f2d36630a472e991416 100644 (file)
@@ -2259,7 +2259,7 @@ out_acl:
        if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) {
                if ((buflen -= 4) < 0)
                        goto out_resource;
-               WRITE32(1);
+               WRITE32(0);
        }
        if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) {
                if ((buflen -= 4) < 0)
index c55298ed5772577e5afe3bd613c3e5a0df3b69dd..fa49cff5ee651b9aa0b16f9cb43804f616aedc4e 100644 (file)
@@ -673,9 +673,7 @@ static ssize_t __write_ports_addfd(char *buf)
 
        err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
        if (err < 0) {
-               if (nfsd_serv->sv_nrthreads == 1)
-                       svc_shutdown_net(nfsd_serv, net);
-               svc_destroy(nfsd_serv);
+               nfsd_destroy(net);
                return err;
        }
 
@@ -744,9 +742,7 @@ out_close:
                svc_xprt_put(xprt);
        }
 out_err:
-       if (nfsd_serv->sv_nrthreads == 1)
-               svc_shutdown_net(nfsd_serv, net);
-       svc_destroy(nfsd_serv);
+       nfsd_destroy(net);
        return err;
 }
 
index 1671429ffa66fa1db509fbb212a09ad80d49efa8..2244222368ab29cf4681d0d94012055bc5861f02 100644 (file)
@@ -72,6 +72,19 @@ int          nfsd_nrthreads(void);
 int            nfsd_nrpools(void);
 int            nfsd_get_nrthreads(int n, int *);
 int            nfsd_set_nrthreads(int n, int *);
+int            nfsd_pool_stats_open(struct inode *, struct file *);
+int            nfsd_pool_stats_release(struct inode *, struct file *);
+
+static inline void nfsd_destroy(struct net *net)
+{
+       int destroy = (nfsd_serv->sv_nrthreads == 1);
+
+       if (destroy)
+               svc_shutdown_net(nfsd_serv, net);
+       svc_destroy(nfsd_serv);
+       if (destroy)
+               nfsd_serv = NULL;
+}
 
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 #ifdef CONFIG_NFSD_V2_ACL
index ee709fc8f58bc0b62a3f7ca64104630fe803b6d0..240473cb708ff8a726d2b881d9d7ec2b42339653 100644 (file)
@@ -254,8 +254,6 @@ static void nfsd_shutdown(void)
 
 static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
 {
-       /* When last nfsd thread exits we need to do some clean-up */
-       nfsd_serv = NULL;
        nfsd_shutdown();
 
        svc_rpcb_cleanup(serv, net);
@@ -332,6 +330,7 @@ static int nfsd_get_default_max_blksize(void)
 int nfsd_create_serv(void)
 {
        int error;
+       struct net *net = current->nsproxy->net_ns;
 
        WARN_ON(!mutex_is_locked(&nfsd_mutex));
        if (nfsd_serv) {
@@ -346,7 +345,7 @@ int nfsd_create_serv(void)
        if (nfsd_serv == NULL)
                return -ENOMEM;
 
-       error = svc_bind(nfsd_serv, current->nsproxy->net_ns);
+       error = svc_bind(nfsd_serv, net);
        if (error < 0) {
                svc_destroy(nfsd_serv);
                return error;
@@ -427,11 +426,7 @@ int nfsd_set_nrthreads(int n, int *nthreads)
                if (err)
                        break;
        }
-
-       if (nfsd_serv->sv_nrthreads == 1)
-               svc_shutdown_net(nfsd_serv, net);
-       svc_destroy(nfsd_serv);
-
+       nfsd_destroy(net);
        return err;
 }
 
@@ -478,9 +473,7 @@ out_shutdown:
        if (error < 0 && !nfsd_up_before)
                nfsd_shutdown();
 out_destroy:
-       if (nfsd_serv->sv_nrthreads == 1)
-               svc_shutdown_net(nfsd_serv, net);
-       svc_destroy(nfsd_serv);         /* Release server */
+       nfsd_destroy(net);              /* Release server */
 out:
        mutex_unlock(&nfsd_mutex);
        return error;
@@ -563,12 +556,13 @@ nfsd(void *vrqstp)
        nfsdstats.th_cnt --;
 
 out:
-       if (rqstp->rq_server->sv_nrthreads == 1)
-               svc_shutdown_net(rqstp->rq_server, &init_net);
+       rqstp->rq_server = NULL;
 
        /* Release the thread */
        svc_exit_thread(rqstp);
 
+       nfsd_destroy(&init_net);
+
        /* Release module */
        mutex_unlock(&nfsd_mutex);
        module_put_and_exit(0);
@@ -682,9 +676,7 @@ int nfsd_pool_stats_release(struct inode *inode, struct file *file)
 
        mutex_lock(&nfsd_mutex);
        /* this function really, really should have been called svc_put() */
-       if (nfsd_serv->sv_nrthreads == 1)
-               svc_shutdown_net(nfsd_serv, net);
-       svc_destroy(nfsd_serv);
+       nfsd_destroy(net);
        mutex_unlock(&nfsd_mutex);
        return ret;
 }
index 849091e16ea6afd43e4ddd2dbd17962fdd87ad85..e6173147f9821c816527e0bde05289d392374af7 100644 (file)
@@ -450,8 +450,10 @@ static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s)
 #define WR_STATE               0x00000020
 
 struct nfsd4_compound_state;
+struct nfsd_net;
 
-extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
+extern __be32 nfs4_preprocess_stateid_op(struct net *net,
+               struct nfsd4_compound_state *cstate,
                stateid_t *stateid, int flags, struct file **filp);
 extern void nfs4_lock_state(void);
 extern void nfs4_unlock_state(void);
@@ -475,7 +477,6 @@ extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
 extern int nfs4_client_to_reclaim(const char *name);
 extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
 extern void release_session_client(struct nfsd4_session *);
-extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
 extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
 
 /* nfs4recover operations */
index 4700a0a929d72baeb0c86024a1c5051e6d19cab5..702f64e820c301992afda8adecf6d06dc4746c22 100644 (file)
@@ -757,8 +757,16 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
         * If we get here, then the client has already done an "open",
         * and (hopefully) checked permission - so allow OWNER_OVERRIDE
         * in case a chmod has now revoked permission.
+        *
+        * Arguably we should also allow the owner override for
+        * directories, but we never have and it doesn't seem to have
+        * caused anyone a problem.  If we were to change this, note
+        * also that our filldir callbacks would need a variant of
+        * lookup_one_len that doesn't check permissions.
         */
-       err = fh_verify(rqstp, fhp, type, may_flags | NFSD_MAY_OWNER_OVERRIDE);
+       if (type == S_IFREG)
+               may_flags |= NFSD_MAY_OWNER_OVERRIDE;
+       err = fh_verify(rqstp, fhp, type, may_flags);
        if (err)
                goto out;
 
index f5fde36b9e28d09f07596d23b127005fcb26384e..fb7238100548e3e3ba1dcc0c75b362a930a22718 100644 (file)
@@ -76,15 +76,23 @@ int nilfs_palloc_freev(struct inode *, __u64 *, size_t);
 #define nilfs_clear_bit_atomic         ext2_clear_bit_atomic
 #define nilfs_find_next_zero_bit       find_next_zero_bit_le
 
-/*
- * persistent object allocator cache
+/**
+ * struct nilfs_bh_assoc - block offset and buffer head association
+ * @blkoff: block offset
+ * @bh: buffer head
  */
-
 struct nilfs_bh_assoc {
        unsigned long blkoff;
        struct buffer_head *bh;
 };
 
+/**
+ * struct nilfs_palloc_cache - persistent object allocator cache
+ * @lock: cache protecting lock
+ * @prev_desc: blockgroup descriptors cache
+ * @prev_bitmap: blockgroup bitmap cache
+ * @prev_entry: translation entries cache
+ */
 struct nilfs_palloc_cache {
        spinlock_t lock;
        struct nilfs_bh_assoc prev_desc;
index 40d9f453d31c121d29dc09279bfa57ece7d79d7d..b89e68076adc262b737c44a0b04104f56a790bd1 100644 (file)
@@ -135,6 +135,13 @@ struct nilfs_bmap {
 /* state */
 #define NILFS_BMAP_DIRTY       0x00000001
 
+/**
+ * struct nilfs_bmap_store - shadow copy of bmap state
+ * @data: cached raw block mapping of on-disk inode
+ * @last_allocated_key: cached value of last allocated key for data block
+ * @last_allocated_ptr: cached value of last allocated ptr for data block
+ * @state: cached value of state field of bmap structure
+ */
 struct nilfs_bmap_store {
        __le64 data[NILFS_BMAP_SIZE / sizeof(__le64)];
        __u64 last_allocated_key;
index 3a4dd2d8d3fc9fe47fceec0aed1a0e09837449e4..d876b565ce64863812da3d780a7e25be76c0e531 100644 (file)
 #include <linux/fs.h>
 #include <linux/backing-dev.h>
 
-
+/**
+ * struct nilfs_btnode_chkey_ctxt - change key context
+ * @oldkey: old key of block's moving content
+ * @newkey: new key for block's content
+ * @bh: buffer head of old buffer
+ * @newbh: buffer head of new buffer
+ */
 struct nilfs_btnode_chkey_ctxt {
        __u64 oldkey;
        __u64 newkey;
index dab5c4c6dfaf1d13079bc5a088cbb5f379a6cb1d..deaa3d33a0aafa7a6cc303a263288784d03e002f 100644 (file)
@@ -286,7 +286,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
        __u64 cno;
        void *kaddr;
        unsigned long tnicps;
-       int ret, ncps, nicps, count, i;
+       int ret, ncps, nicps, nss, count, i;
 
        if (unlikely(start == 0 || start > end)) {
                printk(KERN_ERR "%s: invalid range of checkpoint numbers: "
@@ -301,6 +301,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
        if (ret < 0)
                goto out_sem;
        tnicps = 0;
+       nss = 0;
 
        for (cno = start; cno < end; cno += ncps) {
                ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, end);
@@ -318,8 +319,9 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
                        cpfile, cno, cp_bh, kaddr);
                nicps = 0;
                for (i = 0; i < ncps; i++, cp = (void *)cp + cpsz) {
-                       WARN_ON(nilfs_checkpoint_snapshot(cp));
-                       if (!nilfs_checkpoint_invalid(cp)) {
+                       if (nilfs_checkpoint_snapshot(cp)) {
+                               nss++;
+                       } else if (!nilfs_checkpoint_invalid(cp)) {
                                nilfs_checkpoint_set_invalid(cp);
                                nicps++;
                        }
@@ -364,6 +366,8 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
        }
 
        brelse(header_bh);
+       if (nss > 0)
+               ret = -EBUSY;
 
  out_sem:
        up_write(&NILFS_MDT(cpfile)->mi_sem);
index b5c13f3576b935a556334692dac6df65c6bfc031..fa0f80308c2dce70d89bf6e459119c9b18543d27 100644 (file)
 #define NILFS_CNO_MIN  ((__u64)1)
 #define NILFS_CNO_MAX  (~(__u64)0)
 
+/**
+ * struct nilfs_dat_info - on-memory private data of DAT file
+ * @mi: on-memory private data of metadata file
+ * @palloc_cache: persistent object allocator cache of DAT file
+ * @shadow: shadow map of DAT file
+ */
 struct nilfs_dat_info {
        struct nilfs_mdt_info mi;
        struct nilfs_palloc_cache palloc_cache;
index a71cc412b651830184d77368349338a0bb4618f2..19ccbf9522ab3f826af531c328d73b8b4ce5ec42 100644 (file)
@@ -5,6 +5,14 @@
 
 extern const struct export_operations nilfs_export_ops;
 
+/**
+ * struct nilfs_fid - NILFS file id type
+ * @cno: checkpoint number
+ * @ino: inode number
+ * @gen: file generation (version) for NFS
+ * @parent_gen: parent generation (version) for NFS
+ * @parent_ino: parent inode number
+ */
 struct nilfs_fid {
        u64 cno;
        u64 ino;
index 5a48df79d6742caad1bdfc73d2ffa5760a3eaeba..d8e65bde083c0c46fb157d321d8ed63a6a6e0ad0 100644 (file)
 #include "alloc.h"
 #include "ifile.h"
 
-
+/**
+ * struct nilfs_ifile_info - on-memory private data of ifile
+ * @mi: on-memory private data of metadata file
+ * @palloc_cache: persistent object allocator cache of ifile
+ */
 struct nilfs_ifile_info {
        struct nilfs_mdt_info mi;
        struct nilfs_palloc_cache palloc_cache;
index 7cc64465ec2699960f045f37cd29bab8931c76ff..6e2c3db976b2a8d4b2d5bb6fdd877660fb86b0b7 100644 (file)
 #include "cpfile.h"
 #include "ifile.h"
 
+/**
+ * struct nilfs_iget_args - arguments used during comparison between inodes
+ * @ino: inode number
+ * @cno: checkpoint number
+ * @root: pointer on NILFS root object (mounted checkpoint)
+ * @for_gc: inode for GC flag
+ */
 struct nilfs_iget_args {
        u64 ino;
        __u64 cno;
index 06658caa18bd229ab42e01b876538efaf2c48882..0b6387c67e6ca601d91fe75684fede7826c6f11f 100644 (file)
@@ -182,7 +182,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
        if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
                goto out;
 
-       down_read(&inode->i_sb->s_umount);
+       mutex_lock(&nilfs->ns_snapshot_mount_mutex);
 
        nilfs_transaction_begin(inode->i_sb, &ti, 0);
        ret = nilfs_cpfile_change_cpmode(
@@ -192,7 +192,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
        else
                nilfs_transaction_commit(inode->i_sb); /* never fails */
 
-       up_read(&inode->i_sb->s_umount);
+       mutex_unlock(&nilfs->ns_snapshot_mount_mutex);
 out:
        mnt_drop_write_file(filp);
        return ret;
index ab20a4baa50fa3a41ea735fe891848f8abfb581f..ab172e8549c57ce5ca20cfe4d7e215f6c41dd679 100644 (file)
 #include "nilfs.h"
 #include "page.h"
 
+/**
+ * struct nilfs_shadow_map - shadow mapping of meta data file
+ * @bmap_store: shadow copy of bmap state
+ * @frozen_data: shadowed dirty data pages
+ * @frozen_btnodes: shadowed dirty b-tree nodes' pages
+ * @frozen_buffers: list of frozen buffers
+ */
 struct nilfs_shadow_map {
        struct nilfs_bmap_store bmap_store;
        struct address_space frozen_data;
index 250add84da768e0a66118edd3e246e95bcb2e628..74cece80e9a32c302e8a7f433234d4b196914adf 100644 (file)
 #include "the_nilfs.h"
 #include "bmap.h"
 
-/*
- * nilfs inode data in memory
+/**
+ * struct nilfs_inode_info - nilfs inode data in memory
+ * @i_flags: inode flags
+ * @i_state: dynamic state flags
+ * @i_bmap: pointer on i_bmap_data
+ * @i_bmap_data: raw block mapping
+ * @i_xattr: <TODO>
+ * @i_dir_start_lookup: page index of last successful search
+ * @i_cno: checkpoint number for GC inode
+ * @i_btnode_cache: cached pages of b-tree nodes
+ * @i_dirty: list for connecting dirty files
+ * @xattr_sem: semaphore for extended attributes processing
+ * @i_bh: buffer contains disk inode
+ * @i_root: root object of the current filesystem tree
+ * @vfs_inode: VFS inode object
  */
 struct nilfs_inode_info {
        __u32 i_flags;
index c5b7653a43910414007a954181d88f789b687158..3127e9f438a7c22e7e00d54288209bf0c8c02659 100644 (file)
 #include "mdt.h"
 #include "sufile.h"
 
-
+/**
+ * struct nilfs_sufile_info - on-memory private data of sufile
+ * @mi: on-memory private data of metadata file
+ * @ncleansegs: number of clean segments
+ * @allocmin: lower limit of allocatable segment range
+ * @allocmax: upper limit of allocatable segment range
+ */
 struct nilfs_sufile_info {
        struct nilfs_mdt_info mi;
        unsigned long ncleansegs;/* number of clean segments */
index d57c42f974ea3ccb78dfccccc34cbbedf9603004..6522cac6057c900fccdac3138475ea4c0aa0a830 100644 (file)
@@ -677,7 +677,6 @@ static const struct super_operations nilfs_sops = {
        .destroy_inode  = nilfs_destroy_inode,
        .dirty_inode    = nilfs_dirty_inode,
        /* .write_inode    = nilfs_write_inode, */
-       /* .put_inode      = nilfs_put_inode, */
        /* .drop_inode    = nilfs_drop_inode, */
        .evict_inode    = nilfs_evict_inode,
        .put_super      = nilfs_put_super,
@@ -685,8 +684,6 @@ static const struct super_operations nilfs_sops = {
        .sync_fs        = nilfs_sync_fs,
        .freeze_fs      = nilfs_freeze,
        .unfreeze_fs    = nilfs_unfreeze,
-       /* .write_super_lockfs */
-       /* .unlockfs */
        .statfs         = nilfs_statfs,
        .remount_fs     = nilfs_remount,
        /* .umount_begin */
@@ -948,6 +945,8 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno,
        struct nilfs_root *root;
        int ret;
 
+       mutex_lock(&nilfs->ns_snapshot_mount_mutex);
+
        down_read(&nilfs->ns_segctor_sem);
        ret = nilfs_cpfile_is_snapshot(nilfs->ns_cpfile, cno);
        up_read(&nilfs->ns_segctor_sem);
@@ -972,6 +971,7 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno,
        ret = nilfs_get_root_dentry(s, root, root_dentry);
        nilfs_put_root(root);
  out:
+       mutex_unlock(&nilfs->ns_snapshot_mount_mutex);
        return ret;
 }
 
index 501b7f8b739fc2ed8079c0bc664481933d8d9d74..41e6a04a561f36ac1bd190b80dd2c10def4cf176 100644 (file)
@@ -76,6 +76,7 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
        nilfs->ns_bdev = bdev;
        atomic_set(&nilfs->ns_ndirtyblks, 0);
        init_rwsem(&nilfs->ns_sem);
+       mutex_init(&nilfs->ns_snapshot_mount_mutex);
        INIT_LIST_HEAD(&nilfs->ns_dirty_files);
        INIT_LIST_HEAD(&nilfs->ns_gc_inodes);
        spin_lock_init(&nilfs->ns_inode_lock);
index 9992b11312ff5918b9509eabfdb0cab1ecbecd94..6eee4177807bf611874208c09fce9440979fbc4f 100644 (file)
@@ -47,11 +47,13 @@ enum {
  * @ns_flags: flags
  * @ns_bdev: block device
  * @ns_sem: semaphore for shared states
+ * @ns_snapshot_mount_mutex: mutex to protect snapshot mounts
  * @ns_sbh: buffer heads of on-disk super blocks
  * @ns_sbp: pointers to super block data
  * @ns_sbwtime: previous write time of super block
  * @ns_sbwcount: write count of super block
  * @ns_sbsize: size of valid data in super block
+ * @ns_mount_state: file system state
  * @ns_seg_seq: segment sequence counter
  * @ns_segnum: index number of the latest full segment.
  * @ns_nextnum: index number of the full segment index to be used next
@@ -99,6 +101,7 @@ struct the_nilfs {
 
        struct block_device    *ns_bdev;
        struct rw_semaphore     ns_sem;
+       struct mutex            ns_snapshot_mount_mutex;
 
        /*
         * used for
@@ -229,9 +232,8 @@ THE_NILFS_FNS(SB_DIRTY, sb_dirty)
  * @count: refcount of this structure
  * @nilfs: nilfs object
  * @ifile: inode file
- * @root: root inode
  * @inodes_count: number of inodes
- * @blocks_count: number of blocks (Reserved)
+ * @blocks_count: number of blocks
  */
 struct nilfs_root {
        __u64 cno;
index b341492542ca9c8319cb4dc33f4cbdd088ab3242..2bc149d6a784e74ba485216d888ccd95f12e9516 100644 (file)
@@ -2660,31 +2660,14 @@ static const struct super_operations ntfs_sops = {
        .alloc_inode    = ntfs_alloc_big_inode,   /* VFS: Allocate new inode. */
        .destroy_inode  = ntfs_destroy_big_inode, /* VFS: Deallocate inode. */
 #ifdef NTFS_RW
-       //.dirty_inode  = NULL,                 /* VFS: Called from
-       //                                         __mark_inode_dirty(). */
        .write_inode    = ntfs_write_inode,     /* VFS: Write dirty inode to
                                                   disk. */
-       //.drop_inode   = NULL,                 /* VFS: Called just after the
-       //                                         inode reference count has
-       //                                         been decreased to zero.
-       //                                         NOTE: The inode lock is
-       //                                         held. See fs/inode.c::
-       //                                         generic_drop_inode(). */
-       //.delete_inode = NULL,                 /* VFS: Delete inode from disk.
-       //                                         Called when i_count becomes
-       //                                         0 and i_nlink is also 0. */
-       //.write_super  = NULL,                 /* Flush dirty super block to
-       //                                         disk. */
-       //.sync_fs      = NULL,                 /* ? */
-       //.write_super_lockfs   = NULL,         /* ? */
-       //.unlockfs     = NULL,                 /* ? */
 #endif /* NTFS_RW */
        .put_super      = ntfs_put_super,       /* Syscall: umount. */
        .statfs         = ntfs_statfs,          /* Syscall: statfs */
        .remount_fs     = ntfs_remount,         /* Syscall: mount -o remount. */
        .evict_inode    = ntfs_evict_big_inode, /* VFS: Called when an inode is
                                                   removed from memory. */
-       //.umount_begin = NULL,                 /* Forced umount. */
        .show_options   = ntfs_show_options,    /* Show mount options in
                                                   proc. */
 };
index 210c35237548be82f9d99966beb166cdd2ffc87d..a9f78c74d687ed5845587ac619081653f7e510b7 100644 (file)
@@ -784,14 +784,10 @@ bail:
 
 static u32 ocfs2_local_alloc_count_bits(struct ocfs2_dinode *alloc)
 {
-       int i;
-       u8 *buffer;
-       u32 count = 0;
+       u32 count;
        struct ocfs2_local_alloc *la = OCFS2_LOCAL_ALLOC(alloc);
 
-       buffer = la->la_bitmap;
-       for (i = 0; i < le16_to_cpu(la->la_size); i++)
-               count += hweight8(buffer[i]);
+       count = memweight(la->la_bitmap, le16_to_cpu(la->la_size));
 
        trace_ocfs2_local_alloc_count_bits(count);
        return count;
index 2772208338f811c6b5d5bc067c490fe8725ba3cb..1b6c84cbdb732e5684ccaa823548b8780cf1c16d 100644 (file)
@@ -695,8 +695,6 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
                mmput(mm);
        }
 
-       /* OK to pass negative loff_t, we can catch out-of-range */
-       file->f_mode |= FMODE_UNSIGNED_OFFSET;
        file->private_data = mm;
 
        return 0;
@@ -704,7 +702,12 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
 
 static int mem_open(struct inode *inode, struct file *file)
 {
-       return __mem_open(inode, file, PTRACE_MODE_ATTACH);
+       int ret = __mem_open(inode, file, PTRACE_MODE_ATTACH);
+
+       /* OK to pass negative loff_t, we can catch out-of-range */
+       file->f_mode |= FMODE_UNSIGNED_OFFSET;
+
+       return ret;
 }
 
 static ssize_t mem_rw(struct file *file, char __user *buf,
@@ -827,15 +830,16 @@ static ssize_t environ_read(struct file *file, char __user *buf,
        if (!atomic_inc_not_zero(&mm->mm_users))
                goto free;
        while (count > 0) {
-               int this_len, retval, max_len;
-
-               this_len = mm->env_end - (mm->env_start + src);
+               size_t this_len, max_len;
+               int retval;
 
-               if (this_len <= 0)
+               if (src >= (mm->env_end - mm->env_start))
                        break;
 
-               max_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-               this_len = (this_len > max_len) ? max_len : this_len;
+               this_len = mm->env_end - (mm->env_start + src);
+
+               max_len = min_t(size_t, PAGE_SIZE, count);
+               this_len = min(max_len, this_len);
 
                retval = access_remote_vm(mm, (mm->env_start + src),
                        page, this_len, 0);
index 22e0d60e53efbe3072ade881ec69251062df83c9..76a7a697b778d7918e5db75bf5a1dd744a073a5d 100644 (file)
 #include <linux/bitops.h>
 #include "qnx4.h"
 
-static void count_bits(register const char *bmPart, register int size,
-                      int *const tf)
-{
-       char b;
-       int tot = *tf;
-
-       if (size > QNX4_BLOCK_SIZE) {
-               size = QNX4_BLOCK_SIZE;
-       }
-       do {
-               b = *bmPart++;
-               tot += 8 - hweight8(b);
-               size--;
-       } while (size != 0);
-       *tf = tot;
-}
-
 unsigned long qnx4_count_free_blocks(struct super_block *sb)
 {
        int start = le32_to_cpu(qnx4_sb(sb)->BitMap->di_first_xtnt.xtnt_blk) - 1;
@@ -44,13 +27,16 @@ unsigned long qnx4_count_free_blocks(struct super_block *sb)
        struct buffer_head *bh;
 
        while (total < size) {
+               int bytes = min(size - total, QNX4_BLOCK_SIZE);
+
                if ((bh = sb_bread(sb, start + offset)) == NULL) {
                        printk(KERN_ERR "qnx4: I/O error in counting free blocks\n");
                        break;
                }
-               count_bits(bh->b_data, size - total, &total_free);
+               total_free += bytes * BITS_PER_BYTE -
+                               memweight(bh->b_data, bytes);
                brelse(bh);
-               total += QNX4_BLOCK_SIZE;
+               total += bytes;
                offset++;
        }
 
index c743fb3be4b8a45d8d99f9b757bfc44bbb949683..4c5d82f56ec44940c7aadcc16569b9f038f206a8 100644 (file)
@@ -320,7 +320,7 @@ static int grab_super(struct super_block *s) __releases(sb_lock)
 
 /*
  *     grab_super_passive - acquire a passive reference
- *     @s: reference we are trying to grab
+ *     @sb: reference we are trying to grab
  *
  *     Tries to acquire a passive reference. This is used in places where we
  *     cannot take an active reference but we need to ensure that the
index 1d7ac379045879b827b196f0d7a7420fe33c783d..4d45b7189e7eaa352da0567b8fe4a2d1b738c999 100644 (file)
@@ -427,6 +427,7 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
 {
        ssize_t error;
        void *kvalue = NULL;
+       void *vvalue = NULL;
        char kname[XATTR_NAME_MAX + 1];
 
        error = strncpy_from_user(kname, name, sizeof(kname));
@@ -438,9 +439,13 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
        if (size) {
                if (size > XATTR_SIZE_MAX)
                        size = XATTR_SIZE_MAX;
-               kvalue = kzalloc(size, GFP_KERNEL);
-               if (!kvalue)
-                       return -ENOMEM;
+               kvalue = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+               if (!kvalue) {
+                       vvalue = vmalloc(size);
+                       if (!vvalue)
+                               return -ENOMEM;
+                       kvalue = vvalue;
+               }
        }
 
        error = vfs_getxattr(d, kname, kvalue, size);
@@ -452,7 +457,10 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
                   than XATTR_SIZE_MAX bytes. Not possible. */
                error = -E2BIG;
        }
-       kfree(kvalue);
+       if (vvalue)
+               vfree(vvalue);
+       else
+               kfree(kvalue);
        return error;
 }
 
index a6caa0022c9bba4f937abaf032ede0761e930a22..359fb86ed8769b6ba5259a5be6959fd40c977b46 100644 (file)
@@ -50,20 +50,6 @@ typedef struct xfs_alloc_rec_incore {
 /* btree pointer type */
 typedef __be32 xfs_alloc_ptr_t;
 
-/*
- * Minimum and maximum blocksize and sectorsize.
- * The blocksize upper limit is pretty much arbitrary.
- * The sectorsize upper limit is due to sizeof(sb_sectsize).
- */
-#define XFS_MIN_BLOCKSIZE_LOG  9       /* i.e. 512 bytes */
-#define XFS_MAX_BLOCKSIZE_LOG  16      /* i.e. 65536 bytes */
-#define XFS_MIN_BLOCKSIZE      (1 << XFS_MIN_BLOCKSIZE_LOG)
-#define XFS_MAX_BLOCKSIZE      (1 << XFS_MAX_BLOCKSIZE_LOG)
-#define XFS_MIN_SECTORSIZE_LOG 9       /* i.e. 512 bytes */
-#define XFS_MAX_SECTORSIZE_LOG 15      /* i.e. 32768 bytes */
-#define XFS_MIN_SECTORSIZE     (1 << XFS_MIN_SECTORSIZE_LOG)
-#define XFS_MAX_SECTORSIZE     (1 << XFS_MAX_SECTORSIZE_LOG)
-
 /*
  * Block numbers in the AG:
  * SB is sector 0, AGF is sector 1, AGI is sector 2, AGFL is sector 3.
index 8dad722c00410f25294f0a8fec608fcbd56e74e8..15052ff916ec4fbef6059486f251a07ed3105b71 100644 (file)
@@ -179,7 +179,7 @@ xfs_finish_ioend(
        if (atomic_dec_and_test(&ioend->io_remaining)) {
                struct xfs_mount        *mp = XFS_I(ioend->io_inode)->i_mount;
 
-               if (ioend->io_type == IO_UNWRITTEN)
+               if (ioend->io_type == XFS_IO_UNWRITTEN)
                        queue_work(mp->m_unwritten_workqueue, &ioend->io_work);
                else if (ioend->io_append_trans)
                        queue_work(mp->m_data_workqueue, &ioend->io_work);
@@ -210,7 +210,7 @@ xfs_end_io(
         * For unwritten extents we need to issue transactions to convert a
         * range to normal written extens after the data I/O has finished.
         */
-       if (ioend->io_type == IO_UNWRITTEN) {
+       if (ioend->io_type == XFS_IO_UNWRITTEN) {
                /*
                 * For buffered I/O we never preallocate a transaction when
                 * doing the unwritten extent conversion, but for direct I/O
@@ -312,7 +312,7 @@ xfs_map_blocks(
        if (XFS_FORCED_SHUTDOWN(mp))
                return -XFS_ERROR(EIO);
 
-       if (type == IO_UNWRITTEN)
+       if (type == XFS_IO_UNWRITTEN)
                bmapi_flags |= XFS_BMAPI_IGSTATE;
 
        if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) {
@@ -323,10 +323,10 @@ xfs_map_blocks(
 
        ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
               (ip->i_df.if_flags & XFS_IFEXTENTS));
-       ASSERT(offset <= mp->m_maxioffset);
+       ASSERT(offset <= mp->m_super->s_maxbytes);
 
-       if (offset + count > mp->m_maxioffset)
-               count = mp->m_maxioffset - offset;
+       if (offset + count > mp->m_super->s_maxbytes)
+               count = mp->m_super->s_maxbytes - offset;
        end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
        offset_fsb = XFS_B_TO_FSBT(mp, offset);
        error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
@@ -336,7 +336,7 @@ xfs_map_blocks(
        if (error)
                return -XFS_ERROR(error);
 
-       if (type == IO_DELALLOC &&
+       if (type == XFS_IO_DELALLOC &&
            (!nimaps || isnullstartblock(imap->br_startblock))) {
                error = xfs_iomap_write_allocate(ip, offset, count, imap);
                if (!error)
@@ -345,7 +345,7 @@ xfs_map_blocks(
        }
 
 #ifdef DEBUG
-       if (type == IO_UNWRITTEN) {
+       if (type == XFS_IO_UNWRITTEN) {
                ASSERT(nimaps);
                ASSERT(imap->br_startblock != HOLESTARTBLOCK);
                ASSERT(imap->br_startblock != DELAYSTARTBLOCK);
@@ -634,11 +634,11 @@ xfs_check_page_type(
                bh = head = page_buffers(page);
                do {
                        if (buffer_unwritten(bh))
-                               acceptable += (type == IO_UNWRITTEN);
+                               acceptable += (type == XFS_IO_UNWRITTEN);
                        else if (buffer_delay(bh))
-                               acceptable += (type == IO_DELALLOC);
+                               acceptable += (type == XFS_IO_DELALLOC);
                        else if (buffer_dirty(bh) && buffer_mapped(bh))
-                               acceptable += (type == IO_OVERWRITE);
+                               acceptable += (type == XFS_IO_OVERWRITE);
                        else
                                break;
                } while ((bh = bh->b_this_page) != head);
@@ -721,11 +721,11 @@ xfs_convert_page(
                if (buffer_unwritten(bh) || buffer_delay(bh) ||
                    buffer_mapped(bh)) {
                        if (buffer_unwritten(bh))
-                               type = IO_UNWRITTEN;
+                               type = XFS_IO_UNWRITTEN;
                        else if (buffer_delay(bh))
-                               type = IO_DELALLOC;
+                               type = XFS_IO_DELALLOC;
                        else
-                               type = IO_OVERWRITE;
+                               type = XFS_IO_OVERWRITE;
 
                        if (!xfs_imap_valid(inode, imap, offset)) {
                                done = 1;
@@ -733,7 +733,7 @@ xfs_convert_page(
                        }
 
                        lock_buffer(bh);
-                       if (type != IO_OVERWRITE)
+                       if (type != XFS_IO_OVERWRITE)
                                xfs_map_at_offset(inode, bh, imap, offset);
                        xfs_add_to_ioend(inode, bh, offset, type,
                                         ioendp, done);
@@ -831,7 +831,7 @@ xfs_aops_discard_page(
        struct buffer_head      *bh, *head;
        loff_t                  offset = page_offset(page);
 
-       if (!xfs_check_page_type(page, IO_DELALLOC))
+       if (!xfs_check_page_type(page, XFS_IO_DELALLOC))
                goto out_invalidate;
 
        if (XFS_FORCED_SHUTDOWN(ip->i_mount))
@@ -927,11 +927,26 @@ xfs_vm_writepage(
        end_index = offset >> PAGE_CACHE_SHIFT;
        last_index = (offset - 1) >> PAGE_CACHE_SHIFT;
        if (page->index >= end_index) {
-               if ((page->index >= end_index + 1) ||
-                   !(i_size_read(inode) & (PAGE_CACHE_SIZE - 1))) {
+               unsigned offset_into_page = offset & (PAGE_CACHE_SIZE - 1);
+
+               /*
+                * Just skip the page if it is fully outside i_size, e.g. due
+                * to a truncate operation that is in progress.
+                */
+               if (page->index >= end_index + 1 || offset_into_page == 0) {
                        unlock_page(page);
                        return 0;
                }
+
+               /*
+                * The page straddles i_size.  It must be zeroed out on each
+                * and every writepage invocation because it may be mmapped.
+                * "A file is mapped in multiples of the page size.  For a file
+                * that is not a multiple of the  page size, the remaining
+                * memory is zeroed when mapped, and writes to that region are
+                * not written out to the file."
+                */
+               zero_user_segment(page, offset_into_page, PAGE_CACHE_SIZE);
        }
 
        end_offset = min_t(unsigned long long,
@@ -941,7 +956,7 @@ xfs_vm_writepage(
 
        bh = head = page_buffers(page);
        offset = page_offset(page);
-       type = IO_OVERWRITE;
+       type = XFS_IO_OVERWRITE;
 
        if (wbc->sync_mode == WB_SYNC_NONE)
                nonblocking = 1;
@@ -966,18 +981,18 @@ xfs_vm_writepage(
                }
 
                if (buffer_unwritten(bh)) {
-                       if (type != IO_UNWRITTEN) {
-                               type = IO_UNWRITTEN;
+                       if (type != XFS_IO_UNWRITTEN) {
+                               type = XFS_IO_UNWRITTEN;
                                imap_valid = 0;
                        }
                } else if (buffer_delay(bh)) {
-                       if (type != IO_DELALLOC) {
-                               type = IO_DELALLOC;
+                       if (type != XFS_IO_DELALLOC) {
+                               type = XFS_IO_DELALLOC;
                                imap_valid = 0;
                        }
                } else if (buffer_uptodate(bh)) {
-                       if (type != IO_OVERWRITE) {
-                               type = IO_OVERWRITE;
+                       if (type != XFS_IO_OVERWRITE) {
+                               type = XFS_IO_OVERWRITE;
                                imap_valid = 0;
                        }
                } else {
@@ -1013,7 +1028,7 @@ xfs_vm_writepage(
                }
                if (imap_valid) {
                        lock_buffer(bh);
-                       if (type != IO_OVERWRITE)
+                       if (type != XFS_IO_OVERWRITE)
                                xfs_map_at_offset(inode, bh, &imap, offset);
                        xfs_add_to_ioend(inode, bh, offset, type, &ioend,
                                         new_ioend);
@@ -1054,7 +1069,7 @@ xfs_vm_writepage(
                 * Reserve log space if we might write beyond the on-disk
                 * inode size.
                 */
-               if (ioend->io_type != IO_UNWRITTEN &&
+               if (ioend->io_type != XFS_IO_UNWRITTEN &&
                    xfs_ioend_is_append(ioend)) {
                        err = xfs_setfilesize_trans_alloc(ioend);
                        if (err)
@@ -1162,9 +1177,9 @@ __xfs_get_blocks(
                lockmode = xfs_ilock_map_shared(ip);
        }
 
-       ASSERT(offset <= mp->m_maxioffset);
-       if (offset + size > mp->m_maxioffset)
-               size = mp->m_maxioffset - offset;
+       ASSERT(offset <= mp->m_super->s_maxbytes);
+       if (offset + size > mp->m_super->s_maxbytes)
+               size = mp->m_super->s_maxbytes - offset;
        end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size);
        offset_fsb = XFS_B_TO_FSBT(mp, offset);
 
@@ -1351,7 +1366,7 @@ xfs_end_io_direct_write(
        ioend->io_iocb = iocb;
        ioend->io_result = ret;
        if (private && size > 0)
-               ioend->io_type = IO_UNWRITTEN;
+               ioend->io_type = XFS_IO_UNWRITTEN;
 
        if (is_async) {
                ioend->io_isasync = 1;
@@ -1383,7 +1398,7 @@ xfs_vm_direct_IO(
                 * and converts at least on unwritten extent we will cancel
                 * the still clean transaction after the I/O has finished.
                 */
-               iocb->private = ioend = xfs_alloc_ioend(inode, IO_DIRECT);
+               iocb->private = ioend = xfs_alloc_ioend(inode, XFS_IO_DIRECT);
                if (offset + size > XFS_I(inode)->i_d.di_size) {
                        ret = xfs_setfilesize_trans_alloc(ioend);
                        if (ret)
index 84eafbcb0d9dd65cecd57ef9074eb66b89bb9c08..c325abb8d61ab6bcf031073b905e440be440f8f7 100644 (file)
@@ -24,17 +24,17 @@ extern mempool_t *xfs_ioend_pool;
  * Types of I/O for bmap clustering and I/O completion tracking.
  */
 enum {
-       IO_DIRECT = 0,  /* special case for direct I/O ioends */
-       IO_DELALLOC,    /* mapping covers delalloc region */
-       IO_UNWRITTEN,   /* mapping covers allocated but uninitialized data */
-       IO_OVERWRITE,   /* mapping covers already allocated extent */
+       XFS_IO_DIRECT = 0,      /* special case for direct I/O ioends */
+       XFS_IO_DELALLOC,        /* covers delalloc region */
+       XFS_IO_UNWRITTEN,       /* covers allocated but uninitialized data */
+       XFS_IO_OVERWRITE,       /* covers already allocated extent */
 };
 
 #define XFS_IO_TYPES \
        { 0,                    "" }, \
-       { IO_DELALLOC,          "delalloc" }, \
-       { IO_UNWRITTEN,         "unwritten" }, \
-       { IO_OVERWRITE,         "overwrite" }
+       { XFS_IO_DELALLOC,              "delalloc" }, \
+       { XFS_IO_UNWRITTEN,             "unwritten" }, \
+       { XFS_IO_OVERWRITE,             "overwrite" }
 
 /*
  * xfs_ioend struct manages large extent writes for XFS.
index a17ff01b5adf900da88aacb0e430b8853443bb62..0ca1f0be62d262f8eb23873f48c81ab864995fe8 100644 (file)
@@ -893,7 +893,7 @@ STATIC int
 xfs_attr_leaf_addname(xfs_da_args_t *args)
 {
        xfs_inode_t *dp;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int retval, error, committed, forkoff;
 
        trace_xfs_attr_leaf_addname(args);
@@ -915,11 +915,11 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
         */
        retval = xfs_attr_leaf_lookup_int(bp, args);
        if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
-               xfs_da_brelse(args->trans, bp);
+               xfs_trans_brelse(args->trans, bp);
                return(retval);
        } else if (retval == EEXIST) {
                if (args->flags & ATTR_CREATE) {        /* pure create op */
-                       xfs_da_brelse(args->trans, bp);
+                       xfs_trans_brelse(args->trans, bp);
                        return(retval);
                }
 
@@ -937,7 +937,6 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
         * if required.
         */
        retval = xfs_attr_leaf_add(bp, args);
-       xfs_da_buf_done(bp);
        if (retval == ENOSPC) {
                /*
                 * Promote the attribute list to the Btree format, then
@@ -1065,8 +1064,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                         */
                        if (committed)
                                xfs_trans_ijoin(args->trans, dp, 0);
-               } else
-                       xfs_da_buf_done(bp);
+               }
 
                /*
                 * Commit the remove and start the next trans in series.
@@ -1092,7 +1090,7 @@ STATIC int
 xfs_attr_leaf_removename(xfs_da_args_t *args)
 {
        xfs_inode_t *dp;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int error, committed, forkoff;
 
        trace_xfs_attr_leaf_removename(args);
@@ -1111,7 +1109,7 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
        ASSERT(bp != NULL);
        error = xfs_attr_leaf_lookup_int(bp, args);
        if (error == ENOATTR) {
-               xfs_da_brelse(args->trans, bp);
+               xfs_trans_brelse(args->trans, bp);
                return(error);
        }
 
@@ -1141,8 +1139,7 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
                 */
                if (committed)
                        xfs_trans_ijoin(args->trans, dp, 0);
-       } else
-               xfs_da_buf_done(bp);
+       }
        return(0);
 }
 
@@ -1155,7 +1152,7 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
 STATIC int
 xfs_attr_leaf_get(xfs_da_args_t *args)
 {
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int error;
 
        args->blkno = 0;
@@ -1167,11 +1164,11 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
 
        error = xfs_attr_leaf_lookup_int(bp, args);
        if (error != EEXIST)  {
-               xfs_da_brelse(args->trans, bp);
+               xfs_trans_brelse(args->trans, bp);
                return(error);
        }
        error = xfs_attr_leaf_getvalue(bp, args);
-       xfs_da_brelse(args->trans, bp);
+       xfs_trans_brelse(args->trans, bp);
        if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) {
                error = xfs_attr_rmtval_get(args);
        }
@@ -1186,23 +1183,23 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
 {
        xfs_attr_leafblock_t *leaf;
        int error;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
 
        context->cursor->blkno = 0;
        error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK);
        if (error)
                return XFS_ERROR(error);
        ASSERT(bp != NULL);
-       leaf = bp->data;
+       leaf = bp->b_addr;
        if (unlikely(leaf->hdr.info.magic != cpu_to_be16(XFS_ATTR_LEAF_MAGIC))) {
                XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW,
                                     context->dp->i_mount, leaf);
-               xfs_da_brelse(NULL, bp);
+               xfs_trans_brelse(NULL, bp);
                return XFS_ERROR(EFSCORRUPTED);
        }
 
        error = xfs_attr_leaf_list_int(bp, context);
-       xfs_da_brelse(NULL, bp);
+       xfs_trans_brelse(NULL, bp);
        return XFS_ERROR(error);
 }
 
@@ -1489,7 +1486,7 @@ xfs_attr_node_removename(xfs_da_args_t *args)
        xfs_da_state_t *state;
        xfs_da_state_blk_t *blk;
        xfs_inode_t *dp;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int retval, error, committed, forkoff;
 
        trace_xfs_attr_node_removename(args);
@@ -1601,14 +1598,13 @@ xfs_attr_node_removename(xfs_da_args_t *args)
                 */
                ASSERT(state->path.active == 1);
                ASSERT(state->path.blk[0].bp);
-               xfs_da_buf_done(state->path.blk[0].bp);
                state->path.blk[0].bp = NULL;
 
                error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
                                                     XFS_ATTR_FORK);
                if (error)
                        goto out;
-               ASSERT((((xfs_attr_leafblock_t *)bp->data)->hdr.info.magic) ==
+               ASSERT((((xfs_attr_leafblock_t *)bp->b_addr)->hdr.info.magic) ==
                       cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
 
                if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
@@ -1635,7 +1631,7 @@ xfs_attr_node_removename(xfs_da_args_t *args)
                        if (committed)
                                xfs_trans_ijoin(args->trans, dp, 0);
                } else
-                       xfs_da_brelse(args->trans, bp);
+                       xfs_trans_brelse(args->trans, bp);
        }
        error = 0;
 
@@ -1665,8 +1661,7 @@ xfs_attr_fillstate(xfs_da_state_t *state)
        ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
        for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
                if (blk->bp) {
-                       blk->disk_blkno = xfs_da_blkno(blk->bp);
-                       xfs_da_buf_done(blk->bp);
+                       blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
                        blk->bp = NULL;
                } else {
                        blk->disk_blkno = 0;
@@ -1681,8 +1676,7 @@ xfs_attr_fillstate(xfs_da_state_t *state)
        ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
        for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
                if (blk->bp) {
-                       blk->disk_blkno = xfs_da_blkno(blk->bp);
-                       xfs_da_buf_done(blk->bp);
+                       blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
                        blk->bp = NULL;
                } else {
                        blk->disk_blkno = 0;
@@ -1792,7 +1786,7 @@ xfs_attr_node_get(xfs_da_args_t *args)
         * If not in a transaction, we have to release all the buffers.
         */
        for (i = 0; i < state->path.active; i++) {
-               xfs_da_brelse(args->trans, state->path.blk[i].bp);
+               xfs_trans_brelse(args->trans, state->path.blk[i].bp);
                state->path.blk[i].bp = NULL;
        }
 
@@ -1808,7 +1802,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
        xfs_da_intnode_t *node;
        xfs_da_node_entry_t *btree;
        int error, i;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
 
        cursor = context->cursor;
        cursor->initted = 1;
@@ -1825,30 +1819,30 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
                if ((error != 0) && (error != EFSCORRUPTED))
                        return(error);
                if (bp) {
-                       node = bp->data;
+                       node = bp->b_addr;
                        switch (be16_to_cpu(node->hdr.info.magic)) {
                        case XFS_DA_NODE_MAGIC:
                                trace_xfs_attr_list_wrong_blk(context);
-                               xfs_da_brelse(NULL, bp);
+                               xfs_trans_brelse(NULL, bp);
                                bp = NULL;
                                break;
                        case XFS_ATTR_LEAF_MAGIC:
-                               leaf = bp->data;
+                               leaf = bp->b_addr;
                                if (cursor->hashval > be32_to_cpu(leaf->entries[
                                    be16_to_cpu(leaf->hdr.count)-1].hashval)) {
                                        trace_xfs_attr_list_wrong_blk(context);
-                                       xfs_da_brelse(NULL, bp);
+                                       xfs_trans_brelse(NULL, bp);
                                        bp = NULL;
                                } else if (cursor->hashval <=
                                             be32_to_cpu(leaf->entries[0].hashval)) {
                                        trace_xfs_attr_list_wrong_blk(context);
-                                       xfs_da_brelse(NULL, bp);
+                                       xfs_trans_brelse(NULL, bp);
                                        bp = NULL;
                                }
                                break;
                        default:
                                trace_xfs_attr_list_wrong_blk(context);
-                               xfs_da_brelse(NULL, bp);
+                               xfs_trans_brelse(NULL, bp);
                                bp = NULL;
                        }
                }
@@ -1873,7 +1867,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
                                                 context->dp->i_mount);
                                return(XFS_ERROR(EFSCORRUPTED));
                        }
-                       node = bp->data;
+                       node = bp->b_addr;
                        if (node->hdr.info.magic ==
                            cpu_to_be16(XFS_ATTR_LEAF_MAGIC))
                                break;
@@ -1883,7 +1877,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
                                                     XFS_ERRLEVEL_LOW,
                                                     context->dp->i_mount,
                                                     node);
-                               xfs_da_brelse(NULL, bp);
+                               xfs_trans_brelse(NULL, bp);
                                return(XFS_ERROR(EFSCORRUPTED));
                        }
                        btree = node->btree;
@@ -1898,10 +1892,10 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
                                }
                        }
                        if (i == be16_to_cpu(node->hdr.count)) {
-                               xfs_da_brelse(NULL, bp);
+                               xfs_trans_brelse(NULL, bp);
                                return(0);
                        }
-                       xfs_da_brelse(NULL, bp);
+                       xfs_trans_brelse(NULL, bp);
                }
        }
        ASSERT(bp != NULL);
@@ -1912,24 +1906,24 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
         * adding the information.
         */
        for (;;) {
-               leaf = bp->data;
+               leaf = bp->b_addr;
                if (unlikely(leaf->hdr.info.magic !=
                             cpu_to_be16(XFS_ATTR_LEAF_MAGIC))) {
                        XFS_CORRUPTION_ERROR("xfs_attr_node_list(4)",
                                             XFS_ERRLEVEL_LOW,
                                             context->dp->i_mount, leaf);
-                       xfs_da_brelse(NULL, bp);
+                       xfs_trans_brelse(NULL, bp);
                        return(XFS_ERROR(EFSCORRUPTED));
                }
                error = xfs_attr_leaf_list_int(bp, context);
                if (error) {
-                       xfs_da_brelse(NULL, bp);
+                       xfs_trans_brelse(NULL, bp);
                        return error;
                }
                if (context->seen_enough || leaf->hdr.info.forw == 0)
                        break;
                cursor->blkno = be32_to_cpu(leaf->hdr.info.forw);
-               xfs_da_brelse(NULL, bp);
+               xfs_trans_brelse(NULL, bp);
                error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
                                              &bp, XFS_ATTR_FORK);
                if (error)
@@ -1941,7 +1935,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
                        return(XFS_ERROR(EFSCORRUPTED));
                }
        }
-       xfs_da_brelse(NULL, bp);
+       xfs_trans_brelse(NULL, bp);
        return(0);
 }
 
index 7d89d800f5173f2d5d1c34a36278cab703f92d33..d330111ca738eef9ff86b5fd28723c0b63a9b379 100644 (file)
  * Routines used for growing the Btree.
  */
 STATIC int xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t which_block,
-                                   xfs_dabuf_t **bpp);
-STATIC int xfs_attr_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args,
-                                             int freemap_index);
-STATIC void xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer);
+                               struct xfs_buf **bpp);
+STATIC int xfs_attr_leaf_add_work(struct xfs_buf *leaf_buffer,
+                                 xfs_da_args_t *args, int freemap_index);
+STATIC void xfs_attr_leaf_compact(xfs_trans_t *tp, struct xfs_buf *leaf_buffer);
 STATIC void xfs_attr_leaf_rebalance(xfs_da_state_t *state,
                                                   xfs_da_state_blk_t *blk1,
                                                   xfs_da_state_blk_t *blk2);
@@ -71,9 +71,9 @@ STATIC int xfs_attr_leaf_figure_balance(xfs_da_state_t *state,
  * Routines used for shrinking the Btree.
  */
 STATIC int xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp,
-                                 xfs_dabuf_t *bp, int level);
+                                 struct xfs_buf *bp, int level);
 STATIC int xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp,
-                                 xfs_dabuf_t *bp);
+                                 struct xfs_buf *bp);
 STATIC int xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
                                   xfs_dablk_t blkno, int blkcnt);
 
@@ -480,7 +480,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
        char *tmpbuffer;
        int error, i, size;
        xfs_dablk_t blkno;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        xfs_ifork_t *ifp;
 
        trace_xfs_attr_sf_to_leaf(args);
@@ -550,8 +550,6 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
        error = 0;
 
 out:
-       if(bp)
-               xfs_da_buf_done(bp);
        kmem_free(tmpbuffer);
        return(error);
 }
@@ -737,14 +735,16 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
  * a shortform attribute list.
  */
 int
-xfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp)
+xfs_attr_shortform_allfit(
+       struct xfs_buf  *bp,
+       struct xfs_inode *dp)
 {
        xfs_attr_leafblock_t *leaf;
        xfs_attr_leaf_entry_t *entry;
        xfs_attr_leaf_name_local_t *name_loc;
        int bytes, i;
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
 
        entry = &leaf->entries[0];
@@ -774,7 +774,10 @@ xfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp)
  * Convert a leaf attribute list to shortform attribute list
  */
 int
-xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
+xfs_attr_leaf_to_shortform(
+       struct xfs_buf  *bp,
+       xfs_da_args_t   *args,
+       int             forkoff)
 {
        xfs_attr_leafblock_t *leaf;
        xfs_attr_leaf_entry_t *entry;
@@ -791,10 +794,10 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
        ASSERT(tmpbuffer != NULL);
 
        ASSERT(bp != NULL);
-       memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount));
+       memcpy(tmpbuffer, bp->b_addr, XFS_LBSIZE(dp->i_mount));
        leaf = (xfs_attr_leafblock_t *)tmpbuffer;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
-       memset(bp->data, 0, XFS_LBSIZE(dp->i_mount));
+       memset(bp->b_addr, 0, XFS_LBSIZE(dp->i_mount));
 
        /*
         * Clean out the prior contents of the attribute list.
@@ -855,7 +858,7 @@ xfs_attr_leaf_to_node(xfs_da_args_t *args)
        xfs_attr_leafblock_t *leaf;
        xfs_da_intnode_t *node;
        xfs_inode_t *dp;
-       xfs_dabuf_t *bp1, *bp2;
+       struct xfs_buf *bp1, *bp2;
        xfs_dablk_t blkno;
        int error;
 
@@ -877,10 +880,9 @@ xfs_attr_leaf_to_node(xfs_da_args_t *args)
        if (error)
                goto out;
        ASSERT(bp2 != NULL);
-       memcpy(bp2->data, bp1->data, XFS_LBSIZE(dp->i_mount));
-       xfs_da_buf_done(bp1);
+       memcpy(bp2->b_addr, bp1->b_addr, XFS_LBSIZE(dp->i_mount));
        bp1 = NULL;
-       xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1);
+       xfs_trans_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1);
 
        /*
         * Set up the new root node.
@@ -888,21 +890,17 @@ xfs_attr_leaf_to_node(xfs_da_args_t *args)
        error = xfs_da_node_create(args, 0, 1, &bp1, XFS_ATTR_FORK);
        if (error)
                goto out;
-       node = bp1->data;
-       leaf = bp2->data;
+       node = bp1->b_addr;
+       leaf = bp2->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        /* both on-disk, don't endian-flip twice */
        node->btree[0].hashval =
                leaf->entries[be16_to_cpu(leaf->hdr.count)-1 ].hashval;
        node->btree[0].before = cpu_to_be32(blkno);
        node->hdr.count = cpu_to_be16(1);
-       xfs_da_log_buf(args->trans, bp1, 0, XFS_LBSIZE(dp->i_mount) - 1);
+       xfs_trans_log_buf(args->trans, bp1, 0, XFS_LBSIZE(dp->i_mount) - 1);
        error = 0;
 out:
-       if (bp1)
-               xfs_da_buf_done(bp1);
-       if (bp2)
-               xfs_da_buf_done(bp2);
        return(error);
 }
 
@@ -916,12 +914,15 @@ out:
  * or a leaf in a node attribute list.
  */
 STATIC int
-xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp)
+xfs_attr_leaf_create(
+       xfs_da_args_t   *args,
+       xfs_dablk_t     blkno,
+       struct xfs_buf  **bpp)
 {
        xfs_attr_leafblock_t *leaf;
        xfs_attr_leaf_hdr_t *hdr;
        xfs_inode_t *dp;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int error;
 
        trace_xfs_attr_leaf_create(args);
@@ -933,7 +934,7 @@ xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp)
        if (error)
                return(error);
        ASSERT(bp != NULL);
-       leaf = bp->data;
+       leaf = bp->b_addr;
        memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount));
        hdr = &leaf->hdr;
        hdr->info.magic = cpu_to_be16(XFS_ATTR_LEAF_MAGIC);
@@ -947,7 +948,7 @@ xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp)
        hdr->freemap[0].size = cpu_to_be16(be16_to_cpu(hdr->firstused) -
                                           sizeof(xfs_attr_leaf_hdr_t));
 
-       xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1);
+       xfs_trans_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1);
 
        *bpp = bp;
        return(0);
@@ -1014,7 +1015,9 @@ xfs_attr_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
  * Add a name to the leaf attribute list structure.
  */
 int
-xfs_attr_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args)
+xfs_attr_leaf_add(
+       struct xfs_buf          *bp,
+       struct xfs_da_args      *args)
 {
        xfs_attr_leafblock_t *leaf;
        xfs_attr_leaf_hdr_t *hdr;
@@ -1023,7 +1026,7 @@ xfs_attr_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args)
 
        trace_xfs_attr_leaf_add(args);
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        ASSERT((args->index >= 0)
                && (args->index <= be16_to_cpu(leaf->hdr.count)));
@@ -1085,7 +1088,10 @@ xfs_attr_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args)
  * Add a name to a leaf attribute list structure.
  */
 STATIC int
-xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
+xfs_attr_leaf_add_work(
+       struct xfs_buf  *bp,
+       xfs_da_args_t   *args,
+       int             mapindex)
 {
        xfs_attr_leafblock_t *leaf;
        xfs_attr_leaf_hdr_t *hdr;
@@ -1096,7 +1102,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
        xfs_mount_t *mp;
        int tmp, i;
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        hdr = &leaf->hdr;
        ASSERT((mapindex >= 0) && (mapindex < XFS_ATTR_LEAF_MAPSIZE));
@@ -1110,7 +1116,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
                tmp  = be16_to_cpu(hdr->count) - args->index;
                tmp *= sizeof(xfs_attr_leaf_entry_t);
                memmove((char *)(entry+1), (char *)entry, tmp);
-               xfs_da_log_buf(args->trans, bp,
+               xfs_trans_log_buf(args->trans, bp,
                    XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry)));
        }
        be16_add_cpu(&hdr->count, 1);
@@ -1142,7 +1148,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
                        args->index2++;
                }
        }
-       xfs_da_log_buf(args->trans, bp,
+       xfs_trans_log_buf(args->trans, bp,
                          XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
        ASSERT((args->index == 0) ||
               (be32_to_cpu(entry->hashval) >= be32_to_cpu((entry-1)->hashval)));
@@ -1174,7 +1180,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
                args->rmtblkno = 1;
                args->rmtblkcnt = XFS_B_TO_FSB(mp, args->valuelen);
        }
-       xfs_da_log_buf(args->trans, bp,
+       xfs_trans_log_buf(args->trans, bp,
             XFS_DA_LOGRANGE(leaf, xfs_attr_leaf_name(leaf, args->index),
                                   xfs_attr_leaf_entsize(leaf, args->index)));
 
@@ -1198,7 +1204,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
                }
        }
        be16_add_cpu(&hdr->usedbytes, xfs_attr_leaf_entsize(leaf, args->index));
-       xfs_da_log_buf(args->trans, bp,
+       xfs_trans_log_buf(args->trans, bp,
                XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr)));
        return(0);
 }
@@ -1207,7 +1213,9 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
  * Garbage collect a leaf attribute list block by copying it to a new buffer.
  */
 STATIC void
-xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp)
+xfs_attr_leaf_compact(
+       struct xfs_trans *trans,
+       struct xfs_buf  *bp)
 {
        xfs_attr_leafblock_t *leaf_s, *leaf_d;
        xfs_attr_leaf_hdr_t *hdr_s, *hdr_d;
@@ -1217,14 +1225,14 @@ xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp)
        mp = trans->t_mountp;
        tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP);
        ASSERT(tmpbuffer != NULL);
-       memcpy(tmpbuffer, bp->data, XFS_LBSIZE(mp));
-       memset(bp->data, 0, XFS_LBSIZE(mp));
+       memcpy(tmpbuffer, bp->b_addr, XFS_LBSIZE(mp));
+       memset(bp->b_addr, 0, XFS_LBSIZE(mp));
 
        /*
         * Copy basic information
         */
        leaf_s = (xfs_attr_leafblock_t *)tmpbuffer;
-       leaf_d = bp->data;
+       leaf_d = bp->b_addr;
        hdr_s = &leaf_s->hdr;
        hdr_d = &leaf_d->hdr;
        hdr_d->info = hdr_s->info;      /* struct copy */
@@ -1247,7 +1255,7 @@ xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp)
         */
        xfs_attr_leaf_moveents(leaf_s, 0, leaf_d, 0,
                                be16_to_cpu(hdr_s->count), mp);
-       xfs_da_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1);
+       xfs_trans_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1);
 
        kmem_free(tmpbuffer);
 }
@@ -1279,8 +1287,8 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
         */
        ASSERT(blk1->magic == XFS_ATTR_LEAF_MAGIC);
        ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC);
-       leaf1 = blk1->bp->data;
-       leaf2 = blk2->bp->data;
+       leaf1 = blk1->bp->b_addr;
+       leaf2 = blk2->bp->b_addr;
        ASSERT(leaf1->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        args = state->args;
@@ -1298,8 +1306,8 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
                tmp_blk = blk1;
                blk1 = blk2;
                blk2 = tmp_blk;
-               leaf1 = blk1->bp->data;
-               leaf2 = blk2->bp->data;
+               leaf1 = blk1->bp->b_addr;
+               leaf2 = blk2->bp->b_addr;
                swap = 1;
        }
        hdr1 = &leaf1->hdr;
@@ -1346,8 +1354,8 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
                xfs_attr_leaf_moveents(leaf1, be16_to_cpu(hdr1->count) - count,
                                leaf2, 0, count, state->mp);
 
-               xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1);
-               xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1);
+               xfs_trans_log_buf(args->trans, blk1->bp, 0, state->blocksize-1);
+               xfs_trans_log_buf(args->trans, blk2->bp, 0, state->blocksize-1);
        } else if (count > be16_to_cpu(hdr1->count)) {
                /*
                 * I assert that since all callers pass in an empty
@@ -1378,8 +1386,8 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
                xfs_attr_leaf_moveents(leaf2, 0, leaf1,
                                be16_to_cpu(hdr1->count), count, state->mp);
 
-               xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1);
-               xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1);
+               xfs_trans_log_buf(args->trans, blk1->bp, 0, state->blocksize-1);
+               xfs_trans_log_buf(args->trans, blk2->bp, 0, state->blocksize-1);
        }
 
        /*
@@ -1448,8 +1456,8 @@ xfs_attr_leaf_figure_balance(xfs_da_state_t *state,
        /*
         * Set up environment.
         */
-       leaf1 = blk1->bp->data;
-       leaf2 = blk2->bp->data;
+       leaf1 = blk1->bp->b_addr;
+       leaf2 = blk2->bp->b_addr;
        hdr1 = &leaf1->hdr;
        hdr2 = &leaf2->hdr;
        foundit = 0;
@@ -1551,7 +1559,7 @@ xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action)
        xfs_da_blkinfo_t *info;
        int count, bytes, forward, error, retval, i;
        xfs_dablk_t blkno;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
 
        /*
         * Check for the degenerate case of the block being over 50% full.
@@ -1559,7 +1567,7 @@ xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action)
         * to coalesce with a sibling.
         */
        blk = &state->path.blk[ state->path.active-1 ];
-       info = blk->bp->data;
+       info = blk->bp->b_addr;
        ASSERT(info->magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        leaf = (xfs_attr_leafblock_t *)info;
        count = be16_to_cpu(leaf->hdr.count);
@@ -1622,13 +1630,13 @@ xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action)
                count  = be16_to_cpu(leaf->hdr.count);
                bytes  = state->blocksize - (state->blocksize>>2);
                bytes -= be16_to_cpu(leaf->hdr.usedbytes);
-               leaf = bp->data;
+               leaf = bp->b_addr;
                ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
                count += be16_to_cpu(leaf->hdr.count);
                bytes -= be16_to_cpu(leaf->hdr.usedbytes);
                bytes -= count * sizeof(xfs_attr_leaf_entry_t);
                bytes -= sizeof(xfs_attr_leaf_hdr_t);
-               xfs_da_brelse(state->args->trans, bp);
+               xfs_trans_brelse(state->args->trans, bp);
                if (bytes >= 0)
                        break;  /* fits with at least 25% to spare */
        }
@@ -1666,7 +1674,9 @@ xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action)
  * If two leaves are 37% full, when combined they will leave 25% free.
  */
 int
-xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args)
+xfs_attr_leaf_remove(
+       struct xfs_buf  *bp,
+       xfs_da_args_t   *args)
 {
        xfs_attr_leafblock_t *leaf;
        xfs_attr_leaf_hdr_t *hdr;
@@ -1676,7 +1686,7 @@ xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args)
        int tablesize, tmp, i;
        xfs_mount_t *mp;
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        hdr = &leaf->hdr;
        mp = args->trans->t_mountp;
@@ -1769,7 +1779,7 @@ xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args)
         */
        memset(xfs_attr_leaf_name(leaf, args->index), 0, entsize);
        be16_add_cpu(&hdr->usedbytes, -entsize);
-       xfs_da_log_buf(args->trans, bp,
+       xfs_trans_log_buf(args->trans, bp,
             XFS_DA_LOGRANGE(leaf, xfs_attr_leaf_name(leaf, args->index),
                                   entsize));
 
@@ -1777,7 +1787,7 @@ xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args)
                                        * sizeof(xfs_attr_leaf_entry_t);
        memmove((char *)entry, (char *)(entry+1), tmp);
        be16_add_cpu(&hdr->count, -1);
-       xfs_da_log_buf(args->trans, bp,
+       xfs_trans_log_buf(args->trans, bp,
            XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry)));
        entry = &leaf->entries[be16_to_cpu(hdr->count)];
        memset((char *)entry, 0, sizeof(xfs_attr_leaf_entry_t));
@@ -1807,7 +1817,7 @@ xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args)
        } else {
                hdr->holes = 1;         /* mark as needing compaction */
        }
-       xfs_da_log_buf(args->trans, bp,
+       xfs_trans_log_buf(args->trans, bp,
                          XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr)));
 
        /*
@@ -1840,8 +1850,8 @@ xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
        mp = state->mp;
        ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC);
        ASSERT(save_blk->magic == XFS_ATTR_LEAF_MAGIC);
-       drop_leaf = drop_blk->bp->data;
-       save_leaf = save_blk->bp->data;
+       drop_leaf = drop_blk->bp->b_addr;
+       save_leaf = save_blk->bp->b_addr;
        ASSERT(drop_leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        ASSERT(save_leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        drop_hdr = &drop_leaf->hdr;
@@ -1906,7 +1916,7 @@ xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
                kmem_free(tmpbuffer);
        }
 
-       xfs_da_log_buf(state->args->trans, save_blk->bp, 0,
+       xfs_trans_log_buf(state->args->trans, save_blk->bp, 0,
                                           state->blocksize - 1);
 
        /*
@@ -1934,7 +1944,9 @@ xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
  * Don't change the args->value unless we find the attribute.
  */
 int
-xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
+xfs_attr_leaf_lookup_int(
+       struct xfs_buf  *bp,
+       xfs_da_args_t   *args)
 {
        xfs_attr_leafblock_t *leaf;
        xfs_attr_leaf_entry_t *entry;
@@ -1945,7 +1957,7 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
 
        trace_xfs_attr_leaf_lookup(args);
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        ASSERT(be16_to_cpu(leaf->hdr.count)
                                        < (XFS_LBSIZE(args->dp->i_mount)/8));
@@ -2041,7 +2053,9 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
  * list structure.
  */
 int
-xfs_attr_leaf_getvalue(xfs_dabuf_t *bp, xfs_da_args_t *args)
+xfs_attr_leaf_getvalue(
+       struct xfs_buf  *bp,
+       xfs_da_args_t   *args)
 {
        int valuelen;
        xfs_attr_leafblock_t *leaf;
@@ -2049,7 +2063,7 @@ xfs_attr_leaf_getvalue(xfs_dabuf_t *bp, xfs_da_args_t *args)
        xfs_attr_leaf_name_local_t *name_loc;
        xfs_attr_leaf_name_remote_t *name_rmt;
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        ASSERT(be16_to_cpu(leaf->hdr.count)
                                        < (XFS_LBSIZE(args->dp->i_mount)/8));
@@ -2247,12 +2261,14 @@ xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s,
  * Return 0 unless leaf2 should go before leaf1.
  */
 int
-xfs_attr_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp)
+xfs_attr_leaf_order(
+       struct xfs_buf  *leaf1_bp,
+       struct xfs_buf  *leaf2_bp)
 {
        xfs_attr_leafblock_t *leaf1, *leaf2;
 
-       leaf1 = leaf1_bp->data;
-       leaf2 = leaf2_bp->data;
+       leaf1 = leaf1_bp->b_addr;
+       leaf2 = leaf2_bp->b_addr;
        ASSERT((leaf1->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC)) &&
               (leaf2->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC)));
        if ((be16_to_cpu(leaf1->hdr.count) > 0) &&
@@ -2272,11 +2288,13 @@ xfs_attr_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp)
  * Pick up the last hashvalue from a leaf block.
  */
 xfs_dahash_t
-xfs_attr_leaf_lasthash(xfs_dabuf_t *bp, int *count)
+xfs_attr_leaf_lasthash(
+       struct xfs_buf  *bp,
+       int             *count)
 {
        xfs_attr_leafblock_t *leaf;
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        if (count)
                *count = be16_to_cpu(leaf->hdr.count);
@@ -2337,7 +2355,9 @@ xfs_attr_leaf_newentsize(int namelen, int valuelen, int blocksize, int *local)
  * Copy out attribute list entries for attr_list(), for leaf attribute lists.
  */
 int
-xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
+xfs_attr_leaf_list_int(
+       struct xfs_buf          *bp,
+       xfs_attr_list_context_t *context)
 {
        attrlist_cursor_kern_t *cursor;
        xfs_attr_leafblock_t *leaf;
@@ -2345,7 +2365,7 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
        int retval, i;
 
        ASSERT(bp != NULL);
-       leaf = bp->data;
+       leaf = bp->b_addr;
        cursor = context->cursor;
        cursor->initted = 1;
 
@@ -2463,7 +2483,7 @@ xfs_attr_leaf_clearflag(xfs_da_args_t *args)
        xfs_attr_leafblock_t *leaf;
        xfs_attr_leaf_entry_t *entry;
        xfs_attr_leaf_name_remote_t *name_rmt;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int error;
 #ifdef DEBUG
        xfs_attr_leaf_name_local_t *name_loc;
@@ -2482,7 +2502,7 @@ xfs_attr_leaf_clearflag(xfs_da_args_t *args)
        }
        ASSERT(bp != NULL);
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        ASSERT(args->index < be16_to_cpu(leaf->hdr.count));
        ASSERT(args->index >= 0);
@@ -2505,7 +2525,7 @@ xfs_attr_leaf_clearflag(xfs_da_args_t *args)
 #endif /* DEBUG */
 
        entry->flags &= ~XFS_ATTR_INCOMPLETE;
-       xfs_da_log_buf(args->trans, bp,
+       xfs_trans_log_buf(args->trans, bp,
                         XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
 
        if (args->rmtblkno) {
@@ -2513,10 +2533,9 @@ xfs_attr_leaf_clearflag(xfs_da_args_t *args)
                name_rmt = xfs_attr_leaf_name_remote(leaf, args->index);
                name_rmt->valueblk = cpu_to_be32(args->rmtblkno);
                name_rmt->valuelen = cpu_to_be32(args->valuelen);
-               xfs_da_log_buf(args->trans, bp,
+               xfs_trans_log_buf(args->trans, bp,
                         XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
        }
-       xfs_da_buf_done(bp);
 
        /*
         * Commit the flag value change and start the next trans in series.
@@ -2533,7 +2552,7 @@ xfs_attr_leaf_setflag(xfs_da_args_t *args)
        xfs_attr_leafblock_t *leaf;
        xfs_attr_leaf_entry_t *entry;
        xfs_attr_leaf_name_remote_t *name_rmt;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int error;
 
        trace_xfs_attr_leaf_setflag(args);
@@ -2548,7 +2567,7 @@ xfs_attr_leaf_setflag(xfs_da_args_t *args)
        }
        ASSERT(bp != NULL);
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        ASSERT(args->index < be16_to_cpu(leaf->hdr.count));
        ASSERT(args->index >= 0);
@@ -2556,16 +2575,15 @@ xfs_attr_leaf_setflag(xfs_da_args_t *args)
 
        ASSERT((entry->flags & XFS_ATTR_INCOMPLETE) == 0);
        entry->flags |= XFS_ATTR_INCOMPLETE;
-       xfs_da_log_buf(args->trans, bp,
+       xfs_trans_log_buf(args->trans, bp,
                        XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
        if ((entry->flags & XFS_ATTR_LOCAL) == 0) {
                name_rmt = xfs_attr_leaf_name_remote(leaf, args->index);
                name_rmt->valueblk = 0;
                name_rmt->valuelen = 0;
-               xfs_da_log_buf(args->trans, bp,
+               xfs_trans_log_buf(args->trans, bp,
                         XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
        }
-       xfs_da_buf_done(bp);
 
        /*
         * Commit the flag value change and start the next trans in series.
@@ -2586,7 +2604,7 @@ xfs_attr_leaf_flipflags(xfs_da_args_t *args)
        xfs_attr_leafblock_t *leaf1, *leaf2;
        xfs_attr_leaf_entry_t *entry1, *entry2;
        xfs_attr_leaf_name_remote_t *name_rmt;
-       xfs_dabuf_t *bp1, *bp2;
+       struct xfs_buf *bp1, *bp2;
        int error;
 #ifdef DEBUG
        xfs_attr_leaf_name_local_t *name_loc;
@@ -2620,13 +2638,13 @@ xfs_attr_leaf_flipflags(xfs_da_args_t *args)
                bp2 = bp1;
        }
 
-       leaf1 = bp1->data;
+       leaf1 = bp1->b_addr;
        ASSERT(leaf1->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        ASSERT(args->index < be16_to_cpu(leaf1->hdr.count));
        ASSERT(args->index >= 0);
        entry1 = &leaf1->entries[ args->index ];
 
-       leaf2 = bp2->data;
+       leaf2 = bp2->b_addr;
        ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        ASSERT(args->index2 < be16_to_cpu(leaf2->hdr.count));
        ASSERT(args->index2 >= 0);
@@ -2660,30 +2678,27 @@ xfs_attr_leaf_flipflags(xfs_da_args_t *args)
        ASSERT((entry2->flags & XFS_ATTR_INCOMPLETE) == 0);
 
        entry1->flags &= ~XFS_ATTR_INCOMPLETE;
-       xfs_da_log_buf(args->trans, bp1,
+       xfs_trans_log_buf(args->trans, bp1,
                          XFS_DA_LOGRANGE(leaf1, entry1, sizeof(*entry1)));
        if (args->rmtblkno) {
                ASSERT((entry1->flags & XFS_ATTR_LOCAL) == 0);
                name_rmt = xfs_attr_leaf_name_remote(leaf1, args->index);
                name_rmt->valueblk = cpu_to_be32(args->rmtblkno);
                name_rmt->valuelen = cpu_to_be32(args->valuelen);
-               xfs_da_log_buf(args->trans, bp1,
+               xfs_trans_log_buf(args->trans, bp1,
                         XFS_DA_LOGRANGE(leaf1, name_rmt, sizeof(*name_rmt)));
        }
 
        entry2->flags |= XFS_ATTR_INCOMPLETE;
-       xfs_da_log_buf(args->trans, bp2,
+       xfs_trans_log_buf(args->trans, bp2,
                          XFS_DA_LOGRANGE(leaf2, entry2, sizeof(*entry2)));
        if ((entry2->flags & XFS_ATTR_LOCAL) == 0) {
                name_rmt = xfs_attr_leaf_name_remote(leaf2, args->index2);
                name_rmt->valueblk = 0;
                name_rmt->valuelen = 0;
-               xfs_da_log_buf(args->trans, bp2,
+               xfs_trans_log_buf(args->trans, bp2,
                         XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
        }
-       xfs_da_buf_done(bp1);
-       if (bp1 != bp2)
-               xfs_da_buf_done(bp2);
 
        /*
         * Commit the flag value change and start the next trans in series.
@@ -2706,7 +2721,7 @@ xfs_attr_root_inactive(xfs_trans_t **trans, xfs_inode_t *dp)
 {
        xfs_da_blkinfo_t *info;
        xfs_daddr_t blkno;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int error;
 
        /*
@@ -2718,20 +2733,20 @@ xfs_attr_root_inactive(xfs_trans_t **trans, xfs_inode_t *dp)
        error = xfs_da_read_buf(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
        if (error)
                return(error);
-       blkno = xfs_da_blkno(bp);
+       blkno = XFS_BUF_ADDR(bp);
 
        /*
         * Invalidate the tree, even if the "tree" is only a single leaf block.
         * This is a depth-first traversal!
         */
-       info = bp->data;
+       info = bp->b_addr;
        if (info->magic == cpu_to_be16(XFS_DA_NODE_MAGIC)) {
                error = xfs_attr_node_inactive(trans, dp, bp, 1);
        } else if (info->magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC)) {
                error = xfs_attr_leaf_inactive(trans, dp, bp);
        } else {
                error = XFS_ERROR(EIO);
-               xfs_da_brelse(*trans, bp);
+               xfs_trans_brelse(*trans, bp);
        }
        if (error)
                return(error);
@@ -2742,7 +2757,7 @@ xfs_attr_root_inactive(xfs_trans_t **trans, xfs_inode_t *dp)
        error = xfs_da_get_buf(*trans, dp, 0, blkno, &bp, XFS_ATTR_FORK);
        if (error)
                return(error);
-       xfs_da_binval(*trans, bp);      /* remove from cache */
+       xfs_trans_binval(*trans, bp);   /* remove from cache */
        /*
         * Commit the invalidate and start the next transaction.
         */
@@ -2756,34 +2771,37 @@ xfs_attr_root_inactive(xfs_trans_t **trans, xfs_inode_t *dp)
  * We're doing a depth-first traversal in order to invalidate everything.
  */
 STATIC int
-xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp,
-                                  int level)
+xfs_attr_node_inactive(
+       struct xfs_trans **trans,
+       struct xfs_inode *dp,
+       struct xfs_buf  *bp,
+       int             level)
 {
        xfs_da_blkinfo_t *info;
        xfs_da_intnode_t *node;
        xfs_dablk_t child_fsb;
        xfs_daddr_t parent_blkno, child_blkno;
        int error, count, i;
-       xfs_dabuf_t *child_bp;
+       struct xfs_buf *child_bp;
 
        /*
         * Since this code is recursive (gasp!) we must protect ourselves.
         */
        if (level > XFS_DA_NODE_MAXDEPTH) {
-               xfs_da_brelse(*trans, bp);      /* no locks for later trans */
+               xfs_trans_brelse(*trans, bp);   /* no locks for later trans */
                return(XFS_ERROR(EIO));
        }
 
-       node = bp->data;
+       node = bp->b_addr;
        ASSERT(node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
-       parent_blkno = xfs_da_blkno(bp);        /* save for re-read later */
+       parent_blkno = XFS_BUF_ADDR(bp);        /* save for re-read later */
        count = be16_to_cpu(node->hdr.count);
        if (!count) {
-               xfs_da_brelse(*trans, bp);
+               xfs_trans_brelse(*trans, bp);
                return(0);
        }
        child_fsb = be32_to_cpu(node->btree[0].before);
-       xfs_da_brelse(*trans, bp);      /* no locks for later trans */
+       xfs_trans_brelse(*trans, bp);   /* no locks for later trans */
 
        /*
         * If this is the node level just above the leaves, simply loop
@@ -2803,12 +2821,12 @@ xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp,
                        return(error);
                if (child_bp) {
                                                /* save for re-read later */
-                       child_blkno = xfs_da_blkno(child_bp);
+                       child_blkno = XFS_BUF_ADDR(child_bp);
 
                        /*
                         * Invalidate the subtree, however we have to.
                         */
-                       info = child_bp->data;
+                       info = child_bp->b_addr;
                        if (info->magic == cpu_to_be16(XFS_DA_NODE_MAGIC)) {
                                error = xfs_attr_node_inactive(trans, dp,
                                                child_bp, level+1);
@@ -2817,7 +2835,7 @@ xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp,
                                                child_bp);
                        } else {
                                error = XFS_ERROR(EIO);
-                               xfs_da_brelse(*trans, child_bp);
+                               xfs_trans_brelse(*trans, child_bp);
                        }
                        if (error)
                                return(error);
@@ -2830,7 +2848,7 @@ xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp,
                                &child_bp, XFS_ATTR_FORK);
                        if (error)
                                return(error);
-                       xfs_da_binval(*trans, child_bp);
+                       xfs_trans_binval(*trans, child_bp);
                }
 
                /*
@@ -2843,7 +2861,7 @@ xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp,
                        if (error)
                                return(error);
                        child_fsb = be32_to_cpu(node->btree[i+1].before);
-                       xfs_da_brelse(*trans, bp);
+                       xfs_trans_brelse(*trans, bp);
                }
                /*
                 * Atomically commit the whole invalidate stuff.
@@ -2863,7 +2881,10 @@ xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp,
  * caught holding something that the logging code wants to flush to disk.
  */
 STATIC int
-xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp)
+xfs_attr_leaf_inactive(
+       struct xfs_trans **trans,
+       struct xfs_inode *dp,
+       struct xfs_buf  *bp)
 {
        xfs_attr_leafblock_t *leaf;
        xfs_attr_leaf_entry_t *entry;
@@ -2871,7 +2892,7 @@ xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp)
        xfs_attr_inactive_list_t *list, *lp;
        int error, count, size, tmp, i;
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
 
        /*
@@ -2892,7 +2913,7 @@ xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp)
         * If there are no "remote" values, we're done.
         */
        if (count == 0) {
-               xfs_da_brelse(*trans, bp);
+               xfs_trans_brelse(*trans, bp);
                return(0);
        }
 
@@ -2919,7 +2940,7 @@ xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp)
                        }
                }
        }
-       xfs_da_brelse(*trans, bp);      /* unlock for trans. in freextent() */
+       xfs_trans_brelse(*trans, bp);   /* unlock for trans. in freextent() */
 
        /*
         * Invalidate each of the "remote" value extents.
index 9c7d22fdcf4d8ea0412d840a109f14c3923d3aab..dea17722945e1646a54498047c31c6918421f8ae 100644 (file)
@@ -31,7 +31,6 @@
 struct attrlist;
 struct attrlist_cursor_kern;
 struct xfs_attr_list_context;
-struct xfs_dabuf;
 struct xfs_da_args;
 struct xfs_da_state;
 struct xfs_da_state_blk;
@@ -215,7 +214,7 @@ int xfs_attr_shortform_getvalue(struct xfs_da_args *args);
 int    xfs_attr_shortform_to_leaf(struct xfs_da_args *args);
 int    xfs_attr_shortform_remove(struct xfs_da_args *args);
 int    xfs_attr_shortform_list(struct xfs_attr_list_context *context);
-int    xfs_attr_shortform_allfit(struct xfs_dabuf *bp, struct xfs_inode *dp);
+int    xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
 int    xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes);
 
 
@@ -223,7 +222,7 @@ int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes);
  * Internal routines when attribute fork size == XFS_LBSIZE(mp).
  */
 int    xfs_attr_leaf_to_node(struct xfs_da_args *args);
-int    xfs_attr_leaf_to_shortform(struct xfs_dabuf *bp,
+int    xfs_attr_leaf_to_shortform(struct xfs_buf *bp,
                                   struct xfs_da_args *args, int forkoff);
 int    xfs_attr_leaf_clearflag(struct xfs_da_args *args);
 int    xfs_attr_leaf_setflag(struct xfs_da_args *args);
@@ -235,14 +234,14 @@ int       xfs_attr_leaf_flipflags(xfs_da_args_t *args);
 int    xfs_attr_leaf_split(struct xfs_da_state *state,
                                   struct xfs_da_state_blk *oldblk,
                                   struct xfs_da_state_blk *newblk);
-int    xfs_attr_leaf_lookup_int(struct xfs_dabuf *leaf,
+int    xfs_attr_leaf_lookup_int(struct xfs_buf *leaf,
                                        struct xfs_da_args *args);
-int    xfs_attr_leaf_getvalue(struct xfs_dabuf *bp, struct xfs_da_args *args);
-int    xfs_attr_leaf_add(struct xfs_dabuf *leaf_buffer,
+int    xfs_attr_leaf_getvalue(struct xfs_buf *bp, struct xfs_da_args *args);
+int    xfs_attr_leaf_add(struct xfs_buf *leaf_buffer,
                                 struct xfs_da_args *args);
-int    xfs_attr_leaf_remove(struct xfs_dabuf *leaf_buffer,
+int    xfs_attr_leaf_remove(struct xfs_buf *leaf_buffer,
                                    struct xfs_da_args *args);
-int    xfs_attr_leaf_list_int(struct xfs_dabuf *bp,
+int    xfs_attr_leaf_list_int(struct xfs_buf *bp,
                                      struct xfs_attr_list_context *context);
 
 /*
@@ -257,9 +256,9 @@ int xfs_attr_root_inactive(struct xfs_trans **trans, struct xfs_inode *dp);
 /*
  * Utility routines.
  */
-xfs_dahash_t   xfs_attr_leaf_lasthash(struct xfs_dabuf *bp, int *count);
-int    xfs_attr_leaf_order(struct xfs_dabuf *leaf1_bp,
-                                  struct xfs_dabuf *leaf2_bp);
+xfs_dahash_t   xfs_attr_leaf_lasthash(struct xfs_buf *bp, int *count);
+int    xfs_attr_leaf_order(struct xfs_buf *leaf1_bp,
+                                  struct xfs_buf *leaf2_bp);
 int    xfs_attr_leaf_newentsize(int namelen, int valuelen, int blocksize,
                                        int *local);
 #endif /* __XFS_ATTR_LEAF_H__ */
index 58b815ec8c91f6ef70fef988eecfd74533bd08b0..848ffa77707b98bf272f61fc162f6e361504926e 100644 (file)
@@ -5517,7 +5517,7 @@ xfs_getbmap(
                if (xfs_get_extsz_hint(ip) ||
                    ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){
                        prealloced = 1;
-                       fixlen = XFS_MAXIOFFSET(mp);
+                       fixlen = mp->m_super->s_maxbytes;
                } else {
                        prealloced = 0;
                        fixlen = XFS_ISIZE(ip);
index 269b35c084dab6906267ccf66f473c98e85ce473..d7a9dd735e1e429a1787d8b0e8e1c9ddde5eff10 100644 (file)
@@ -164,14 +164,49 @@ xfs_buf_stale(
        ASSERT(atomic_read(&bp->b_hold) >= 1);
 }
 
+static int
+xfs_buf_get_maps(
+       struct xfs_buf          *bp,
+       int                     map_count)
+{
+       ASSERT(bp->b_maps == NULL);
+       bp->b_map_count = map_count;
+
+       if (map_count == 1) {
+               bp->b_maps = &bp->b_map;
+               return 0;
+       }
+
+       bp->b_maps = kmem_zalloc(map_count * sizeof(struct xfs_buf_map),
+                               KM_NOFS);
+       if (!bp->b_maps)
+               return ENOMEM;
+       return 0;
+}
+
+/*
+ *     Frees b_pages if it was allocated.
+ */
+static void
+xfs_buf_free_maps(
+       struct xfs_buf  *bp)
+{
+       if (bp->b_maps != &bp->b_map) {
+               kmem_free(bp->b_maps);
+               bp->b_maps = NULL;
+       }
+}
+
 struct xfs_buf *
-xfs_buf_alloc(
+_xfs_buf_alloc(
        struct xfs_buftarg      *target,
-       xfs_daddr_t             blkno,
-       size_t                  numblks,
+       struct xfs_buf_map      *map,
+       int                     nmaps,
        xfs_buf_flags_t         flags)
 {
        struct xfs_buf          *bp;
+       int                     error;
+       int                     i;
 
        bp = kmem_zone_zalloc(xfs_buf_zone, KM_NOFS);
        if (unlikely(!bp))
@@ -192,16 +227,28 @@ xfs_buf_alloc(
        sema_init(&bp->b_sema, 0); /* held, no waiters */
        XB_SET_OWNER(bp);
        bp->b_target = target;
+       bp->b_flags = flags;
 
        /*
         * Set length and io_length to the same value initially.
         * I/O routines should use io_length, which will be the same in
         * most cases but may be reset (e.g. XFS recovery).
         */
-       bp->b_length = numblks;
-       bp->b_io_length = numblks;
-       bp->b_flags = flags;
-       bp->b_bn = blkno;
+       error = xfs_buf_get_maps(bp, nmaps);
+       if (error)  {
+               kmem_zone_free(xfs_buf_zone, bp);
+               return NULL;
+       }
+
+       bp->b_bn = map[0].bm_bn;
+       bp->b_length = 0;
+       for (i = 0; i < nmaps; i++) {
+               bp->b_maps[i].bm_bn = map[i].bm_bn;
+               bp->b_maps[i].bm_len = map[i].bm_len;
+               bp->b_length += map[i].bm_len;
+       }
+       bp->b_io_length = bp->b_length;
+
        atomic_set(&bp->b_pin_count, 0);
        init_waitqueue_head(&bp->b_waiters);
 
@@ -280,6 +327,7 @@ xfs_buf_free(
        } else if (bp->b_flags & _XBF_KMEM)
                kmem_free(bp->b_addr);
        _xfs_buf_free_pages(bp);
+       xfs_buf_free_maps(bp);
        kmem_zone_free(xfs_buf_zone, bp);
 }
 
@@ -327,8 +375,9 @@ xfs_buf_allocate_memory(
        }
 
 use_alloc_page:
-       start = BBTOB(bp->b_bn) >> PAGE_SHIFT;
-       end = (BBTOB(bp->b_bn + bp->b_length) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       start = BBTOB(bp->b_map.bm_bn) >> PAGE_SHIFT;
+       end = (BBTOB(bp->b_map.bm_bn + bp->b_length) + PAGE_SIZE - 1)
+                                                               >> PAGE_SHIFT;
        page_count = end - start;
        error = _xfs_buf_get_pages(bp, page_count, flags);
        if (unlikely(error))
@@ -425,8 +474,8 @@ _xfs_buf_map_pages(
 xfs_buf_t *
 _xfs_buf_find(
        struct xfs_buftarg      *btp,
-       xfs_daddr_t             blkno,
-       size_t                  numblks,
+       struct xfs_buf_map      *map,
+       int                     nmaps,
        xfs_buf_flags_t         flags,
        xfs_buf_t               *new_bp)
 {
@@ -435,7 +484,12 @@ _xfs_buf_find(
        struct rb_node          **rbp;
        struct rb_node          *parent;
        xfs_buf_t               *bp;
+       xfs_daddr_t             blkno = map[0].bm_bn;
+       int                     numblks = 0;
+       int                     i;
 
+       for (i = 0; i < nmaps; i++)
+               numblks += map[i].bm_len;
        numbytes = BBTOB(numblks);
 
        /* Check for IOs smaller than the sector size / not sector aligned */
@@ -527,31 +581,31 @@ found:
  * more hits than misses.
  */
 struct xfs_buf *
-xfs_buf_get(
-       xfs_buftarg_t           *target,
-       xfs_daddr_t             blkno,
-       size_t                  numblks,
+xfs_buf_get_map(
+       struct xfs_buftarg      *target,
+       struct xfs_buf_map      *map,
+       int                     nmaps,
        xfs_buf_flags_t         flags)
 {
        struct xfs_buf          *bp;
        struct xfs_buf          *new_bp;
        int                     error = 0;
 
-       bp = _xfs_buf_find(target, blkno, numblks, flags, NULL);
+       bp = _xfs_buf_find(target, map, nmaps, flags, NULL);
        if (likely(bp))
                goto found;
 
-       new_bp = xfs_buf_alloc(target, blkno, numblks, flags);
+       new_bp = _xfs_buf_alloc(target, map, nmaps, flags);
        if (unlikely(!new_bp))
                return NULL;
 
        error = xfs_buf_allocate_memory(new_bp, flags);
        if (error) {
-               kmem_zone_free(xfs_buf_zone, new_bp);
+               xfs_buf_free(new_bp);
                return NULL;
        }
 
-       bp = _xfs_buf_find(target, blkno, numblks, flags, new_bp);
+       bp = _xfs_buf_find(target, map, nmaps, flags, new_bp);
        if (!bp) {
                xfs_buf_free(new_bp);
                return NULL;
@@ -560,8 +614,6 @@ xfs_buf_get(
        if (bp != new_bp)
                xfs_buf_free(new_bp);
 
-       bp->b_io_length = bp->b_length;
-
 found:
        if (!bp->b_addr) {
                error = _xfs_buf_map_pages(bp, flags);
@@ -584,7 +636,7 @@ _xfs_buf_read(
        xfs_buf_flags_t         flags)
 {
        ASSERT(!(flags & XBF_WRITE));
-       ASSERT(bp->b_bn != XFS_BUF_DADDR_NULL);
+       ASSERT(bp->b_map.bm_bn != XFS_BUF_DADDR_NULL);
 
        bp->b_flags &= ~(XBF_WRITE | XBF_ASYNC | XBF_READ_AHEAD);
        bp->b_flags |= flags & (XBF_READ | XBF_ASYNC | XBF_READ_AHEAD);
@@ -596,17 +648,17 @@ _xfs_buf_read(
 }
 
 xfs_buf_t *
-xfs_buf_read(
-       xfs_buftarg_t           *target,
-       xfs_daddr_t             blkno,
-       size_t                  numblks,
+xfs_buf_read_map(
+       struct xfs_buftarg      *target,
+       struct xfs_buf_map      *map,
+       int                     nmaps,
        xfs_buf_flags_t         flags)
 {
-       xfs_buf_t               *bp;
+       struct xfs_buf          *bp;
 
        flags |= XBF_READ;
 
-       bp = xfs_buf_get(target, blkno, numblks, flags);
+       bp = xfs_buf_get_map(target, map, nmaps, flags);
        if (bp) {
                trace_xfs_buf_read(bp, flags, _RET_IP_);
 
@@ -634,15 +686,15 @@ xfs_buf_read(
  *     safe manner.
  */
 void
-xfs_buf_readahead(
-       xfs_buftarg_t           *target,
-       xfs_daddr_t             blkno,
-       size_t                  numblks)
+xfs_buf_readahead_map(
+       struct xfs_buftarg      *target,
+       struct xfs_buf_map      *map,
+       int                     nmaps)
 {
        if (bdi_read_congested(target->bt_bdi))
                return;
 
-       xfs_buf_read(target, blkno, numblks,
+       xfs_buf_read_map(target, map, nmaps,
                     XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD);
 }
 
@@ -665,8 +717,10 @@ xfs_buf_read_uncached(
                return NULL;
 
        /* set up the buffer for a read IO */
-       XFS_BUF_SET_ADDR(bp, daddr);
-       XFS_BUF_READ(bp);
+       ASSERT(bp->b_map_count == 1);
+       bp->b_bn = daddr;
+       bp->b_maps[0].bm_bn = daddr;
+       bp->b_flags |= XBF_READ;
 
        xfsbdstrat(target->bt_mount, bp);
        error = xfs_buf_iowait(bp);
@@ -694,7 +748,11 @@ xfs_buf_set_empty(
        bp->b_addr = NULL;
        bp->b_length = numblks;
        bp->b_io_length = numblks;
+
+       ASSERT(bp->b_map_count == 1);
        bp->b_bn = XFS_BUF_DADDR_NULL;
+       bp->b_maps[0].bm_bn = XFS_BUF_DADDR_NULL;
+       bp->b_maps[0].bm_len = bp->b_length;
 }
 
 static inline struct page *
@@ -758,9 +816,10 @@ xfs_buf_get_uncached(
 {
        unsigned long           page_count;
        int                     error, i;
-       xfs_buf_t               *bp;
+       struct xfs_buf          *bp;
+       DEFINE_SINGLE_BUF_MAP(map, XFS_BUF_DADDR_NULL, numblks);
 
-       bp = xfs_buf_alloc(target, XFS_BUF_DADDR_NULL, numblks, 0);
+       bp = _xfs_buf_alloc(target, &map, 1, 0);
        if (unlikely(bp == NULL))
                goto fail;
 
@@ -791,6 +850,7 @@ xfs_buf_get_uncached(
                __free_page(bp->b_pages[i]);
        _xfs_buf_free_pages(bp);
  fail_free_buf:
+       xfs_buf_free_maps(bp);
        kmem_zone_free(xfs_buf_zone, bp);
  fail:
        return NULL;
@@ -1144,36 +1204,39 @@ xfs_buf_bio_end_io(
        bio_put(bio);
 }
 
-STATIC void
-_xfs_buf_ioapply(
-       xfs_buf_t               *bp)
+static void
+xfs_buf_ioapply_map(
+       struct xfs_buf  *bp,
+       int             map,
+       int             *buf_offset,
+       int             *count,
+       int             rw)
 {
-       int                     rw, map_i, total_nr_pages, nr_pages;
-       struct bio              *bio;
-       int                     offset = bp->b_offset;
-       int                     size = BBTOB(bp->b_io_length);
-       sector_t                sector = bp->b_bn;
+       int             page_index;
+       int             total_nr_pages = bp->b_page_count;
+       int             nr_pages;
+       struct bio      *bio;
+       sector_t        sector =  bp->b_maps[map].bm_bn;
+       int             size;
+       int             offset;
 
        total_nr_pages = bp->b_page_count;
-       map_i = 0;
 
-       if (bp->b_flags & XBF_WRITE) {
-               if (bp->b_flags & XBF_SYNCIO)
-                       rw = WRITE_SYNC;
-               else
-                       rw = WRITE;
-               if (bp->b_flags & XBF_FUA)
-                       rw |= REQ_FUA;
-               if (bp->b_flags & XBF_FLUSH)
-                       rw |= REQ_FLUSH;
-       } else if (bp->b_flags & XBF_READ_AHEAD) {
-               rw = READA;
-       } else {
-               rw = READ;
+       /* skip the pages in the buffer before the start offset */
+       page_index = 0;
+       offset = *buf_offset;
+       while (offset >= PAGE_SIZE) {
+               page_index++;
+               offset -= PAGE_SIZE;
        }
 
-       /* we only use the buffer cache for meta-data */
-       rw |= REQ_META;
+       /*
+        * Limit the IO size to the length of the current vector, and update the
+        * remaining IO count for the next time around.
+        */
+       size = min_t(int, BBTOB(bp->b_maps[map].bm_len), *count);
+       *count -= size;
+       *buf_offset += size;
 
 next_chunk:
        atomic_inc(&bp->b_io_remaining);
@@ -1188,13 +1251,14 @@ next_chunk:
        bio->bi_private = bp;
 
 
-       for (; size && nr_pages; nr_pages--, map_i++) {
+       for (; size && nr_pages; nr_pages--, page_index++) {
                int     rbytes, nbytes = PAGE_SIZE - offset;
 
                if (nbytes > size)
                        nbytes = size;
 
-               rbytes = bio_add_page(bio, bp->b_pages[map_i], nbytes, offset);
+               rbytes = bio_add_page(bio, bp->b_pages[page_index], nbytes,
+                                     offset);
                if (rbytes < nbytes)
                        break;
 
@@ -1216,6 +1280,54 @@ next_chunk:
                xfs_buf_ioerror(bp, EIO);
                bio_put(bio);
        }
+
+}
+
+STATIC void
+_xfs_buf_ioapply(
+       struct xfs_buf  *bp)
+{
+       struct blk_plug plug;
+       int             rw;
+       int             offset;
+       int             size;
+       int             i;
+
+       if (bp->b_flags & XBF_WRITE) {
+               if (bp->b_flags & XBF_SYNCIO)
+                       rw = WRITE_SYNC;
+               else
+                       rw = WRITE;
+               if (bp->b_flags & XBF_FUA)
+                       rw |= REQ_FUA;
+               if (bp->b_flags & XBF_FLUSH)
+                       rw |= REQ_FLUSH;
+       } else if (bp->b_flags & XBF_READ_AHEAD) {
+               rw = READA;
+       } else {
+               rw = READ;
+       }
+
+       /* we only use the buffer cache for meta-data */
+       rw |= REQ_META;
+
+       /*
+        * Walk all the vectors issuing IO on them. Set up the initial offset
+        * into the buffer and the desired IO size before we start -
+        * _xfs_buf_ioapply_vec() will modify them appropriately for each
+        * subsequent call.
+        */
+       offset = bp->b_offset;
+       size = BBTOB(bp->b_io_length);
+       blk_start_plug(&plug);
+       for (i = 0; i < bp->b_map_count; i++) {
+               xfs_buf_ioapply_map(bp, i, &offset, &size, rw);
+               if (bp->b_error)
+                       break;
+               if (size <= 0)
+                       break;  /* all done */
+       }
+       blk_finish_plug(&plug);
 }
 
 void
@@ -1557,7 +1669,7 @@ xfs_buf_cmp(
        struct xfs_buf  *bp = container_of(b, struct xfs_buf, b_list);
        xfs_daddr_t             diff;
 
-       diff = ap->b_bn - bp->b_bn;
+       diff = ap->b_map.bm_bn - bp->b_map.bm_bn;
        if (diff < 0)
                return -1;
        if (diff > 0)
index 79344c48008eedaab4aaa21dc6ed28fe328607d3..d03b73b9604e3d55d93f1fdc08201512b01449dd 100644 (file)
@@ -58,6 +58,7 @@ typedef enum {
 #define _XBF_PAGES     (1 << 20)/* backed by refcounted pages */
 #define _XBF_KMEM      (1 << 21)/* backed by heap memory */
 #define _XBF_DELWRI_Q  (1 << 22)/* buffer on a delwri queue */
+#define _XBF_COMPOUND  (1 << 23)/* compound buffer */
 
 typedef unsigned int xfs_buf_flags_t;
 
@@ -75,7 +76,8 @@ typedef unsigned int xfs_buf_flags_t;
        { XBF_UNMAPPED,         "UNMAPPED" },   /* ditto */\
        { _XBF_PAGES,           "PAGES" }, \
        { _XBF_KMEM,            "KMEM" }, \
-       { _XBF_DELWRI_Q,        "DELWRI_Q" }
+       { _XBF_DELWRI_Q,        "DELWRI_Q" }, \
+       { _XBF_COMPOUND,        "COMPOUND" }
 
 typedef struct xfs_buftarg {
        dev_t                   bt_dev;
@@ -98,6 +100,14 @@ typedef void (*xfs_buf_iodone_t)(struct xfs_buf *);
 
 #define XB_PAGES       2
 
+struct xfs_buf_map {
+       xfs_daddr_t             bm_bn;  /* block number for I/O */
+       int                     bm_len; /* size of I/O */
+};
+
+#define DEFINE_SINGLE_BUF_MAP(map, blkno, numblk) \
+       struct xfs_buf_map (map) = { .bm_bn = (blkno), .bm_len = (numblk) };
+
 typedef struct xfs_buf {
        /*
         * first cacheline holds all the fields needed for an uncontended cache
@@ -107,7 +117,7 @@ typedef struct xfs_buf {
         * fast-path on locking.
         */
        struct rb_node          b_rbnode;       /* rbtree node */
-       xfs_daddr_t             b_bn;           /* block number for I/O */
+       xfs_daddr_t             b_bn;           /* block number of buffer */
        int                     b_length;       /* size of buffer in BBs */
        atomic_t                b_hold;         /* reference count */
        atomic_t                b_lru_ref;      /* lru reclaim ref count */
@@ -127,12 +137,16 @@ typedef struct xfs_buf {
        struct xfs_trans        *b_transp;
        struct page             **b_pages;      /* array of page pointers */
        struct page             *b_page_array[XB_PAGES]; /* inline pages */
+       struct xfs_buf_map      *b_maps;        /* compound buffer map */
+       struct xfs_buf_map      b_map;          /* inline compound buffer map */
+       int                     b_map_count;
        int                     b_io_length;    /* IO size in BBs */
        atomic_t                b_pin_count;    /* pin count */
        atomic_t                b_io_remaining; /* #outstanding I/O requests */
        unsigned int            b_page_count;   /* size of page array */
        unsigned int            b_offset;       /* page offset in first page */
        unsigned short          b_error;        /* error code on I/O */
+
 #ifdef XFS_BUF_LOCK_TRACKING
        int                     b_last_holder;
 #endif
@@ -140,22 +154,78 @@ typedef struct xfs_buf {
 
 
 /* Finding and Reading Buffers */
-struct xfs_buf *_xfs_buf_find(struct xfs_buftarg *target, xfs_daddr_t blkno,
-                               size_t numblks, xfs_buf_flags_t flags,
-                               struct xfs_buf *new_bp);
-#define xfs_incore(buftarg,blkno,len,lockit) \
-       _xfs_buf_find(buftarg, blkno ,len, lockit, NULL)
-
-struct xfs_buf *xfs_buf_get(struct xfs_buftarg *target, xfs_daddr_t blkno,
-                               size_t numblks, xfs_buf_flags_t flags);
-struct xfs_buf *xfs_buf_read(struct xfs_buftarg *target, xfs_daddr_t blkno,
-                               size_t numblks, xfs_buf_flags_t flags);
-void xfs_buf_readahead(struct xfs_buftarg *target, xfs_daddr_t blkno,
-                               size_t numblks);
+struct xfs_buf *_xfs_buf_find(struct xfs_buftarg *target,
+                             struct xfs_buf_map *map, int nmaps,
+                             xfs_buf_flags_t flags, struct xfs_buf *new_bp);
+
+static inline struct xfs_buf *
+xfs_incore(
+       struct xfs_buftarg      *target,
+       xfs_daddr_t             blkno,
+       size_t                  numblks,
+       xfs_buf_flags_t         flags)
+{
+       DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
+       return _xfs_buf_find(target, &map, 1, flags, NULL);
+}
+
+struct xfs_buf *_xfs_buf_alloc(struct xfs_buftarg *target,
+                              struct xfs_buf_map *map, int nmaps,
+                              xfs_buf_flags_t flags);
+
+static inline struct xfs_buf *
+xfs_buf_alloc(
+       struct xfs_buftarg      *target,
+       xfs_daddr_t             blkno,
+       size_t                  numblks,
+       xfs_buf_flags_t         flags)
+{
+       DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
+       return _xfs_buf_alloc(target, &map, 1, flags);
+}
+
+struct xfs_buf *xfs_buf_get_map(struct xfs_buftarg *target,
+                              struct xfs_buf_map *map, int nmaps,
+                              xfs_buf_flags_t flags);
+struct xfs_buf *xfs_buf_read_map(struct xfs_buftarg *target,
+                              struct xfs_buf_map *map, int nmaps,
+                              xfs_buf_flags_t flags);
+void xfs_buf_readahead_map(struct xfs_buftarg *target,
+                              struct xfs_buf_map *map, int nmaps);
+
+static inline struct xfs_buf *
+xfs_buf_get(
+       struct xfs_buftarg      *target,
+       xfs_daddr_t             blkno,
+       size_t                  numblks,
+       xfs_buf_flags_t         flags)
+{
+       DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
+       return xfs_buf_get_map(target, &map, 1, flags);
+}
+
+static inline struct xfs_buf *
+xfs_buf_read(
+       struct xfs_buftarg      *target,
+       xfs_daddr_t             blkno,
+       size_t                  numblks,
+       xfs_buf_flags_t         flags)
+{
+       DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
+       return xfs_buf_read_map(target, &map, 1, flags);
+}
+
+static inline void
+xfs_buf_readahead(
+       struct xfs_buftarg      *target,
+       xfs_daddr_t             blkno,
+       size_t                  numblks)
+{
+       DEFINE_SINGLE_BUF_MAP(map, blkno, numblks);
+       return xfs_buf_readahead_map(target, &map, 1);
+}
 
 struct xfs_buf *xfs_buf_get_empty(struct xfs_buftarg *target, size_t numblks);
-struct xfs_buf *xfs_buf_alloc(struct xfs_buftarg *target, xfs_daddr_t blkno,
-                               size_t numblks, xfs_buf_flags_t flags);
 void xfs_buf_set_empty(struct xfs_buf *bp, size_t numblks);
 int xfs_buf_associate_memory(struct xfs_buf *bp, void *mem, size_t length);
 
@@ -232,8 +302,18 @@ 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_ADDR(bp)               ((bp)->b_bn)
-#define XFS_BUF_SET_ADDR(bp, bno)      ((bp)->b_bn = (xfs_daddr_t)(bno))
+/*
+ * These macros use the IO block map rather than b_bn. b_bn is now really
+ * just for the buffer cache index for cached buffers. As IO does not use b_bn
+ * anymore, uncached buffers do not use b_bn at all and hence must modify the IO
+ * map directly. Uncached buffers are not allowed to be discontiguous, so this
+ * is safe to do.
+ *
+ * In future, uncached buffers will pass the block number directly to the io
+ * request function and hence these macros will go away at that point.
+ */
+#define XFS_BUF_ADDR(bp)               ((bp)->b_map.bm_bn)
+#define XFS_BUF_SET_ADDR(bp, bno)      ((bp)->b_map.bm_bn = (xfs_daddr_t)(bno))
 
 static inline void xfs_buf_set_ref(struct xfs_buf *bp, int lru_ref)
 {
index d9e451115f980ac1529c4e89aa89665c82661360..a8d0ed911196120a80a26bb7232f79d3a5badee1 100644 (file)
@@ -153,33 +153,25 @@ STATIC void       xfs_buf_do_callbacks(struct xfs_buf *bp);
  * If the XFS_BLI_STALE flag has been set, then log nothing.
  */
 STATIC uint
-xfs_buf_item_size(
-       struct xfs_log_item     *lip)
+xfs_buf_item_size_segment(
+       struct xfs_buf_log_item *bip,
+       struct xfs_buf_log_format *blfp)
 {
-       struct xfs_buf_log_item *bip = BUF_ITEM(lip);
        struct xfs_buf          *bp = bip->bli_buf;
        uint                    nvecs;
        int                     next_bit;
        int                     last_bit;
 
-       ASSERT(atomic_read(&bip->bli_refcount) > 0);
-       if (bip->bli_flags & XFS_BLI_STALE) {
-               /*
-                * The buffer is stale, so all we need to log
-                * is the buf log format structure with the
-                * cancel flag in it.
-                */
-               trace_xfs_buf_item_size_stale(bip);
-               ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
-               return 1;
-       }
+       last_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0);
+       if (last_bit == -1)
+               return 0;
+
+       /*
+        * initial count for a dirty buffer is 2 vectors - the format structure
+        * and the first dirty region.
+        */
+       nvecs = 2;
 
-       ASSERT(bip->bli_flags & XFS_BLI_LOGGED);
-       nvecs = 1;
-       last_bit = xfs_next_bit(bip->bli_format.blf_data_map,
-                                        bip->bli_format.blf_map_size, 0);
-       ASSERT(last_bit != -1);
-       nvecs++;
        while (last_bit != -1) {
                /*
                 * This takes the bit number to start looking from and
@@ -187,16 +179,15 @@ xfs_buf_item_size(
                 * if there are no more bits set or the start bit is
                 * beyond the end of the bitmap.
                 */
-               next_bit = xfs_next_bit(bip->bli_format.blf_data_map,
-                                                bip->bli_format.blf_map_size,
-                                                last_bit + 1);
+               next_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size,
+                                       last_bit + 1);
                /*
                 * If we run out of bits, leave the loop,
                 * else if we find a new set of bits bump the number of vecs,
                 * else keep scanning the current set of bits.
                 */
                if (next_bit == -1) {
-                       last_bit = -1;
+                       break;
                } else if (next_bit != last_bit + 1) {
                        last_bit = next_bit;
                        nvecs++;
@@ -210,22 +201,73 @@ xfs_buf_item_size(
                }
        }
 
-       trace_xfs_buf_item_size(bip);
        return nvecs;
 }
 
 /*
- * This is called to fill in the vector of log iovecs for the
- * given log buf item.  It fills the first entry with a buf log
- * format structure, and the rest point to contiguous chunks
- * within the buffer.
+ * This returns the number of log iovecs needed to log the given buf log item.
+ *
+ * It calculates this as 1 iovec for the buf log format structure and 1 for each
+ * stretch of non-contiguous chunks to be logged.  Contiguous chunks are logged
+ * in a single iovec.
+ *
+ * Discontiguous buffers need a format structure per region that that is being
+ * logged. This makes the changes in the buffer appear to log recovery as though
+ * they came from separate buffers, just like would occur if multiple buffers
+ * were used instead of a single discontiguous buffer. This enables
+ * discontiguous buffers to be in-memory constructs, completely transparent to
+ * what ends up on disk.
+ *
+ * If the XFS_BLI_STALE flag has been set, then log nothing but the buf log
+ * format structures.
  */
-STATIC void
-xfs_buf_item_format(
-       struct xfs_log_item     *lip,
-       struct xfs_log_iovec    *vecp)
+STATIC uint
+xfs_buf_item_size(
+       struct xfs_log_item     *lip)
 {
        struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+       uint                    nvecs;
+       int                     i;
+
+       ASSERT(atomic_read(&bip->bli_refcount) > 0);
+       if (bip->bli_flags & XFS_BLI_STALE) {
+               /*
+                * The buffer is stale, so all we need to log
+                * is the buf log format structure with the
+                * cancel flag in it.
+                */
+               trace_xfs_buf_item_size_stale(bip);
+               ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
+               return bip->bli_format_count;
+       }
+
+       ASSERT(bip->bli_flags & XFS_BLI_LOGGED);
+
+       /*
+        * the vector count is based on the number of buffer vectors we have
+        * dirty bits in. This will only be greater than one when we have a
+        * compound buffer with more than one segment dirty. Hence for compound
+        * buffers we need to track which segment the dirty bits correspond to,
+        * and when we move from one segment to the next increment the vector
+        * count for the extra buf log format structure that will need to be
+        * written.
+        */
+       nvecs = 0;
+       for (i = 0; i < bip->bli_format_count; i++) {
+               nvecs += xfs_buf_item_size_segment(bip, &bip->bli_formats[i]);
+       }
+
+       trace_xfs_buf_item_size(bip);
+       return nvecs;
+}
+
+static struct xfs_log_iovec *
+xfs_buf_item_format_segment(
+       struct xfs_buf_log_item *bip,
+       struct xfs_log_iovec    *vecp,
+       uint                    offset,
+       struct xfs_buf_log_format *blfp)
+{
        struct xfs_buf  *bp = bip->bli_buf;
        uint            base_size;
        uint            nvecs;
@@ -235,40 +277,22 @@ xfs_buf_item_format(
        uint            nbits;
        uint            buffer_offset;
 
-       ASSERT(atomic_read(&bip->bli_refcount) > 0);
-       ASSERT((bip->bli_flags & XFS_BLI_LOGGED) ||
-              (bip->bli_flags & XFS_BLI_STALE));
+       /* copy the flags across from the base format item */
+       blfp->blf_flags = bip->bli_format.blf_flags;
 
        /*
-        * The size of the base structure is the size of the
-        * declared structure plus the space for the extra words
-        * of the bitmap.  We subtract one from the map size, because
-        * the first element of the bitmap is accounted for in the
-        * size of the base structure.
+        * Base size is the actual size of the ondisk structure - it reflects
+        * the actual size of the dirty bitmap rather than the size of the in
+        * memory structure.
         */
-       base_size =
-               (uint)(sizeof(xfs_buf_log_format_t) +
-                      ((bip->bli_format.blf_map_size - 1) * sizeof(uint)));
-       vecp->i_addr = &bip->bli_format;
+       base_size = offsetof(struct xfs_buf_log_format, blf_data_map) +
+                       (blfp->blf_map_size * sizeof(blfp->blf_data_map[0]));
+       vecp->i_addr = blfp;
        vecp->i_len = base_size;
        vecp->i_type = XLOG_REG_TYPE_BFORMAT;
        vecp++;
        nvecs = 1;
 
-       /*
-        * If it is an inode buffer, transfer the in-memory state to the
-        * format flags and clear the in-memory state. We do not transfer
-        * this state if the inode buffer allocation has not yet been committed
-        * to the log as setting the XFS_BLI_INODE_BUF flag will prevent
-        * correct replay of the inode allocation.
-        */
-       if (bip->bli_flags & XFS_BLI_INODE_BUF) {
-               if (!((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) &&
-                     xfs_log_item_in_current_chkpt(lip)))
-                       bip->bli_format.blf_flags |= XFS_BLF_INODE_BUF;
-               bip->bli_flags &= ~XFS_BLI_INODE_BUF;
-       }
-
        if (bip->bli_flags & XFS_BLI_STALE) {
                /*
                 * The buffer is stale, so all we need to log
@@ -276,16 +300,15 @@ xfs_buf_item_format(
                 * cancel flag in it.
                 */
                trace_xfs_buf_item_format_stale(bip);
-               ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
-               bip->bli_format.blf_size = nvecs;
-               return;
+               ASSERT(blfp->blf_flags & XFS_BLF_CANCEL);
+               blfp->blf_size = nvecs;
+               return vecp;
        }
 
        /*
         * Fill in an iovec for each set of contiguous chunks.
         */
-       first_bit = xfs_next_bit(bip->bli_format.blf_data_map,
-                                        bip->bli_format.blf_map_size, 0);
+       first_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0);
        ASSERT(first_bit != -1);
        last_bit = first_bit;
        nbits = 1;
@@ -296,9 +319,8 @@ xfs_buf_item_format(
                 * if there are no more bits set or the start bit is
                 * beyond the end of the bitmap.
                 */
-               next_bit = xfs_next_bit(bip->bli_format.blf_data_map,
-                                                bip->bli_format.blf_map_size,
-                                                (uint)last_bit + 1);
+               next_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size,
+                                       (uint)last_bit + 1);
                /*
                 * If we run out of bits fill in the last iovec and get
                 * out of the loop.
@@ -309,14 +331,14 @@ xfs_buf_item_format(
                 * keep counting and scanning.
                 */
                if (next_bit == -1) {
-                       buffer_offset = first_bit * XFS_BLF_CHUNK;
+                       buffer_offset = offset + first_bit * XFS_BLF_CHUNK;
                        vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
                        vecp->i_len = nbits * XFS_BLF_CHUNK;
                        vecp->i_type = XLOG_REG_TYPE_BCHUNK;
                        nvecs++;
                        break;
                } else if (next_bit != last_bit + 1) {
-                       buffer_offset = first_bit * XFS_BLF_CHUNK;
+                       buffer_offset = offset + first_bit * XFS_BLF_CHUNK;
                        vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
                        vecp->i_len = nbits * XFS_BLF_CHUNK;
                        vecp->i_type = XLOG_REG_TYPE_BCHUNK;
@@ -325,14 +347,17 @@ xfs_buf_item_format(
                        first_bit = next_bit;
                        last_bit = next_bit;
                        nbits = 1;
-               } else if (xfs_buf_offset(bp, next_bit << XFS_BLF_SHIFT) !=
-                          (xfs_buf_offset(bp, last_bit << XFS_BLF_SHIFT) +
+               } else if (xfs_buf_offset(bp, offset +
+                                             (next_bit << XFS_BLF_SHIFT)) !=
+                          (xfs_buf_offset(bp, offset +
+                                              (last_bit << XFS_BLF_SHIFT)) +
                            XFS_BLF_CHUNK)) {
-                       buffer_offset = first_bit * XFS_BLF_CHUNK;
+                       buffer_offset = offset + first_bit * XFS_BLF_CHUNK;
                        vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
                        vecp->i_len = nbits * XFS_BLF_CHUNK;
                        vecp->i_type = XLOG_REG_TYPE_BCHUNK;
-/* You would think we need to bump the nvecs here too, but we do not
+/*
+ * You would think we need to bump the nvecs here too, but we do not
  * this number is used by recovery, and it gets confused by the boundary
  * split here
  *                     nvecs++;
@@ -347,6 +372,48 @@ xfs_buf_item_format(
                }
        }
        bip->bli_format.blf_size = nvecs;
+       return vecp;
+}
+
+/*
+ * This is called to fill in the vector of log iovecs for the
+ * given log buf item.  It fills the first entry with a buf log
+ * format structure, and the rest point to contiguous chunks
+ * within the buffer.
+ */
+STATIC void
+xfs_buf_item_format(
+       struct xfs_log_item     *lip,
+       struct xfs_log_iovec    *vecp)
+{
+       struct xfs_buf_log_item *bip = BUF_ITEM(lip);
+       struct xfs_buf          *bp = bip->bli_buf;
+       uint                    offset = 0;
+       int                     i;
+
+       ASSERT(atomic_read(&bip->bli_refcount) > 0);
+       ASSERT((bip->bli_flags & XFS_BLI_LOGGED) ||
+              (bip->bli_flags & XFS_BLI_STALE));
+
+       /*
+        * If it is an inode buffer, transfer the in-memory state to the
+        * format flags and clear the in-memory state. We do not transfer
+        * this state if the inode buffer allocation has not yet been committed
+        * to the log as setting the XFS_BLI_INODE_BUF flag will prevent
+        * correct replay of the inode allocation.
+        */
+       if (bip->bli_flags & XFS_BLI_INODE_BUF) {
+               if (!((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) &&
+                     xfs_log_item_in_current_chkpt(lip)))
+                       bip->bli_format.blf_flags |= XFS_BLF_INODE_BUF;
+               bip->bli_flags &= ~XFS_BLI_INODE_BUF;
+       }
+
+       for (i = 0; i < bip->bli_format_count; i++) {
+               vecp = xfs_buf_item_format_segment(bip, vecp, offset,
+                                               &bip->bli_formats[i]);
+               offset += bp->b_maps[i].bm_len;
+       }
 
        /*
         * Check to make sure everything is consistent.
@@ -622,6 +689,35 @@ static const struct xfs_item_ops xfs_buf_item_ops = {
        .iop_committing = xfs_buf_item_committing
 };
 
+STATIC int
+xfs_buf_item_get_format(
+       struct xfs_buf_log_item *bip,
+       int                     count)
+{
+       ASSERT(bip->bli_formats == NULL);
+       bip->bli_format_count = count;
+
+       if (count == 1) {
+               bip->bli_formats = &bip->bli_format;
+               return 0;
+       }
+
+       bip->bli_formats = kmem_zalloc(count * sizeof(struct xfs_buf_log_format),
+                               KM_SLEEP);
+       if (!bip->bli_formats)
+               return ENOMEM;
+       return 0;
+}
+
+STATIC void
+xfs_buf_item_free_format(
+       struct xfs_buf_log_item *bip)
+{
+       if (bip->bli_formats != &bip->bli_format) {
+               kmem_free(bip->bli_formats);
+               bip->bli_formats = NULL;
+       }
+}
 
 /*
  * Allocate a new buf log item to go with the given buffer.
@@ -639,6 +735,8 @@ xfs_buf_item_init(
        xfs_buf_log_item_t      *bip;
        int                     chunks;
        int                     map_size;
+       int                     error;
+       int                     i;
 
        /*
         * Check to see if there is already a buf log item for
@@ -650,25 +748,33 @@ xfs_buf_item_init(
        if (lip != NULL && lip->li_type == XFS_LI_BUF)
                return;
 
-       /*
-        * chunks is the number of XFS_BLF_CHUNK size pieces
-        * the buffer can be divided into. Make sure not to
-        * truncate any pieces.  map_size is the size of the
-        * bitmap needed to describe the chunks of the buffer.
-        */
-       chunks = (int)((BBTOB(bp->b_length) + (XFS_BLF_CHUNK - 1)) >>
-                                                               XFS_BLF_SHIFT);
-       map_size = (int)((chunks + NBWORD) >> BIT_TO_WORD_SHIFT);
-
-       bip = (xfs_buf_log_item_t*)kmem_zone_zalloc(xfs_buf_item_zone,
-                                                   KM_SLEEP);
+       bip = kmem_zone_zalloc(xfs_buf_item_zone, KM_SLEEP);
        xfs_log_item_init(mp, &bip->bli_item, XFS_LI_BUF, &xfs_buf_item_ops);
        bip->bli_buf = bp;
        xfs_buf_hold(bp);
-       bip->bli_format.blf_type = XFS_LI_BUF;
-       bip->bli_format.blf_blkno = (__int64_t)XFS_BUF_ADDR(bp);
-       bip->bli_format.blf_len = (ushort)bp->b_length;
-       bip->bli_format.blf_map_size = map_size;
+
+       /*
+        * chunks is the number of XFS_BLF_CHUNK size pieces the buffer
+        * can be divided into. Make sure not to truncate any pieces.
+        * map_size is the size of the bitmap needed to describe the
+        * chunks of the buffer.
+        *
+        * Discontiguous buffer support follows the layout of the underlying
+        * buffer. This makes the implementation as simple as possible.
+        */
+       error = xfs_buf_item_get_format(bip, bp->b_map_count);
+       ASSERT(error == 0);
+
+       for (i = 0; i < bip->bli_format_count; i++) {
+               chunks = DIV_ROUND_UP(BBTOB(bp->b_maps[i].bm_len),
+                                     XFS_BLF_CHUNK);
+               map_size = DIV_ROUND_UP(chunks, NBWORD);
+
+               bip->bli_formats[i].blf_type = XFS_LI_BUF;
+               bip->bli_formats[i].blf_blkno = bp->b_maps[i].bm_bn;
+               bip->bli_formats[i].blf_len = bp->b_maps[i].bm_len;
+               bip->bli_formats[i].blf_map_size = map_size;
+       }
 
 #ifdef XFS_TRANS_DEBUG
        /*
@@ -699,10 +805,11 @@ xfs_buf_item_init(
  * item's bitmap.
  */
 void
-xfs_buf_item_log(
-       xfs_buf_log_item_t      *bip,
+xfs_buf_item_log_segment(
+       struct xfs_buf_log_item *bip,
        uint                    first,
-       uint                    last)
+       uint                    last,
+       uint                    *map)
 {
        uint            first_bit;
        uint            last_bit;
@@ -714,12 +821,6 @@ xfs_buf_item_log(
        uint            end_bit;
        uint            mask;
 
-       /*
-        * Mark the item as having some dirty data for
-        * quick reference in xfs_buf_item_dirty.
-        */
-       bip->bli_flags |= XFS_BLI_DIRTY;
-
        /*
         * Convert byte offsets to bit numbers.
         */
@@ -736,7 +837,7 @@ xfs_buf_item_log(
         * to set a bit in.
         */
        word_num = first_bit >> BIT_TO_WORD_SHIFT;
-       wordp = &(bip->bli_format.blf_data_map[word_num]);
+       wordp = &map[word_num];
 
        /*
         * Calculate the starting bit in the first word.
@@ -783,6 +884,51 @@ xfs_buf_item_log(
        xfs_buf_item_log_debug(bip, first, last);
 }
 
+/*
+ * Mark bytes first through last inclusive as dirty in the buf
+ * item's bitmap.
+ */
+void
+xfs_buf_item_log(
+       xfs_buf_log_item_t      *bip,
+       uint                    first,
+       uint                    last)
+{
+       int                     i;
+       uint                    start;
+       uint                    end;
+       struct xfs_buf          *bp = bip->bli_buf;
+
+       /*
+        * Mark the item as having some dirty data for
+        * quick reference in xfs_buf_item_dirty.
+        */
+       bip->bli_flags |= XFS_BLI_DIRTY;
+
+       /*
+        * walk each buffer segment and mark them dirty appropriately.
+        */
+       start = 0;
+       for (i = 0; i < bip->bli_format_count; i++) {
+               if (start > last)
+                       break;
+               end = start + BBTOB(bp->b_maps[i].bm_len);
+               if (first > end) {
+                       start += BBTOB(bp->b_maps[i].bm_len);
+                       continue;
+               }
+               if (first < start)
+                       first = start;
+               if (end > last)
+                       end = last;
+
+               xfs_buf_item_log_segment(bip, first, end,
+                                        &bip->bli_formats[i].blf_data_map[0]);
+
+               start += bp->b_maps[i].bm_len;
+       }
+}
+
 
 /*
  * Return 1 if the buffer has some data that has been logged (at any
@@ -804,6 +950,7 @@ xfs_buf_item_free(
        kmem_free(bip->bli_logged);
 #endif /* XFS_TRANS_DEBUG */
 
+       xfs_buf_item_free_format(bip);
        kmem_zone_free(xfs_buf_item_zone, bip);
 }
 
index b6ecd2061e7cd292b0f1c4447b13b91c65b1fa86..6850f49f4af3f60c0a5a8ef9508f7bac9af00e4c 100644 (file)
 
 extern kmem_zone_t     *xfs_buf_item_zone;
 
-/*
- * This is the structure used to lay out a buf log item in the
- * log.  The data map describes which 128 byte chunks of the buffer
- * have been logged.
- * For 6.2 and beyond, this is XFS_LI_BUF.  We use this to log everything.
- */
-typedef struct xfs_buf_log_format {
-       unsigned short  blf_type;       /* buf log item type indicator */
-       unsigned short  blf_size;       /* size of this item */
-       ushort          blf_flags;      /* misc state */
-       ushort          blf_len;        /* number of blocks in this buf */
-       __int64_t       blf_blkno;      /* starting blkno of this buf */
-       unsigned int    blf_map_size;   /* size of data bitmap in words */
-       unsigned int    blf_data_map[1];/* variable size bitmap of */
-                                       /*   regions of buffer in this item */
-} xfs_buf_log_format_t;
-
 /*
  * This flag indicates that the buffer contains on disk inodes
  * and requires special recovery handling.
@@ -60,6 +43,23 @@ typedef struct xfs_buf_log_format {
 #define        BIT_TO_WORD_SHIFT       5
 #define        NBWORD                  (NBBY * sizeof(unsigned int))
 
+/*
+ * This is the structure used to lay out a buf log item in the
+ * log.  The data map describes which 128 byte chunks of the buffer
+ * have been logged.
+ */
+#define XFS_BLF_DATAMAP_SIZE   ((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) / NBWORD)
+
+typedef struct xfs_buf_log_format {
+       unsigned short  blf_type;       /* buf log item type indicator */
+       unsigned short  blf_size;       /* size of this item */
+       ushort          blf_flags;      /* misc state */
+       ushort          blf_len;        /* number of blocks in this buf */
+       __int64_t       blf_blkno;      /* starting blkno of this buf */
+       unsigned int    blf_map_size;   /* used size of data bitmap in words */
+       unsigned int    blf_data_map[XFS_BLF_DATAMAP_SIZE]; /* dirty bitmap */
+} xfs_buf_log_format_t;
+
 /*
  * buf log item flags
  */
@@ -102,7 +102,9 @@ typedef struct xfs_buf_log_item {
        char                    *bli_orig;      /* original buffer copy */
        char                    *bli_logged;    /* bytes logged (bitmap) */
 #endif
-       xfs_buf_log_format_t    bli_format;     /* in-log header */
+       int                     bli_format_count;       /* count of headers */
+       struct xfs_buf_log_format *bli_formats; /* array of in-log header ptrs */
+       struct xfs_buf_log_format bli_format;   /* embedded in-log header */
 } xfs_buf_log_item_t;
 
 void   xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *);
index 015b946c58081acb34e7ce49438debd5dced4aab..7bfb7dd334fc0442204ce6e483f1fc5ba4dee65f 100644 (file)
@@ -83,9 +83,9 @@ STATIC void xfs_da_node_unbalance(xfs_da_state_t *state,
 /*
  * Utility routines.
  */
-STATIC uint    xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count);
-STATIC int     xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp);
-STATIC xfs_dabuf_t *xfs_da_buf_make(int nbuf, xfs_buf_t **bps);
+STATIC uint    xfs_da_node_lasthash(struct xfs_buf *bp, int *count);
+STATIC int     xfs_da_node_order(struct xfs_buf *node1_bp,
+                                 struct xfs_buf *node2_bp);
 STATIC int     xfs_da_blk_unlink(xfs_da_state_t *state,
                                  xfs_da_state_blk_t *drop_blk,
                                  xfs_da_state_blk_t *save_blk);
@@ -100,10 +100,10 @@ STATIC void       xfs_da_state_kill_altpath(xfs_da_state_t *state);
  */
 int
 xfs_da_node_create(xfs_da_args_t *args, xfs_dablk_t blkno, int level,
-                                xfs_dabuf_t **bpp, int whichfork)
+                                struct xfs_buf **bpp, int whichfork)
 {
        xfs_da_intnode_t *node;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int error;
        xfs_trans_t *tp;
 
@@ -114,7 +114,7 @@ xfs_da_node_create(xfs_da_args_t *args, xfs_dablk_t blkno, int level,
        if (error)
                return(error);
        ASSERT(bp != NULL);
-       node = bp->data;
+       node = bp->b_addr;
        node->hdr.info.forw = 0;
        node->hdr.info.back = 0;
        node->hdr.info.magic = cpu_to_be16(XFS_DA_NODE_MAGIC);
@@ -122,7 +122,7 @@ xfs_da_node_create(xfs_da_args_t *args, xfs_dablk_t blkno, int level,
        node->hdr.count = 0;
        node->hdr.level = cpu_to_be16(level);
 
-       xfs_da_log_buf(tp, bp,
+       xfs_trans_log_buf(tp, bp,
                XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr)));
 
        *bpp = bp;
@@ -138,7 +138,7 @@ xfs_da_split(xfs_da_state_t *state)
 {
        xfs_da_state_blk_t *oldblk, *newblk, *addblk;
        xfs_da_intnode_t *node;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int max, action, error, i;
 
        trace_xfs_da_split(state->args);
@@ -203,7 +203,6 @@ xfs_da_split(xfs_da_state_t *state)
                case XFS_DA_NODE_MAGIC:
                        error = xfs_da_node_split(state, oldblk, newblk, addblk,
                                                         max - i, &action);
-                       xfs_da_buf_done(addblk->bp);
                        addblk->bp = NULL;
                        if (error)
                                return(error);  /* GROT: dir is inconsistent */
@@ -221,13 +220,6 @@ xfs_da_split(xfs_da_state_t *state)
                 * Update the btree to show the new hashval for this child.
                 */
                xfs_da_fixhashpath(state, &state->path);
-               /*
-                * If we won't need this block again, it's getting dropped
-                * from the active path by the loop control, so we need
-                * to mark it done now.
-                */
-               if (i > 0 || !addblk)
-                       xfs_da_buf_done(oldblk->bp);
        }
        if (!addblk)
                return(0);
@@ -239,8 +231,6 @@ xfs_da_split(xfs_da_state_t *state)
        oldblk = &state->path.blk[0];
        error = xfs_da_root_split(state, oldblk, addblk);
        if (error) {
-               xfs_da_buf_done(oldblk->bp);
-               xfs_da_buf_done(addblk->bp);
                addblk->bp = NULL;
                return(error);  /* GROT: dir is inconsistent */
        }
@@ -252,7 +242,7 @@ xfs_da_split(xfs_da_state_t *state)
         * and the original block 0 could be at any position in the list.
         */
 
-       node = oldblk->bp->data;
+       node = oldblk->bp->b_addr;
        if (node->hdr.info.forw) {
                if (be32_to_cpu(node->hdr.info.forw) == addblk->blkno) {
                        bp = addblk->bp;
@@ -260,13 +250,13 @@ xfs_da_split(xfs_da_state_t *state)
                        ASSERT(state->extravalid);
                        bp = state->extrablk.bp;
                }
-               node = bp->data;
+               node = bp->b_addr;
                node->hdr.info.back = cpu_to_be32(oldblk->blkno);
-               xfs_da_log_buf(state->args->trans, bp,
+               xfs_trans_log_buf(state->args->trans, bp,
                    XFS_DA_LOGRANGE(node, &node->hdr.info,
                    sizeof(node->hdr.info)));
        }
-       node = oldblk->bp->data;
+       node = oldblk->bp->b_addr;
        if (node->hdr.info.back) {
                if (be32_to_cpu(node->hdr.info.back) == addblk->blkno) {
                        bp = addblk->bp;
@@ -274,14 +264,12 @@ xfs_da_split(xfs_da_state_t *state)
                        ASSERT(state->extravalid);
                        bp = state->extrablk.bp;
                }
-               node = bp->data;
+               node = bp->b_addr;
                node->hdr.info.forw = cpu_to_be32(oldblk->blkno);
-               xfs_da_log_buf(state->args->trans, bp,
+               xfs_trans_log_buf(state->args->trans, bp,
                    XFS_DA_LOGRANGE(node, &node->hdr.info,
                    sizeof(node->hdr.info)));
        }
-       xfs_da_buf_done(oldblk->bp);
-       xfs_da_buf_done(addblk->bp);
        addblk->bp = NULL;
        return(0);
 }
@@ -298,7 +286,7 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
        xfs_da_intnode_t *node, *oldroot;
        xfs_da_args_t *args;
        xfs_dablk_t blkno;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int error, size;
        xfs_inode_t *dp;
        xfs_trans_t *tp;
@@ -323,8 +311,8 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
        if (error)
                return(error);
        ASSERT(bp != NULL);
-       node = bp->data;
-       oldroot = blk1->bp->data;
+       node = bp->b_addr;
+       oldroot = blk1->bp->b_addr;
        if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC)) {
                size = (int)((char *)&oldroot->btree[be16_to_cpu(oldroot->hdr.count)] -
                             (char *)oldroot);
@@ -335,8 +323,7 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
                             (char *)leaf);
        }
        memcpy(node, oldroot, size);
-       xfs_da_log_buf(tp, bp, 0, size - 1);
-       xfs_da_buf_done(blk1->bp);
+       xfs_trans_log_buf(tp, bp, 0, size - 1);
        blk1->bp = bp;
        blk1->blkno = blkno;
 
@@ -348,7 +335,7 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
                be16_to_cpu(node->hdr.level) + 1, &bp, args->whichfork);
        if (error)
                return(error);
-       node = bp->data;
+       node = bp->b_addr;
        node->btree[0].hashval = cpu_to_be32(blk1->hashval);
        node->btree[0].before = cpu_to_be32(blk1->blkno);
        node->btree[1].hashval = cpu_to_be32(blk2->hashval);
@@ -365,10 +352,9 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
 #endif
 
        /* Header is already logged by xfs_da_node_create */
-       xfs_da_log_buf(tp, bp,
+       xfs_trans_log_buf(tp, bp,
                XFS_DA_LOGRANGE(node, node->btree,
                        sizeof(xfs_da_node_entry_t) * 2));
-       xfs_da_buf_done(bp);
 
        return(0);
 }
@@ -389,7 +375,7 @@ xfs_da_node_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
 
        trace_xfs_da_node_split(state->args);
 
-       node = oldblk->bp->data;
+       node = oldblk->bp->b_addr;
        ASSERT(node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
 
        /*
@@ -436,7 +422,7 @@ xfs_da_node_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
         *
         * If we had double-split op below us, then add the extra block too.
         */
-       node = oldblk->bp->data;
+       node = oldblk->bp->b_addr;
        if (oldblk->index <= be16_to_cpu(node->hdr.count)) {
                oldblk->index++;
                xfs_da_node_add(state, oldblk, addblk);
@@ -477,8 +463,8 @@ xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
 
        trace_xfs_da_node_rebalance(state->args);
 
-       node1 = blk1->bp->data;
-       node2 = blk2->bp->data;
+       node1 = blk1->bp->b_addr;
+       node2 = blk2->bp->b_addr;
        /*
         * Figure out how many entries need to move, and in which direction.
         * Swap the nodes around if that makes it simpler.
@@ -532,7 +518,7 @@ xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
                btree_d = &node1->btree[be16_to_cpu(node1->hdr.count)];
                memcpy(btree_d, btree_s, tmp);
                be16_add_cpu(&node1->hdr.count, count);
-               xfs_da_log_buf(tp, blk1->bp,
+               xfs_trans_log_buf(tp, blk1->bp,
                        XFS_DA_LOGRANGE(node1, btree_d, tmp));
 
                /*
@@ -549,9 +535,9 @@ xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
        /*
         * Log header of node 1 and all current bits of node 2.
         */
-       xfs_da_log_buf(tp, blk1->bp,
+       xfs_trans_log_buf(tp, blk1->bp,
                XFS_DA_LOGRANGE(node1, &node1->hdr, sizeof(node1->hdr)));
-       xfs_da_log_buf(tp, blk2->bp,
+       xfs_trans_log_buf(tp, blk2->bp,
                XFS_DA_LOGRANGE(node2, &node2->hdr,
                        sizeof(node2->hdr) +
                        sizeof(node2->btree[0]) * be16_to_cpu(node2->hdr.count)));
@@ -560,8 +546,8 @@ xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
         * Record the last hashval from each block for upward propagation.
         * (note: don't use the swapped node pointers)
         */
-       node1 = blk1->bp->data;
-       node2 = blk2->bp->data;
+       node1 = blk1->bp->b_addr;
+       node2 = blk2->bp->b_addr;
        blk1->hashval = be32_to_cpu(node1->btree[be16_to_cpu(node1->hdr.count)-1].hashval);
        blk2->hashval = be32_to_cpu(node2->btree[be16_to_cpu(node2->hdr.count)-1].hashval);
 
@@ -587,7 +573,7 @@ xfs_da_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
 
        trace_xfs_da_node_add(state->args);
 
-       node = oldblk->bp->data;
+       node = oldblk->bp->b_addr;
        ASSERT(node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
        ASSERT((oldblk->index >= 0) && (oldblk->index <= be16_to_cpu(node->hdr.count)));
        ASSERT(newblk->blkno != 0);
@@ -606,10 +592,10 @@ xfs_da_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
        }
        btree->hashval = cpu_to_be32(newblk->hashval);
        btree->before = cpu_to_be32(newblk->blkno);
-       xfs_da_log_buf(state->args->trans, oldblk->bp,
+       xfs_trans_log_buf(state->args->trans, oldblk->bp,
                XFS_DA_LOGRANGE(node, btree, tmp + sizeof(*btree)));
        be16_add_cpu(&node->hdr.count, 1);
-       xfs_da_log_buf(state->args->trans, oldblk->bp,
+       xfs_trans_log_buf(state->args->trans, oldblk->bp,
                XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr)));
 
        /*
@@ -735,7 +721,7 @@ xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk)
        xfs_da_intnode_t *oldroot;
        xfs_da_args_t *args;
        xfs_dablk_t child;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int error;
 
        trace_xfs_da_root_join(state->args);
@@ -743,7 +729,7 @@ xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk)
        args = state->args;
        ASSERT(args != NULL);
        ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC);
-       oldroot = root_blk->bp->data;
+       oldroot = root_blk->bp->b_addr;
        ASSERT(oldroot->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
        ASSERT(!oldroot->hdr.info.forw);
        ASSERT(!oldroot->hdr.info.back);
@@ -765,11 +751,11 @@ xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk)
        if (error)
                return(error);
        ASSERT(bp != NULL);
-       xfs_da_blkinfo_onlychild_validate(bp->data,
+       xfs_da_blkinfo_onlychild_validate(bp->b_addr,
                                        be16_to_cpu(oldroot->hdr.level));
 
-       memcpy(root_blk->bp->data, bp->data, state->blocksize);
-       xfs_da_log_buf(args->trans, root_blk->bp, 0, state->blocksize - 1);
+       memcpy(root_blk->bp->b_addr, bp->b_addr, state->blocksize);
+       xfs_trans_log_buf(args->trans, root_blk->bp, 0, state->blocksize - 1);
        error = xfs_da_shrink_inode(args, child, bp);
        return(error);
 }
@@ -791,7 +777,7 @@ xfs_da_node_toosmall(xfs_da_state_t *state, int *action)
        xfs_da_blkinfo_t *info;
        int count, forward, error, retval, i;
        xfs_dablk_t blkno;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
 
        /*
         * Check for the degenerate case of the block being over 50% full.
@@ -799,7 +785,7 @@ xfs_da_node_toosmall(xfs_da_state_t *state, int *action)
         * to coalesce with a sibling.
         */
        blk = &state->path.blk[ state->path.active-1 ];
-       info = blk->bp->data;
+       info = blk->bp->b_addr;
        ASSERT(info->magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
        node = (xfs_da_intnode_t *)info;
        count = be16_to_cpu(node->hdr.count);
@@ -859,10 +845,10 @@ xfs_da_node_toosmall(xfs_da_state_t *state, int *action)
                count  = state->node_ents;
                count -= state->node_ents >> 2;
                count -= be16_to_cpu(node->hdr.count);
-               node = bp->data;
+               node = bp->b_addr;
                ASSERT(node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
                count -= be16_to_cpu(node->hdr.count);
-               xfs_da_brelse(state->args->trans, bp);
+               xfs_trans_brelse(state->args->trans, bp);
                if (count >= 0)
                        break;  /* fits with at least 25% to spare */
        }
@@ -934,14 +920,14 @@ xfs_da_fixhashpath(xfs_da_state_t *state, xfs_da_state_path_t *path)
                break;
        }
        for (blk--, level--; level >= 0; blk--, level--) {
-               node = blk->bp->data;
+               node = blk->bp->b_addr;
                ASSERT(node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
                btree = &node->btree[ blk->index ];
                if (be32_to_cpu(btree->hashval) == lasthash)
                        break;
                blk->hashval = lasthash;
                btree->hashval = cpu_to_be32(lasthash);
-               xfs_da_log_buf(state->args->trans, blk->bp,
+               xfs_trans_log_buf(state->args->trans, blk->bp,
                                  XFS_DA_LOGRANGE(node, btree, sizeof(*btree)));
 
                lasthash = be32_to_cpu(node->btree[be16_to_cpu(node->hdr.count)-1].hashval);
@@ -960,7 +946,7 @@ xfs_da_node_remove(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk)
 
        trace_xfs_da_node_remove(state->args);
 
-       node = drop_blk->bp->data;
+       node = drop_blk->bp->b_addr;
        ASSERT(drop_blk->index < be16_to_cpu(node->hdr.count));
        ASSERT(drop_blk->index >= 0);
 
@@ -972,15 +958,15 @@ xfs_da_node_remove(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk)
                tmp  = be16_to_cpu(node->hdr.count) - drop_blk->index - 1;
                tmp *= (uint)sizeof(xfs_da_node_entry_t);
                memmove(btree, btree + 1, tmp);
-               xfs_da_log_buf(state->args->trans, drop_blk->bp,
+               xfs_trans_log_buf(state->args->trans, drop_blk->bp,
                    XFS_DA_LOGRANGE(node, btree, tmp));
                btree = &node->btree[be16_to_cpu(node->hdr.count)-1];
        }
        memset((char *)btree, 0, sizeof(xfs_da_node_entry_t));
-       xfs_da_log_buf(state->args->trans, drop_blk->bp,
+       xfs_trans_log_buf(state->args->trans, drop_blk->bp,
            XFS_DA_LOGRANGE(node, btree, sizeof(*btree)));
        be16_add_cpu(&node->hdr.count, -1);
-       xfs_da_log_buf(state->args->trans, drop_blk->bp,
+       xfs_trans_log_buf(state->args->trans, drop_blk->bp,
            XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr)));
 
        /*
@@ -1005,8 +991,8 @@ xfs_da_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
 
        trace_xfs_da_node_unbalance(state->args);
 
-       drop_node = drop_blk->bp->data;
-       save_node = save_blk->bp->data;
+       drop_node = drop_blk->bp->b_addr;
+       save_node = save_blk->bp->b_addr;
        ASSERT(drop_node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
        ASSERT(save_node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
        tp = state->args->trans;
@@ -1023,13 +1009,13 @@ xfs_da_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
                tmp = be16_to_cpu(save_node->hdr.count) * (uint)sizeof(xfs_da_node_entry_t);
                memmove(btree, &save_node->btree[0], tmp);
                btree = &save_node->btree[0];
-               xfs_da_log_buf(tp, save_blk->bp,
+               xfs_trans_log_buf(tp, save_blk->bp,
                        XFS_DA_LOGRANGE(save_node, btree,
                                (be16_to_cpu(save_node->hdr.count) + be16_to_cpu(drop_node->hdr.count)) *
                                sizeof(xfs_da_node_entry_t)));
        } else {
                btree = &save_node->btree[be16_to_cpu(save_node->hdr.count)];
-               xfs_da_log_buf(tp, save_blk->bp,
+               xfs_trans_log_buf(tp, save_blk->bp,
                        XFS_DA_LOGRANGE(save_node, btree,
                                be16_to_cpu(drop_node->hdr.count) *
                                sizeof(xfs_da_node_entry_t)));
@@ -1042,7 +1028,7 @@ xfs_da_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
        memcpy(btree, &drop_node->btree[0], tmp);
        be16_add_cpu(&save_node->hdr.count, be16_to_cpu(drop_node->hdr.count));
 
-       xfs_da_log_buf(tp, save_blk->bp,
+       xfs_trans_log_buf(tp, save_blk->bp,
                XFS_DA_LOGRANGE(save_node, &save_node->hdr,
                        sizeof(save_node->hdr)));
 
@@ -1100,7 +1086,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
                        state->path.active--;
                        return(error);
                }
-               curr = blk->bp->data;
+               curr = blk->bp->b_addr;
                blk->magic = be16_to_cpu(curr->magic);
                ASSERT(blk->magic == XFS_DA_NODE_MAGIC ||
                       blk->magic == XFS_DIR2_LEAFN_MAGIC ||
@@ -1110,7 +1096,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
                 * Search an intermediate node for a match.
                 */
                if (blk->magic == XFS_DA_NODE_MAGIC) {
-                       node = blk->bp->data;
+                       node = blk->bp->b_addr;
                        max = be16_to_cpu(node->hdr.count);
                        blk->hashval = be32_to_cpu(node->btree[max-1].hashval);
 
@@ -1216,15 +1202,15 @@ xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk,
        xfs_da_blkinfo_t *old_info, *new_info, *tmp_info;
        xfs_da_args_t *args;
        int before=0, error;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
 
        /*
         * Set up environment.
         */
        args = state->args;
        ASSERT(args != NULL);
-       old_info = old_blk->bp->data;
-       new_info = new_blk->bp->data;
+       old_info = old_blk->bp->b_addr;
+       new_info = new_blk->bp->b_addr;
        ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC ||
               old_blk->magic == XFS_DIR2_LEAFN_MAGIC ||
               old_blk->magic == XFS_ATTR_LEAF_MAGIC);
@@ -1261,12 +1247,11 @@ xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk,
                        if (error)
                                return(error);
                        ASSERT(bp != NULL);
-                       tmp_info = bp->data;
+                       tmp_info = bp->b_addr;
                        ASSERT(be16_to_cpu(tmp_info->magic) == be16_to_cpu(old_info->magic));
                        ASSERT(be32_to_cpu(tmp_info->forw) == old_blk->blkno);
                        tmp_info->forw = cpu_to_be32(new_blk->blkno);
-                       xfs_da_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1);
-                       xfs_da_buf_done(bp);
+                       xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1);
                }
                old_info->back = cpu_to_be32(new_blk->blkno);
        } else {
@@ -1283,18 +1268,17 @@ xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk,
                        if (error)
                                return(error);
                        ASSERT(bp != NULL);
-                       tmp_info = bp->data;
+                       tmp_info = bp->b_addr;
                        ASSERT(tmp_info->magic == old_info->magic);
                        ASSERT(be32_to_cpu(tmp_info->back) == old_blk->blkno);
                        tmp_info->back = cpu_to_be32(new_blk->blkno);
-                       xfs_da_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1);
-                       xfs_da_buf_done(bp);
+                       xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1);
                }
                old_info->forw = cpu_to_be32(new_blk->blkno);
        }
 
-       xfs_da_log_buf(args->trans, old_blk->bp, 0, sizeof(*tmp_info) - 1);
-       xfs_da_log_buf(args->trans, new_blk->bp, 0, sizeof(*tmp_info) - 1);
+       xfs_trans_log_buf(args->trans, old_blk->bp, 0, sizeof(*tmp_info) - 1);
+       xfs_trans_log_buf(args->trans, new_blk->bp, 0, sizeof(*tmp_info) - 1);
        return(0);
 }
 
@@ -1302,12 +1286,14 @@ xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk,
  * Compare two intermediate nodes for "order".
  */
 STATIC int
-xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp)
+xfs_da_node_order(
+       struct xfs_buf  *node1_bp,
+       struct xfs_buf  *node2_bp)
 {
        xfs_da_intnode_t *node1, *node2;
 
-       node1 = node1_bp->data;
-       node2 = node2_bp->data;
+       node1 = node1_bp->b_addr;
+       node2 = node2_bp->b_addr;
        ASSERT(node1->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC) &&
               node2->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
        if ((be16_to_cpu(node1->hdr.count) > 0) && (be16_to_cpu(node2->hdr.count) > 0) &&
@@ -1324,11 +1310,13 @@ xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp)
  * Pick up the last hashvalue from an intermediate node.
  */
 STATIC uint
-xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count)
+xfs_da_node_lasthash(
+       struct xfs_buf  *bp,
+       int             *count)
 {
        xfs_da_intnode_t *node;
 
-       node = bp->data;
+       node = bp->b_addr;
        ASSERT(node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
        if (count)
                *count = be16_to_cpu(node->hdr.count);
@@ -1346,7 +1334,7 @@ xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
 {
        xfs_da_blkinfo_t *drop_info, *save_info, *tmp_info;
        xfs_da_args_t *args;
-       xfs_dabuf_t *bp;
+       struct xfs_buf *bp;
        int error;
 
        /*
@@ -1354,8 +1342,8 @@ xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
         */
        args = state->args;
        ASSERT(args != NULL);
-       save_info = save_blk->bp->data;
-       drop_info = drop_blk->bp->data;
+       save_info = save_blk->bp->b_addr;
+       drop_info = drop_blk->bp->b_addr;
        ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC ||
               save_blk->magic == XFS_DIR2_LEAFN_MAGIC ||
               save_blk->magic == XFS_ATTR_LEAF_MAGIC);
@@ -1380,13 +1368,12 @@ xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
                        if (error)
                                return(error);
                        ASSERT(bp != NULL);
-                       tmp_info = bp->data;
+                       tmp_info = bp->b_addr;
                        ASSERT(tmp_info->magic == save_info->magic);
                        ASSERT(be32_to_cpu(tmp_info->forw) == drop_blk->blkno);
                        tmp_info->forw = cpu_to_be32(save_blk->blkno);
-                       xfs_da_log_buf(args->trans, bp, 0,
+                       xfs_trans_log_buf(args->trans, bp, 0,
                                                    sizeof(*tmp_info) - 1);
-                       xfs_da_buf_done(bp);
                }
        } else {
                trace_xfs_da_unlink_forward(args);
@@ -1398,17 +1385,16 @@ xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
                        if (error)
                                return(error);
                        ASSERT(bp != NULL);
-                       tmp_info = bp->data;
+                       tmp_info = bp->b_addr;
                        ASSERT(tmp_info->magic == save_info->magic);
                        ASSERT(be32_to_cpu(tmp_info->back) == drop_blk->blkno);
                        tmp_info->back = cpu_to_be32(save_blk->blkno);
-                       xfs_da_log_buf(args->trans, bp, 0,
+                       xfs_trans_log_buf(args->trans, bp, 0,
                                                    sizeof(*tmp_info) - 1);
-                       xfs_da_buf_done(bp);
                }
        }
 
-       xfs_da_log_buf(args->trans, save_blk->bp, 0, sizeof(*save_info) - 1);
+       xfs_trans_log_buf(args->trans, save_blk->bp, 0, sizeof(*save_info) - 1);
        return(0);
 }
 
@@ -1443,7 +1429,7 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,
        level = (path->active-1) - 1;   /* skip bottom layer in path */
        for (blk = &path->blk[level]; level >= 0; blk--, level--) {
                ASSERT(blk->bp != NULL);
-               node = blk->bp->data;
+               node = blk->bp->b_addr;
                ASSERT(node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
                if (forward && (blk->index < be16_to_cpu(node->hdr.count)-1)) {
                        blk->index++;
@@ -1471,7 +1457,7 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,
                 * (if it's dirty, trans won't actually let go)
                 */
                if (release)
-                       xfs_da_brelse(args->trans, blk->bp);
+                       xfs_trans_brelse(args->trans, blk->bp);
 
                /*
                 * Read the next child block.
@@ -1482,7 +1468,7 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,
                if (error)
                        return(error);
                ASSERT(blk->bp != NULL);
-               info = blk->bp->data;
+               info = blk->bp->b_addr;
                ASSERT(info->magic == cpu_to_be16(XFS_DA_NODE_MAGIC) ||
                       info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
                       info->magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
@@ -1702,11 +1688,13 @@ xfs_da_grow_inode(
  * a bmap btree split to do that.
  */
 STATIC int
-xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
-                     xfs_dabuf_t **dead_bufp)
+xfs_da_swap_lastblock(
+       xfs_da_args_t   *args,
+       xfs_dablk_t     *dead_blknop,
+       struct xfs_buf  **dead_bufp)
 {
        xfs_dablk_t dead_blkno, last_blkno, sib_blkno, par_blkno;
-       xfs_dabuf_t *dead_buf, *last_buf, *sib_buf, *par_buf;
+       struct xfs_buf *dead_buf, *last_buf, *sib_buf, *par_buf;
        xfs_fileoff_t lastoff;
        xfs_inode_t *ip;
        xfs_trans_t *tp;
@@ -1744,9 +1732,9 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
        /*
         * Copy the last block into the dead buffer and log it.
         */
-       memcpy(dead_buf->data, last_buf->data, mp->m_dirblksize);
-       xfs_da_log_buf(tp, dead_buf, 0, mp->m_dirblksize - 1);
-       dead_info = dead_buf->data;
+       memcpy(dead_buf->b_addr, last_buf->b_addr, mp->m_dirblksize);
+       xfs_trans_log_buf(tp, dead_buf, 0, mp->m_dirblksize - 1);
+       dead_info = dead_buf->b_addr;
        /*
         * Get values from the moved block.
         */
@@ -1767,7 +1755,7 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
        if ((sib_blkno = be32_to_cpu(dead_info->back))) {
                if ((error = xfs_da_read_buf(tp, ip, sib_blkno, -1, &sib_buf, w)))
                        goto done;
-               sib_info = sib_buf->data;
+               sib_info = sib_buf->b_addr;
                if (unlikely(
                    be32_to_cpu(sib_info->forw) != last_blkno ||
                    sib_info->magic != dead_info->magic)) {
@@ -1777,10 +1765,9 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
                        goto done;
                }
                sib_info->forw = cpu_to_be32(dead_blkno);
-               xfs_da_log_buf(tp, sib_buf,
+               xfs_trans_log_buf(tp, sib_buf,
                        XFS_DA_LOGRANGE(sib_info, &sib_info->forw,
                                        sizeof(sib_info->forw)));
-               xfs_da_buf_done(sib_buf);
                sib_buf = NULL;
        }
        /*
@@ -1789,7 +1776,7 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
        if ((sib_blkno = be32_to_cpu(dead_info->forw))) {
                if ((error = xfs_da_read_buf(tp, ip, sib_blkno, -1, &sib_buf, w)))
                        goto done;
-               sib_info = sib_buf->data;
+               sib_info = sib_buf->b_addr;
                if (unlikely(
                       be32_to_cpu(sib_info->back) != last_blkno ||
                       sib_info->magic != dead_info->magic)) {
@@ -1799,10 +1786,9 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
                        goto done;
                }
                sib_info->back = cpu_to_be32(dead_blkno);
-               xfs_da_log_buf(tp, sib_buf,
+               xfs_trans_log_buf(tp, sib_buf,
                        XFS_DA_LOGRANGE(sib_info, &sib_info->back,
                                        sizeof(sib_info->back)));
-               xfs_da_buf_done(sib_buf);
                sib_buf = NULL;
        }
        par_blkno = mp->m_dirleafblk;
@@ -1813,7 +1799,7 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
        for (;;) {
                if ((error = xfs_da_read_buf(tp, ip, par_blkno, -1, &par_buf, w)))
                        goto done;
-               par_node = par_buf->data;
+               par_node = par_buf->b_addr;
                if (unlikely(par_node->hdr.info.magic !=
                    cpu_to_be16(XFS_DA_NODE_MAGIC) ||
                    (level >= 0 && level != be16_to_cpu(par_node->hdr.level) + 1))) {
@@ -1837,7 +1823,7 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
                par_blkno = be32_to_cpu(par_node->btree[entno].before);
                if (level == dead_level + 1)
                        break;
-               xfs_da_brelse(tp, par_buf);
+               xfs_trans_brelse(tp, par_buf);
                par_buf = NULL;
        }
        /*
@@ -1853,7 +1839,7 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
                if (entno < be16_to_cpu(par_node->hdr.count))
                        break;
                par_blkno = be32_to_cpu(par_node->hdr.info.forw);
-               xfs_da_brelse(tp, par_buf);
+               xfs_trans_brelse(tp, par_buf);
                par_buf = NULL;
                if (unlikely(par_blkno == 0)) {
                        XFS_ERROR_REPORT("xfs_da_swap_lastblock(6)",
@@ -1863,7 +1849,7 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
                }
                if ((error = xfs_da_read_buf(tp, ip, par_blkno, -1, &par_buf, w)))
                        goto done;
-               par_node = par_buf->data;
+               par_node = par_buf->b_addr;
                if (unlikely(
                    be16_to_cpu(par_node->hdr.level) != level ||
                    par_node->hdr.info.magic != cpu_to_be16(XFS_DA_NODE_MAGIC))) {
@@ -1878,20 +1864,18 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
         * Update the parent entry pointing to the moved block.
         */
        par_node->btree[entno].before = cpu_to_be32(dead_blkno);
-       xfs_da_log_buf(tp, par_buf,
+       xfs_trans_log_buf(tp, par_buf,
                XFS_DA_LOGRANGE(par_node, &par_node->btree[entno].before,
                                sizeof(par_node->btree[entno].before)));
-       xfs_da_buf_done(par_buf);
-       xfs_da_buf_done(dead_buf);
        *dead_blknop = last_blkno;
        *dead_bufp = last_buf;
        return 0;
 done:
        if (par_buf)
-               xfs_da_brelse(tp, par_buf);
+               xfs_trans_brelse(tp, par_buf);
        if (sib_buf)
-               xfs_da_brelse(tp, sib_buf);
-       xfs_da_brelse(tp, last_buf);
+               xfs_trans_brelse(tp, sib_buf);
+       xfs_trans_brelse(tp, last_buf);
        return error;
 }
 
@@ -1899,8 +1883,10 @@ done:
  * Remove a btree block from a directory or attribute.
  */
 int
-xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
-                   xfs_dabuf_t *dead_buf)
+xfs_da_shrink_inode(
+       xfs_da_args_t   *args,
+       xfs_dablk_t     dead_blkno,
+       struct xfs_buf  *dead_buf)
 {
        xfs_inode_t *dp;
        int done, error, w, count;
@@ -1935,7 +1921,7 @@ xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
                        break;
                }
        }
-       xfs_da_binval(tp, dead_buf);
+       xfs_trans_binval(tp, dead_buf);
        return error;
 }
 
@@ -1967,35 +1953,75 @@ xfs_da_map_covers_blocks(
 }
 
 /*
- * Make a dabuf.
- * Used for get_buf, read_buf, read_bufr, and reada_buf.
+ * Convert a struct xfs_bmbt_irec to a struct xfs_buf_map.
+ *
+ * For the single map case, it is assumed that the caller has provided a pointer
+ * to a valid xfs_buf_map.  For the multiple map case, this function will
+ * allocate the xfs_buf_map to hold all the maps and replace the caller's single
+ * map pointer with the allocated map.
  */
-STATIC int
-xfs_da_do_buf(
-       xfs_trans_t     *trans,
-       xfs_inode_t     *dp,
-       xfs_dablk_t     bno,
-       xfs_daddr_t     *mappedbnop,
-       xfs_dabuf_t     **bpp,
-       int             whichfork,
-       int             caller)
+static int
+xfs_buf_map_from_irec(
+       struct xfs_mount        *mp,
+       struct xfs_buf_map      **mapp,
+       unsigned int            *nmaps,
+       struct xfs_bmbt_irec    *irecs,
+       unsigned int            nirecs)
 {
-       xfs_buf_t       *bp = NULL;
-       xfs_buf_t       **bplist;
-       int             error=0;
-       int             i;
-       xfs_bmbt_irec_t map;
-       xfs_bmbt_irec_t *mapp;
-       xfs_daddr_t     mappedbno;
-       xfs_mount_t     *mp;
-       int             nbplist=0;
-       int             nfsb;
-       int             nmap;
-       xfs_dabuf_t     *rbp;
+       struct xfs_buf_map      *map;
+       int                     i;
+
+       ASSERT(*nmaps == 1);
+       ASSERT(nirecs >= 1);
+
+       if (nirecs > 1) {
+               map = kmem_zalloc(nirecs * sizeof(struct xfs_buf_map), KM_SLEEP);
+               if (!map)
+                       return ENOMEM;
+               *mapp = map;
+       }
+
+       *nmaps = nirecs;
+       map = *mapp;
+       for (i = 0; i < *nmaps; i++) {
+               ASSERT(irecs[i].br_startblock != DELAYSTARTBLOCK &&
+                      irecs[i].br_startblock != HOLESTARTBLOCK);
+               map[i].bm_bn = XFS_FSB_TO_DADDR(mp, irecs[i].br_startblock);
+               map[i].bm_len = XFS_FSB_TO_BB(mp, irecs[i].br_blockcount);
+       }
+       return 0;
+}
+
+/*
+ * Map the block we are given ready for reading. There are three possible return
+ * values:
+ *     -1 - will be returned if we land in a hole and mappedbno == -2 so the
+ *          caller knows not to execute a subsequent read.
+ *      0 - if we mapped the block successfully
+ *     >0 - positive error number if there was an error.
+ */
+static int
+xfs_dabuf_map(
+       struct xfs_trans        *trans,
+       struct xfs_inode        *dp,
+       xfs_dablk_t             bno,
+       xfs_daddr_t             mappedbno,
+       int                     whichfork,
+       struct xfs_buf_map      **map,
+       int                     *nmaps)
+{
+       struct xfs_mount        *mp = dp->i_mount;
+       int                     nfsb;
+       int                     error = 0;
+       struct xfs_bmbt_irec    irec;
+       struct xfs_bmbt_irec    *irecs = &irec;
+       int                     nirecs;
+
+       ASSERT(map && *map);
+       ASSERT(*nmaps == 1);
 
-       mp = dp->i_mount;
        nfsb = (whichfork == XFS_DATA_FORK) ? mp->m_dirblkfsbs : 1;
-       mappedbno = *mappedbnop;
+
        /*
         * Caller doesn't have a mapping.  -2 means don't complain
         * if we land in a hole.
@@ -2004,112 +2030,150 @@ xfs_da_do_buf(
                /*
                 * Optimize the one-block case.
                 */
-               if (nfsb == 1)
-                       mapp = &map;
-               else
-                       mapp = kmem_alloc(sizeof(*mapp) * nfsb, KM_SLEEP);
+               if (nfsb != 1)
+                       irecs = kmem_zalloc(sizeof(irec) * nfsb, KM_SLEEP);
 
-               nmap = nfsb;
-               error = xfs_bmapi_read(dp, (xfs_fileoff_t)bno, nfsb, mapp,
-                                      &nmap, xfs_bmapi_aflag(whichfork));
+               nirecs = nfsb;
+               error = xfs_bmapi_read(dp, (xfs_fileoff_t)bno, nfsb, irecs,
+                                      &nirecs, xfs_bmapi_aflag(whichfork));
                if (error)
-                       goto exit0;
+                       goto out;
        } else {
-               map.br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno);
-               map.br_startoff = (xfs_fileoff_t)bno;
-               map.br_blockcount = nfsb;
-               mapp = &map;
-               nmap = 1;
+               irecs->br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno);
+               irecs->br_startoff = (xfs_fileoff_t)bno;
+               irecs->br_blockcount = nfsb;
+               irecs->br_state = 0;
+               nirecs = 1;
        }
-       if (!xfs_da_map_covers_blocks(nmap, mapp, bno, nfsb)) {
-               error = mappedbno == -2 ? 0 : XFS_ERROR(EFSCORRUPTED);
+
+       if (!xfs_da_map_covers_blocks(nirecs, irecs, bno, nfsb)) {
+               error = mappedbno == -2 ? -1 : XFS_ERROR(EFSCORRUPTED);
                if (unlikely(error == EFSCORRUPTED)) {
                        if (xfs_error_level >= XFS_ERRLEVEL_LOW) {
+                               int i;
                                xfs_alert(mp, "%s: bno %lld dir: inode %lld",
                                        __func__, (long long)bno,
                                        (long long)dp->i_ino);
-                               for (i = 0; i < nmap; i++) {
+                               for (i = 0; i < *nmaps; i++) {
                                        xfs_alert(mp,
 "[%02d] br_startoff %lld br_startblock %lld br_blockcount %lld br_state %d",
                                                i,
-                                               (long long)mapp[i].br_startoff,
-                                               (long long)mapp[i].br_startblock,
-                                               (long long)mapp[i].br_blockcount,
-                                               mapp[i].br_state);
+                                               (long long)irecs[i].br_startoff,
+                                               (long long)irecs[i].br_startblock,
+                                               (long long)irecs[i].br_blockcount,
+                                               irecs[i].br_state);
                                }
                        }
                        XFS_ERROR_REPORT("xfs_da_do_buf(1)",
                                         XFS_ERRLEVEL_LOW, mp);
                }
-               goto exit0;
+               goto out;
        }
-       if (caller != 3 && nmap > 1) {
-               bplist = kmem_alloc(sizeof(*bplist) * nmap, KM_SLEEP);
-               nbplist = 0;
-       } else
-               bplist = NULL;
-       /*
-        * Turn the mapping(s) into buffer(s).
-        */
-       for (i = 0; i < nmap; i++) {
-               int     nmapped;
-
-               mappedbno = XFS_FSB_TO_DADDR(mp, mapp[i].br_startblock);
-               if (i == 0)
-                       *mappedbnop = mappedbno;
-               nmapped = (int)XFS_FSB_TO_BB(mp, mapp[i].br_blockcount);
-               switch (caller) {
-               case 0:
-                       bp = xfs_trans_get_buf(trans, mp->m_ddev_targp,
-                               mappedbno, nmapped, 0);
-                       error = bp ? bp->b_error : XFS_ERROR(EIO);
-                       break;
-               case 1:
-               case 2:
-                       bp = NULL;
-                       error = xfs_trans_read_buf(mp, trans, mp->m_ddev_targp,
-                               mappedbno, nmapped, 0, &bp);
-                       break;
-               case 3:
-                       xfs_buf_readahead(mp->m_ddev_targp, mappedbno, nmapped);
+       error = xfs_buf_map_from_irec(mp, map, nmaps, irecs, nirecs);
+out:
+       if (irecs != &irec)
+               kmem_free(irecs);
+       return error;
+}
+
+/*
+ * Get a buffer for the dir/attr block.
+ */
+int
+xfs_da_get_buf(
+       struct xfs_trans        *trans,
+       struct xfs_inode        *dp,
+       xfs_dablk_t             bno,
+       xfs_daddr_t             mappedbno,
+       struct xfs_buf          **bpp,
+       int                     whichfork)
+{
+       struct xfs_buf          *bp;
+       struct xfs_buf_map      map;
+       struct xfs_buf_map      *mapp;
+       int                     nmap;
+       int                     error;
+
+       *bpp = NULL;
+       mapp = &map;
+       nmap = 1;
+       error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork,
+                               &mapp, &nmap);
+       if (error) {
+               /* mapping a hole is not an error, but we don't continue */
+               if (error == -1)
                        error = 0;
-                       bp = NULL;
-                       break;
-               }
-               if (error) {
-                       if (bp)
-                               xfs_trans_brelse(trans, bp);
-                       goto exit1;
-               }
-               if (!bp)
-                       continue;
-               if (caller == 1) {
-                       if (whichfork == XFS_ATTR_FORK)
-                               xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF);
-                       else
-                               xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF);
-               }
-               if (bplist) {
-                       bplist[nbplist++] = bp;
-               }
+               goto out_free;
        }
-       /*
-        * Build a dabuf structure.
-        */
-       if (bplist) {
-               rbp = xfs_da_buf_make(nbplist, bplist);
-       } else if (bp)
-               rbp = xfs_da_buf_make(1, &bp);
+
+       bp = xfs_trans_get_buf_map(trans, dp->i_mount->m_ddev_targp,
+                                   mapp, nmap, 0);
+       error = bp ? bp->b_error : XFS_ERROR(EIO);
+       if (error) {
+               xfs_trans_brelse(trans, bp);
+               goto out_free;
+       }
+
+       *bpp = bp;
+
+out_free:
+       if (mapp != &map)
+               kmem_free(mapp);
+
+       return error;
+}
+
+/*
+ * Get a buffer for the dir/attr block, fill in the contents.
+ */
+int
+xfs_da_read_buf(
+       struct xfs_trans        *trans,
+       struct xfs_inode        *dp,
+       xfs_dablk_t             bno,
+       xfs_daddr_t             mappedbno,
+       struct xfs_buf          **bpp,
+       int                     whichfork)
+{
+       struct xfs_buf          *bp;
+       struct xfs_buf_map      map;
+       struct xfs_buf_map      *mapp;
+       int                     nmap;
+       int                     error;
+
+       *bpp = NULL;
+       mapp = &map;
+       nmap = 1;
+       error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork,
+                               &mapp, &nmap);
+       if (error) {
+               /* mapping a hole is not an error, but we don't continue */
+               if (error == -1)
+                       error = 0;
+               goto out_free;
+       }
+
+       error = xfs_trans_read_buf_map(dp->i_mount, trans,
+                                       dp->i_mount->m_ddev_targp,
+                                       mapp, nmap, 0, &bp);
+       if (error)
+               goto out_free;
+
+       if (whichfork == XFS_ATTR_FORK)
+               xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF);
        else
-               rbp = NULL;
+               xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF);
+
        /*
-        * For read_buf, check the magic number.
+        * This verification code will be moved to a CRC verification callback
+        * function so just leave it here unchanged until then.
         */
-       if (caller == 1) {
-               xfs_dir2_data_hdr_t     *hdr = rbp->data;
-               xfs_dir2_free_t         *free = rbp->data;
-               xfs_da_blkinfo_t        *info = rbp->data;
+       {
+               xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
+               xfs_dir2_free_t         *free = bp->b_addr;
+               xfs_da_blkinfo_t        *info = bp->b_addr;
                uint                    magic, magic1;
+               struct xfs_mount        *mp = dp->i_mount;
 
                magic = be16_to_cpu(info->magic);
                magic1 = be32_to_cpu(hdr->magic);
@@ -2123,66 +2187,20 @@ xfs_da_do_buf(
                                   (free->hdr.magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC)),
                                mp, XFS_ERRTAG_DA_READ_BUF,
                                XFS_RANDOM_DA_READ_BUF))) {
-                       trace_xfs_da_btree_corrupt(rbp->bps[0], _RET_IP_);
+                       trace_xfs_da_btree_corrupt(bp, _RET_IP_);
                        XFS_CORRUPTION_ERROR("xfs_da_do_buf(2)",
                                             XFS_ERRLEVEL_LOW, mp, info);
                        error = XFS_ERROR(EFSCORRUPTED);
-                       xfs_da_brelse(trans, rbp);
-                       nbplist = 0;
-                       goto exit1;
+                       xfs_trans_brelse(trans, bp);
+                       goto out_free;
                }
        }
-       if (bplist) {
-               kmem_free(bplist);
-       }
-       if (mapp != &map) {
-               kmem_free(mapp);
-       }
-       if (bpp)
-               *bpp = rbp;
-       return 0;
-exit1:
-       if (bplist) {
-               for (i = 0; i < nbplist; i++)
-                       xfs_trans_brelse(trans, bplist[i]);
-               kmem_free(bplist);
-       }
-exit0:
+       *bpp = bp;
+out_free:
        if (mapp != &map)
                kmem_free(mapp);
-       if (bpp)
-               *bpp = NULL;
-       return error;
-}
-
-/*
- * Get a buffer for the dir/attr block.
- */
-int
-xfs_da_get_buf(
-       xfs_trans_t     *trans,
-       xfs_inode_t     *dp,
-       xfs_dablk_t     bno,
-       xfs_daddr_t             mappedbno,
-       xfs_dabuf_t     **bpp,
-       int             whichfork)
-{
-       return xfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 0);
-}
 
-/*
- * Get a buffer for the dir/attr block, fill in the contents.
- */
-int
-xfs_da_read_buf(
-       xfs_trans_t     *trans,
-       xfs_inode_t     *dp,
-       xfs_dablk_t     bno,
-       xfs_daddr_t             mappedbno,
-       xfs_dabuf_t     **bpp,
-       int             whichfork)
-{
-       return xfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 1);
+       return error;
 }
 
 /*
@@ -2190,22 +2208,41 @@ xfs_da_read_buf(
  */
 xfs_daddr_t
 xfs_da_reada_buf(
-       xfs_trans_t     *trans,
-       xfs_inode_t     *dp,
-       xfs_dablk_t     bno,
-       int             whichfork)
+       struct xfs_trans        *trans,
+       struct xfs_inode        *dp,
+       xfs_dablk_t             bno,
+       int                     whichfork)
 {
-       xfs_daddr_t             rval;
+       xfs_daddr_t             mappedbno = -1;
+       struct xfs_buf_map      map;
+       struct xfs_buf_map      *mapp;
+       int                     nmap;
+       int                     error;
+
+       mapp = &map;
+       nmap = 1;
+       error = xfs_dabuf_map(trans, dp, bno, -1, whichfork,
+                               &mapp, &nmap);
+       if (error) {
+               /* mapping a hole is not an error, but we don't continue */
+               if (error == -1)
+                       error = 0;
+               goto out_free;
+       }
 
-       rval = -1;
-       if (xfs_da_do_buf(trans, dp, bno, &rval, NULL, whichfork, 3))
+       mappedbno = mapp[0].bm_bn;
+       xfs_buf_readahead_map(dp->i_mount->m_ddev_targp, mapp, nmap);
+
+out_free:
+       if (mapp != &map)
+               kmem_free(mapp);
+
+       if (error)
                return -1;
-       else
-               return rval;
+       return mappedbno;
 }
 
 kmem_zone_t *xfs_da_state_zone;        /* anchor for state struct zone */
-kmem_zone_t *xfs_dabuf_zone;           /* dabuf zone */
 
 /*
  * Allocate a dir-state structure.
@@ -2225,13 +2262,8 @@ xfs_da_state_kill_altpath(xfs_da_state_t *state)
 {
        int     i;
 
-       for (i = 0; i < state->altpath.active; i++) {
-               if (state->altpath.blk[i].bp) {
-                       if (state->altpath.blk[i].bp != state->path.blk[i].bp)
-                               xfs_da_buf_done(state->altpath.blk[i].bp);
-                       state->altpath.blk[i].bp = NULL;
-               }
-       }
+       for (i = 0; i < state->altpath.active; i++)
+               state->altpath.blk[i].bp = NULL;
        state->altpath.active = 0;
 }
 
@@ -2241,204 +2273,9 @@ xfs_da_state_kill_altpath(xfs_da_state_t *state)
 void
 xfs_da_state_free(xfs_da_state_t *state)
 {
-       int     i;
-
        xfs_da_state_kill_altpath(state);
-       for (i = 0; i < state->path.active; i++) {
-               if (state->path.blk[i].bp)
-                       xfs_da_buf_done(state->path.blk[i].bp);
-       }
-       if (state->extravalid && state->extrablk.bp)
-               xfs_da_buf_done(state->extrablk.bp);
 #ifdef DEBUG
        memset((char *)state, 0, sizeof(*state));
 #endif /* DEBUG */
        kmem_zone_free(xfs_da_state_zone, state);
 }
-
-/*
- * Create a dabuf.
- */
-/* ARGSUSED */
-STATIC xfs_dabuf_t *
-xfs_da_buf_make(int nbuf, xfs_buf_t **bps)
-{
-       xfs_buf_t       *bp;
-       xfs_dabuf_t     *dabuf;
-       int             i;
-       int             off;
-
-       if (nbuf == 1)
-               dabuf = kmem_zone_alloc(xfs_dabuf_zone, KM_NOFS);
-       else
-               dabuf = kmem_alloc(XFS_DA_BUF_SIZE(nbuf), KM_NOFS);
-       dabuf->dirty = 0;
-       if (nbuf == 1) {
-               dabuf->nbuf = 1;
-               bp = bps[0];
-               dabuf->bbcount = bp->b_length;
-               dabuf->data = bp->b_addr;
-               dabuf->bps[0] = bp;
-       } else {
-               dabuf->nbuf = nbuf;
-               for (i = 0, dabuf->bbcount = 0; i < nbuf; i++) {
-                       dabuf->bps[i] = bp = bps[i];
-                       dabuf->bbcount += bp->b_length;
-               }
-               dabuf->data = kmem_alloc(BBTOB(dabuf->bbcount), KM_SLEEP);
-               for (i = off = 0; i < nbuf; i++, off += BBTOB(bp->b_length)) {
-                       bp = bps[i];
-                       memcpy((char *)dabuf->data + off, bp->b_addr,
-                               BBTOB(bp->b_length));
-               }
-       }
-       return dabuf;
-}
-
-/*
- * Un-dirty a dabuf.
- */
-STATIC void
-xfs_da_buf_clean(xfs_dabuf_t *dabuf)
-{
-       xfs_buf_t       *bp;
-       int             i;
-       int             off;
-
-       if (dabuf->dirty) {
-               ASSERT(dabuf->nbuf > 1);
-               dabuf->dirty = 0;
-               for (i = off = 0; i < dabuf->nbuf;
-                               i++, off += BBTOB(bp->b_length)) {
-                       bp = dabuf->bps[i];
-                       memcpy(bp->b_addr, dabuf->data + off,
-                                               BBTOB(bp->b_length));
-               }
-       }
-}
-
-/*
- * Release a dabuf.
- */
-void
-xfs_da_buf_done(xfs_dabuf_t *dabuf)
-{
-       ASSERT(dabuf);
-       ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]);
-       if (dabuf->dirty)
-               xfs_da_buf_clean(dabuf);
-       if (dabuf->nbuf > 1) {
-               kmem_free(dabuf->data);
-               kmem_free(dabuf);
-       } else {
-               kmem_zone_free(xfs_dabuf_zone, dabuf);
-       }
-}
-
-/*
- * Log transaction from a dabuf.
- */
-void
-xfs_da_log_buf(xfs_trans_t *tp, xfs_dabuf_t *dabuf, uint first, uint last)
-{
-       xfs_buf_t       *bp;
-       uint            f;
-       int             i;
-       uint            l;
-       int             off;
-
-       ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]);
-       if (dabuf->nbuf == 1) {
-               ASSERT(dabuf->data == dabuf->bps[0]->b_addr);
-               xfs_trans_log_buf(tp, dabuf->bps[0], first, last);
-               return;
-       }
-       dabuf->dirty = 1;
-       ASSERT(first <= last);
-       for (i = off = 0; i < dabuf->nbuf; i++, off += BBTOB(bp->b_length)) {
-               bp = dabuf->bps[i];
-               f = off;
-               l = f + BBTOB(bp->b_length) - 1;
-               if (f < first)
-                       f = first;
-               if (l > last)
-                       l = last;
-               if (f <= l)
-                       xfs_trans_log_buf(tp, bp, f - off, l - off);
-               /*
-                * B_DONE is set by xfs_trans_log buf.
-                * If we don't set it on a new buffer (get not read)
-                * then if we don't put anything in the buffer it won't
-                * be set, and at commit it it released into the cache,
-                * and then a read will fail.
-                */
-               else if (!(XFS_BUF_ISDONE(bp)))
-                 XFS_BUF_DONE(bp);
-       }
-       ASSERT(last < off);
-}
-
-/*
- * Release dabuf from a transaction.
- * Have to free up the dabuf before the buffers are released,
- * since the synchronization on the dabuf is really the lock on the buffer.
- */
-void
-xfs_da_brelse(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
-{
-       xfs_buf_t       *bp;
-       xfs_buf_t       **bplist;
-       int             i;
-       int             nbuf;
-
-       ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]);
-       if ((nbuf = dabuf->nbuf) == 1) {
-               bplist = &bp;
-               bp = dabuf->bps[0];
-       } else {
-               bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP);
-               memcpy(bplist, dabuf->bps, nbuf * sizeof(*bplist));
-       }
-       xfs_da_buf_done(dabuf);
-       for (i = 0; i < nbuf; i++)
-               xfs_trans_brelse(tp, bplist[i]);
-       if (bplist != &bp)
-               kmem_free(bplist);
-}
-
-/*
- * Invalidate dabuf from a transaction.
- */
-void
-xfs_da_binval(xfs_trans_t *tp, xfs_dabuf_t *dabuf)
-{
-       xfs_buf_t       *bp;
-       xfs_buf_t       **bplist;
-       int             i;
-       int             nbuf;
-
-       ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]);
-       if ((nbuf = dabuf->nbuf) == 1) {
-               bplist = &bp;
-               bp = dabuf->bps[0];
-       } else {
-               bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP);
-               memcpy(bplist, dabuf->bps, nbuf * sizeof(*bplist));
-       }
-       xfs_da_buf_done(dabuf);
-       for (i = 0; i < nbuf; i++)
-               xfs_trans_binval(tp, bplist[i]);
-       if (bplist != &bp)
-               kmem_free(bplist);
-}
-
-/*
- * Get the first daddr from a dabuf.
- */
-xfs_daddr_t
-xfs_da_blkno(xfs_dabuf_t *dabuf)
-{
-       ASSERT(dabuf->nbuf);
-       ASSERT(dabuf->data);
-       return XFS_BUF_ADDR(dabuf->bps[0]);
-}
index dbf7c074ae730c66de16aee0eccc128f1e96b5fc..132adafb041ecf2c6483047f63940fbccd118d15 100644 (file)
@@ -32,7 +32,7 @@ struct zone;
 /*
  * This structure is common to both leaf nodes and non-leaf nodes in the Btree.
  *
- * Is is used to manage a doubly linked list of all blocks at the same
+ * It is used to manage a doubly linked list of all blocks at the same
  * level in the Btree, and to identify which type of block this is.
  */
 #define XFS_DA_NODE_MAGIC      0xfebe  /* magic number: non-leaf blocks */
@@ -132,24 +132,6 @@ typedef struct xfs_da_args {
        { XFS_DA_OP_OKNOENT,    "OKNOENT" }, \
        { XFS_DA_OP_CILOOKUP,   "CILOOKUP" }
 
-/*
- * Structure to describe buffer(s) for a block.
- * This is needed in the directory version 2 format case, when
- * multiple non-contiguous fsblocks might be needed to cover one
- * logical directory block.
- * If the buffer count is 1 then the data pointer points to the
- * same place as the b_addr field for the buffer, else to kmem_alloced memory.
- */
-typedef struct xfs_dabuf {
-       int             nbuf;           /* number of buffer pointers present */
-       short           dirty;          /* data needs to be copied back */
-       short           bbcount;        /* how large is data in bbs */
-       void            *data;          /* pointer for buffers' data */
-       struct xfs_buf  *bps[1];        /* actually nbuf of these */
-} xfs_dabuf_t;
-#define        XFS_DA_BUF_SIZE(n)      \
-       (sizeof(xfs_dabuf_t) + sizeof(struct xfs_buf *) * ((n) - 1))
-
 /*
  * Storage for holding state during Btree searches and split/join ops.
  *
@@ -158,7 +140,7 @@ typedef struct xfs_dabuf {
  * which is slightly more than enough.
  */
 typedef struct xfs_da_state_blk {
-       xfs_dabuf_t     *bp;            /* buffer containing block */
+       struct xfs_buf  *bp;            /* buffer containing block */
        xfs_dablk_t     blkno;          /* filesystem blkno of buffer */
        xfs_daddr_t     disk_blkno;     /* on-disk blkno (in BBs) of buffer */
        int             index;          /* relevant index into block */
@@ -211,7 +193,7 @@ struct xfs_nameops {
  * Routines used for growing the Btree.
  */
 int    xfs_da_node_create(xfs_da_args_t *args, xfs_dablk_t blkno, int level,
-                                        xfs_dabuf_t **bpp, int whichfork);
+                                        struct xfs_buf **bpp, int whichfork);
 int    xfs_da_split(xfs_da_state_t *state);
 
 /*
@@ -241,14 +223,14 @@ int       xfs_da_grow_inode_int(struct xfs_da_args *args, xfs_fileoff_t *bno,
                              int count);
 int    xfs_da_get_buf(struct xfs_trans *trans, struct xfs_inode *dp,
                              xfs_dablk_t bno, xfs_daddr_t mappedbno,
-                             xfs_dabuf_t **bp, int whichfork);
+                             struct xfs_buf **bp, int whichfork);
 int    xfs_da_read_buf(struct xfs_trans *trans, struct xfs_inode *dp,
                               xfs_dablk_t bno, xfs_daddr_t mappedbno,
-                              xfs_dabuf_t **bpp, int whichfork);
+                              struct xfs_buf **bpp, int whichfork);
 xfs_daddr_t    xfs_da_reada_buf(struct xfs_trans *trans, struct xfs_inode *dp,
                        xfs_dablk_t bno, int whichfork);
 int    xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
-                                         xfs_dabuf_t *dead_buf);
+                                         struct xfs_buf *dead_buf);
 
 uint xfs_da_hashname(const __uint8_t *name_string, int name_length);
 enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args,
@@ -258,15 +240,7 @@ enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args,
 xfs_da_state_t *xfs_da_state_alloc(void);
 void xfs_da_state_free(xfs_da_state_t *state);
 
-void xfs_da_buf_done(xfs_dabuf_t *dabuf);
-void xfs_da_log_buf(struct xfs_trans *tp, xfs_dabuf_t *dabuf, uint first,
-                          uint last);
-void xfs_da_brelse(struct xfs_trans *tp, xfs_dabuf_t *dabuf);
-void xfs_da_binval(struct xfs_trans *tp, xfs_dabuf_t *dabuf);
-xfs_daddr_t xfs_da_blkno(xfs_dabuf_t *dabuf);
-
 extern struct kmem_zone *xfs_da_state_zone;
-extern struct kmem_zone *xfs_dabuf_zone;
 extern const struct xfs_nameops xfs_default_nameops;
 
 #endif /* __XFS_DA_BTREE_H__ */
index a3721633abc8744a1d0187de3382cdd973efdb15..1d9643b3dce656123cb591379bb07ee235143f11 100644 (file)
@@ -33,7 +33,7 @@ typedef struct xfs_timestamp {
  * variable size the leftover area split into a data and an attribute fork.
  * The format of the data and attribute fork depends on the format of the
  * inode as indicated by di_format and di_aformat.  To access the data and
- * attribute use the XFS_DFORK_PTR, XFS_DFORK_DPTR, and XFS_DFORK_PTR macros
+ * attribute use the XFS_DFORK_DPTR, XFS_DFORK_APTR, and XFS_DFORK_PTR macros
  * below.
  *
  * There is a very similar struct icdinode in xfs_inode which matches the
index 67a250c36d414d3be83a50f4acb51f8069f147f4..b26a50f9921db60e746d43946b644415ba24ca6a 100644 (file)
@@ -592,7 +592,7 @@ int
 xfs_dir2_shrink_inode(
        xfs_da_args_t   *args,
        xfs_dir2_db_t   db,
-       xfs_dabuf_t     *bp)
+       struct xfs_buf  *bp)
 {
        xfs_fileoff_t   bno;            /* directory file offset */
        xfs_dablk_t     da;             /* directory file offset */
@@ -634,7 +634,7 @@ xfs_dir2_shrink_inode(
        /*
         * Invalidate the buffer from the transaction.
         */
-       xfs_da_binval(tp, bp);
+       xfs_trans_binval(tp, bp);
        /*
         * If it's not a data block, we're done.
         */
index 586732f2d80de076faf539e87aba8d1444ff172d..e93ca8f054f404245b2927b93cdf486387b432c1 100644 (file)
 /*
  * Local function prototypes.
  */
-static void xfs_dir2_block_log_leaf(xfs_trans_t *tp, xfs_dabuf_t *bp, int first,
-                                   int last);
-static void xfs_dir2_block_log_tail(xfs_trans_t *tp, xfs_dabuf_t *bp);
-static int xfs_dir2_block_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **bpp,
+static void xfs_dir2_block_log_leaf(xfs_trans_t *tp, struct xfs_buf *bp,
+                                   int first, int last);
+static void xfs_dir2_block_log_tail(xfs_trans_t *tp, struct xfs_buf *bp);
+static int xfs_dir2_block_lookup_int(xfs_da_args_t *args, struct xfs_buf **bpp,
                                     int *entno);
 static int xfs_dir2_block_sort(const void *a, const void *b);
 
@@ -66,7 +66,7 @@ xfs_dir2_block_addname(
        xfs_dir2_data_free_t    *bf;            /* bestfree table in block */
        xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf entries */
-       xfs_dabuf_t             *bp;            /* buffer for block */
+       struct xfs_buf          *bp;            /* buffer for block */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
        int                     compact;        /* need to compact leaf ents */
        xfs_dir2_data_entry_t   *dep;           /* block data entry */
@@ -102,14 +102,14 @@ xfs_dir2_block_addname(
                return error;
        }
        ASSERT(bp != NULL);
-       hdr = bp->data;
+       hdr = bp->b_addr;
        /*
         * Check the magic number, corrupted if wrong.
         */
        if (unlikely(hdr->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC))) {
                XFS_CORRUPTION_ERROR("xfs_dir2_block_addname",
                                     XFS_ERRLEVEL_LOW, mp, hdr);
-               xfs_da_brelse(tp, bp);
+               xfs_trans_brelse(tp, bp);
                return XFS_ERROR(EFSCORRUPTED);
        }
        len = xfs_dir2_data_entsize(args->namelen);
@@ -212,7 +212,7 @@ xfs_dir2_block_addname(
         * If this isn't a real add, we're done with the buffer.
         */
        if (args->op_flags & XFS_DA_OP_JUSTCHECK)
-               xfs_da_brelse(tp, bp);
+               xfs_trans_brelse(tp, bp);
        /*
         * If we don't have space for the new entry & leaf ...
         */
@@ -228,7 +228,6 @@ xfs_dir2_block_addname(
                 * Then add the new entry in that format.
                 */
                error = xfs_dir2_block_to_leaf(args, bp);
-               xfs_da_buf_done(bp);
                if (error)
                        return error;
                return xfs_dir2_leaf_addname(args);
@@ -422,7 +421,6 @@ xfs_dir2_block_addname(
        xfs_dir2_block_log_tail(tp, bp);
        xfs_dir2_data_log_entry(tp, bp, dep);
        xfs_dir2_data_check(dp, bp);
-       xfs_da_buf_done(bp);
        return 0;
 }
 
@@ -437,7 +435,7 @@ xfs_dir2_block_getdents(
        filldir_t               filldir)
 {
        xfs_dir2_data_hdr_t     *hdr;           /* block header */
-       xfs_dabuf_t             *bp;            /* buffer for block */
+       struct xfs_buf          *bp;            /* buffer for block */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
        xfs_dir2_data_entry_t   *dep;           /* block data entry */
        xfs_dir2_data_unused_t  *dup;           /* block unused entry */
@@ -469,7 +467,7 @@ xfs_dir2_block_getdents(
         * We'll skip entries before this.
         */
        wantoff = xfs_dir2_dataptr_to_off(mp, *offset);
-       hdr = bp->data;
+       hdr = bp->b_addr;
        xfs_dir2_data_check(dp, bp);
        /*
         * Set up values for the loop.
@@ -514,7 +512,7 @@ xfs_dir2_block_getdents(
                            cook & 0x7fffffff, be64_to_cpu(dep->inumber),
                            DT_UNKNOWN)) {
                        *offset = cook & 0x7fffffff;
-                       xfs_da_brelse(NULL, bp);
+                       xfs_trans_brelse(NULL, bp);
                        return 0;
                }
        }
@@ -525,7 +523,7 @@ xfs_dir2_block_getdents(
         */
        *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
                        0x7fffffff;
-       xfs_da_brelse(NULL, bp);
+       xfs_trans_brelse(NULL, bp);
        return 0;
 }
 
@@ -535,17 +533,17 @@ xfs_dir2_block_getdents(
 static void
 xfs_dir2_block_log_leaf(
        xfs_trans_t             *tp,            /* transaction structure */
-       xfs_dabuf_t             *bp,            /* block buffer */
+       struct xfs_buf          *bp,            /* block buffer */
        int                     first,          /* index of first logged leaf */
        int                     last)           /* index of last logged leaf */
 {
-       xfs_dir2_data_hdr_t     *hdr = bp->data;
+       xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
        xfs_dir2_leaf_entry_t   *blp;
        xfs_dir2_block_tail_t   *btp;
 
        btp = xfs_dir2_block_tail_p(tp->t_mountp, hdr);
        blp = xfs_dir2_block_leaf_p(btp);
-       xfs_da_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)hdr),
+       xfs_trans_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)hdr),
                (uint)((char *)&blp[last + 1] - (char *)hdr - 1));
 }
 
@@ -555,13 +553,13 @@ xfs_dir2_block_log_leaf(
 static void
 xfs_dir2_block_log_tail(
        xfs_trans_t             *tp,            /* transaction structure */
-       xfs_dabuf_t             *bp)            /* block buffer */
+       struct xfs_buf          *bp)            /* block buffer */
 {
-       xfs_dir2_data_hdr_t     *hdr = bp->data;
+       xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
        xfs_dir2_block_tail_t   *btp;
 
        btp = xfs_dir2_block_tail_p(tp->t_mountp, hdr);
-       xfs_da_log_buf(tp, bp, (uint)((char *)btp - (char *)hdr),
+       xfs_trans_log_buf(tp, bp, (uint)((char *)btp - (char *)hdr),
                (uint)((char *)(btp + 1) - (char *)hdr - 1));
 }
 
@@ -575,7 +573,7 @@ xfs_dir2_block_lookup(
 {
        xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf entries */
-       xfs_dabuf_t             *bp;            /* block buffer */
+       struct xfs_buf          *bp;            /* block buffer */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
        xfs_dir2_data_entry_t   *dep;           /* block data entry */
        xfs_inode_t             *dp;            /* incore inode */
@@ -593,7 +591,7 @@ xfs_dir2_block_lookup(
                return error;
        dp = args->dp;
        mp = dp->i_mount;
-       hdr = bp->data;
+       hdr = bp->b_addr;
        xfs_dir2_data_check(dp, bp);
        btp = xfs_dir2_block_tail_p(mp, hdr);
        blp = xfs_dir2_block_leaf_p(btp);
@@ -607,7 +605,7 @@ xfs_dir2_block_lookup(
         */
        args->inumber = be64_to_cpu(dep->inumber);
        error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
-       xfs_da_brelse(args->trans, bp);
+       xfs_trans_brelse(args->trans, bp);
        return XFS_ERROR(error);
 }
 
@@ -617,13 +615,13 @@ xfs_dir2_block_lookup(
 static int                                     /* error */
 xfs_dir2_block_lookup_int(
        xfs_da_args_t           *args,          /* dir lookup arguments */
-       xfs_dabuf_t             **bpp,          /* returned block buffer */
+       struct xfs_buf          **bpp,          /* returned block buffer */
        int                     *entno)         /* returned entry number */
 {
        xfs_dir2_dataptr_t      addr;           /* data entry address */
        xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf entries */
-       xfs_dabuf_t             *bp;            /* block buffer */
+       struct xfs_buf          *bp;            /* block buffer */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
        xfs_dir2_data_entry_t   *dep;           /* block data entry */
        xfs_inode_t             *dp;            /* incore inode */
@@ -647,7 +645,7 @@ xfs_dir2_block_lookup_int(
                return error;
        }
        ASSERT(bp != NULL);
-       hdr = bp->data;
+       hdr = bp->b_addr;
        xfs_dir2_data_check(dp, bp);
        btp = xfs_dir2_block_tail_p(mp, hdr);
        blp = xfs_dir2_block_leaf_p(btp);
@@ -666,7 +664,7 @@ xfs_dir2_block_lookup_int(
                        high = mid - 1;
                if (low > high) {
                        ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
-                       xfs_da_brelse(tp, bp);
+                       xfs_trans_brelse(tp, bp);
                        return XFS_ERROR(ENOENT);
                }
        }
@@ -714,7 +712,7 @@ xfs_dir2_block_lookup_int(
        /*
         * No match, release the buffer and return ENOENT.
         */
-       xfs_da_brelse(tp, bp);
+       xfs_trans_brelse(tp, bp);
        return XFS_ERROR(ENOENT);
 }
 
@@ -728,7 +726,7 @@ xfs_dir2_block_removename(
 {
        xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf pointer */
-       xfs_dabuf_t             *bp;            /* block buffer */
+       struct xfs_buf          *bp;            /* block buffer */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
        xfs_dir2_data_entry_t   *dep;           /* block data entry */
        xfs_inode_t             *dp;            /* incore inode */
@@ -753,7 +751,7 @@ xfs_dir2_block_removename(
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
-       hdr = bp->data;
+       hdr = bp->b_addr;
        btp = xfs_dir2_block_tail_p(mp, hdr);
        blp = xfs_dir2_block_leaf_p(btp);
        /*
@@ -790,10 +788,9 @@ xfs_dir2_block_removename(
         * See if the size as a shortform is good enough.
         */
        size = xfs_dir2_block_sfsize(dp, hdr, &sfh);
-       if (size > XFS_IFORK_DSIZE(dp)) {
-               xfs_da_buf_done(bp);
+       if (size > XFS_IFORK_DSIZE(dp))
                return 0;
-       }
+
        /*
         * If it works, do the conversion.
         */
@@ -810,7 +807,7 @@ xfs_dir2_block_replace(
 {
        xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf entries */
-       xfs_dabuf_t             *bp;            /* block buffer */
+       struct xfs_buf          *bp;            /* block buffer */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
        xfs_dir2_data_entry_t   *dep;           /* block data entry */
        xfs_inode_t             *dp;            /* incore inode */
@@ -829,7 +826,7 @@ xfs_dir2_block_replace(
        }
        dp = args->dp;
        mp = dp->i_mount;
-       hdr = bp->data;
+       hdr = bp->b_addr;
        btp = xfs_dir2_block_tail_p(mp, hdr);
        blp = xfs_dir2_block_leaf_p(btp);
        /*
@@ -844,7 +841,6 @@ xfs_dir2_block_replace(
        dep->inumber = cpu_to_be64(args->inumber);
        xfs_dir2_data_log_entry(args->trans, bp, dep);
        xfs_dir2_data_check(dp, bp);
-       xfs_da_buf_done(bp);
        return 0;
 }
 
@@ -871,8 +867,8 @@ xfs_dir2_block_sort(
 int                                            /* error */
 xfs_dir2_leaf_to_block(
        xfs_da_args_t           *args,          /* operation arguments */
-       xfs_dabuf_t             *lbp,           /* leaf buffer */
-       xfs_dabuf_t             *dbp)           /* data buffer */
+       struct xfs_buf          *lbp,           /* leaf buffer */
+       struct xfs_buf          *dbp)           /* data buffer */
 {
        __be16                  *bestsp;        /* leaf bests table */
        xfs_dir2_data_hdr_t     *hdr;           /* block header */
@@ -898,7 +894,7 @@ xfs_dir2_leaf_to_block(
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
-       leaf = lbp->data;
+       leaf = lbp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC));
        ltp = xfs_dir2_leaf_tail_p(mp, leaf);
        /*
@@ -914,11 +910,9 @@ xfs_dir2_leaf_to_block(
                        if ((error =
                            xfs_dir2_leaf_trim_data(args, lbp,
                                    (xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1))))
-                               goto out;
-               } else {
-                       error = 0;
-                       goto out;
-               }
+                               return error;
+               } else
+                       return 0;
        }
        /*
         * Read the data block if we don't already have it, give up if it fails.
@@ -926,9 +920,9 @@ xfs_dir2_leaf_to_block(
        if (dbp == NULL &&
            (error = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &dbp,
                    XFS_DATA_FORK))) {
-               goto out;
+               return error;
        }
-       hdr = dbp->data;
+       hdr = dbp->b_addr;
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC));
        /*
         * Size of the "leaf" area in the block.
@@ -944,10 +938,9 @@ xfs_dir2_leaf_to_block(
         * If it's not free or is too short we can't do it.
         */
        if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG ||
-           be16_to_cpu(dup->length) < size) {
-               error = 0;
-               goto out;
-       }
+           be16_to_cpu(dup->length) < size)
+               return 0;
+
        /*
         * Start converting it to block form.
         */
@@ -989,25 +982,17 @@ xfs_dir2_leaf_to_block(
         * Pitch the old leaf block.
         */
        error = xfs_da_shrink_inode(args, mp->m_dirleafblk, lbp);
-       lbp = NULL;
-       if (error) {
-               goto out;
-       }
+       if (error)
+               return error;
+
        /*
         * Now see if the resulting block can be shrunken to shortform.
         */
        size = xfs_dir2_block_sfsize(dp, hdr, &sfh);
-       if (size > XFS_IFORK_DSIZE(dp)) {
-               error = 0;
-               goto out;
-       }
+       if (size > XFS_IFORK_DSIZE(dp))
+               return 0;
+
        return xfs_dir2_block_to_sf(args, dbp, size, &sfh);
-out:
-       if (lbp)
-               xfs_da_buf_done(lbp);
-       if (dbp)
-               xfs_da_buf_done(dbp);
-       return error;
 }
 
 /*
@@ -1020,7 +1005,7 @@ xfs_dir2_sf_to_block(
        xfs_dir2_db_t           blkno;          /* dir-relative block # (0) */
        xfs_dir2_data_hdr_t     *hdr;           /* block header */
        xfs_dir2_leaf_entry_t   *blp;           /* block leaf entries */
-       xfs_dabuf_t             *bp;            /* block buffer */
+       struct xfs_buf          *bp;            /* block buffer */
        xfs_dir2_block_tail_t   *btp;           /* block tail pointer */
        xfs_dir2_data_entry_t   *dep;           /* data entry pointer */
        xfs_inode_t             *dp;            /* incore directory inode */
@@ -1088,7 +1073,7 @@ xfs_dir2_sf_to_block(
                kmem_free(sfp);
                return error;
        }
-       hdr = bp->data;
+       hdr = bp->b_addr;
        hdr->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC);
        /*
         * Compute size of block "tail" area.
@@ -1217,6 +1202,5 @@ xfs_dir2_sf_to_block(
        xfs_dir2_block_log_leaf(tp, bp, 0, be32_to_cpu(btp->count) - 1);
        xfs_dir2_block_log_tail(tp, bp);
        xfs_dir2_data_check(dp, bp);
-       xfs_da_buf_done(bp);
        return 0;
 }
index 2046988e9eb20dcf46832288f74f73f8f966f31c..44ffd4d6bc91af0f0f738bcf38f1371b2185d684 100644 (file)
@@ -42,8 +42,8 @@ xfs_dir2_data_freefind(xfs_dir2_data_hdr_t *hdr, xfs_dir2_data_unused_t *dup);
  */
 void
 xfs_dir2_data_check(
-       xfs_inode_t             *dp,            /* incore inode pointer */
-       xfs_dabuf_t             *bp)            /* data block's buffer */
+       struct xfs_inode        *dp,            /* incore inode pointer */
+       struct xfs_buf          *bp)            /* data block's buffer */
 {
        xfs_dir2_dataptr_t      addr;           /* addr for leaf lookup */
        xfs_dir2_data_free_t    *bf;            /* bestfree table */
@@ -65,7 +65,7 @@ xfs_dir2_data_check(
        struct xfs_name         name;
 
        mp = dp->i_mount;
-       hdr = bp->data;
+       hdr = bp->b_addr;
        bf = hdr->bestfree;
        p = (char *)(hdr + 1);
 
@@ -389,9 +389,9 @@ int                                         /* error */
 xfs_dir2_data_init(
        xfs_da_args_t           *args,          /* directory operation args */
        xfs_dir2_db_t           blkno,          /* logical dir block number */
-       xfs_dabuf_t             **bpp)          /* output block buffer */
+       struct xfs_buf          **bpp)          /* output block buffer */
 {
-       xfs_dabuf_t             *bp;            /* block buffer */
+       struct xfs_buf          *bp;            /* block buffer */
        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
        xfs_inode_t             *dp;            /* incore directory inode */
        xfs_dir2_data_unused_t  *dup;           /* unused entry pointer */
@@ -417,7 +417,7 @@ xfs_dir2_data_init(
        /*
         * Initialize the header.
         */
-       hdr = bp->data;
+       hdr = bp->b_addr;
        hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
        hdr->bestfree[0].offset = cpu_to_be16(sizeof(*hdr));
        for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {
@@ -449,16 +449,16 @@ xfs_dir2_data_init(
  */
 void
 xfs_dir2_data_log_entry(
-       xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_dabuf_t             *bp,            /* block buffer */
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp,
        xfs_dir2_data_entry_t   *dep)           /* data entry pointer */
 {
-       xfs_dir2_data_hdr_t     *hdr = bp->data;
+       xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
 
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
 
-       xfs_da_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr),
+       xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr),
                (uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) -
                       (char *)hdr - 1));
 }
@@ -468,15 +468,15 @@ xfs_dir2_data_log_entry(
  */
 void
 xfs_dir2_data_log_header(
-       xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_dabuf_t             *bp)            /* block buffer */
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp)
 {
-       xfs_dir2_data_hdr_t     *hdr = bp->data;
+       xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
 
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
 
-       xfs_da_log_buf(tp, bp, 0, sizeof(*hdr) - 1);
+       xfs_trans_log_buf(tp, bp, 0, sizeof(*hdr) - 1);
 }
 
 /*
@@ -484,11 +484,11 @@ xfs_dir2_data_log_header(
  */
 void
 xfs_dir2_data_log_unused(
-       xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_dabuf_t             *bp,            /* block buffer */
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp,
        xfs_dir2_data_unused_t  *dup)           /* data unused pointer */
 {
-       xfs_dir2_data_hdr_t     *hdr = bp->data;
+       xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
 
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
@@ -496,13 +496,13 @@ xfs_dir2_data_log_unused(
        /*
         * Log the first part of the unused entry.
         */
-       xfs_da_log_buf(tp, bp, (uint)((char *)dup - (char *)hdr),
+       xfs_trans_log_buf(tp, bp, (uint)((char *)dup - (char *)hdr),
                (uint)((char *)&dup->length + sizeof(dup->length) -
                       1 - (char *)hdr));
        /*
         * Log the end (tag) of the unused entry.
         */
-       xfs_da_log_buf(tp, bp,
+       xfs_trans_log_buf(tp, bp,
                (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr),
                (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr +
                       sizeof(xfs_dir2_data_off_t) - 1));
@@ -514,8 +514,8 @@ xfs_dir2_data_log_unused(
  */
 void
 xfs_dir2_data_make_free(
-       xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_dabuf_t             *bp,            /* block buffer */
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp,
        xfs_dir2_data_aoff_t    offset,         /* starting byte offset */
        xfs_dir2_data_aoff_t    len,            /* length in bytes */
        int                     *needlogp,      /* out: log header */
@@ -531,7 +531,7 @@ xfs_dir2_data_make_free(
        xfs_dir2_data_unused_t  *prevdup;       /* unused entry before us */
 
        mp = tp->t_mountp;
-       hdr = bp->data;
+       hdr = bp->b_addr;
 
        /*
         * Figure out where the end of the data area is.
@@ -696,8 +696,8 @@ xfs_dir2_data_make_free(
  */
 void
 xfs_dir2_data_use_free(
-       xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_dabuf_t             *bp,            /* data block buffer */
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp,
        xfs_dir2_data_unused_t  *dup,           /* unused entry */
        xfs_dir2_data_aoff_t    offset,         /* starting offset to use */
        xfs_dir2_data_aoff_t    len,            /* length to use */
@@ -713,7 +713,7 @@ xfs_dir2_data_use_free(
        xfs_dir2_data_unused_t  *newdup2;       /* another new unused entry */
        int                     oldlen;         /* old unused entry's length */
 
-       hdr = bp->data;
+       hdr = bp->b_addr;
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
        ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
index 397ffbcbab1dbc66fec4e65a418c20bd96808950..0b296253bd018d450f5773d6df3bdbcc03d55db5 100644 (file)
  * Local function declarations.
  */
 #ifdef DEBUG
-static void xfs_dir2_leaf_check(xfs_inode_t *dp, xfs_dabuf_t *bp);
+static void xfs_dir2_leaf_check(struct xfs_inode *dp, struct xfs_buf *bp);
 #else
 #define        xfs_dir2_leaf_check(dp, bp)
 #endif
-static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **lbpp,
-                                   int *indexp, xfs_dabuf_t **dbpp);
-static void xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp,
+static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, struct xfs_buf **lbpp,
+                                   int *indexp, struct xfs_buf **dbpp);
+static void xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_buf *bp,
                                    int first, int last);
-static void xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp);
+static void xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_buf *bp);
 
 
 /*
@@ -55,7 +55,7 @@ static void xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp);
 int                                            /* error */
 xfs_dir2_block_to_leaf(
        xfs_da_args_t           *args,          /* operation arguments */
-       xfs_dabuf_t             *dbp)           /* input block's buffer */
+       struct xfs_buf          *dbp)           /* input block's buffer */
 {
        __be16                  *bestsp;        /* leaf's bestsp entries */
        xfs_dablk_t             blkno;          /* leaf block's bno */
@@ -64,7 +64,7 @@ xfs_dir2_block_to_leaf(
        xfs_dir2_block_tail_t   *btp;           /* block's tail */
        xfs_inode_t             *dp;            /* incore directory inode */
        int                     error;          /* error return code */
-       xfs_dabuf_t             *lbp;           /* leaf block's buffer */
+       struct xfs_buf          *lbp;           /* leaf block's buffer */
        xfs_dir2_db_t           ldb;            /* leaf block's bno */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        xfs_dir2_leaf_tail_t    *ltp;           /* leaf's tail */
@@ -95,8 +95,8 @@ xfs_dir2_block_to_leaf(
                return error;
        }
        ASSERT(lbp != NULL);
-       leaf = lbp->data;
-       hdr = dbp->data;
+       leaf = lbp->b_addr;
+       hdr = dbp->b_addr;
        xfs_dir2_data_check(dp, dbp);
        btp = xfs_dir2_block_tail_p(mp, hdr);
        blp = xfs_dir2_block_leaf_p(btp);
@@ -143,7 +143,6 @@ xfs_dir2_block_to_leaf(
        xfs_dir2_leaf_check(dp, lbp);
        xfs_dir2_data_check(dp, dbp);
        xfs_dir2_leaf_log_bests(tp, lbp, 0, 0);
-       xfs_da_buf_done(lbp);
        return 0;
 }
 
@@ -282,7 +281,7 @@ xfs_dir2_leaf_addname(
        __be16                  *bestsp;        /* freespace table in leaf */
        int                     compact;        /* need to compact leaves */
        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
-       xfs_dabuf_t             *dbp;           /* data block buffer */
+       struct xfs_buf          *dbp;           /* data block buffer */
        xfs_dir2_data_entry_t   *dep;           /* data block entry */
        xfs_inode_t             *dp;            /* incore directory inode */
        xfs_dir2_data_unused_t  *dup;           /* data unused entry */
@@ -291,7 +290,7 @@ xfs_dir2_leaf_addname(
        int                     highstale;      /* index of next stale leaf */
        int                     i;              /* temporary, index */
        int                     index;          /* leaf table position */
-       xfs_dabuf_t             *lbp;           /* leaf's buffer */
+       struct xfs_buf          *lbp;           /* leaf's buffer */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        int                     length;         /* length of new entry */
        xfs_dir2_leaf_entry_t   *lep;           /* leaf entry table pointer */
@@ -328,7 +327,7 @@ xfs_dir2_leaf_addname(
         * But if there are dup hash values the index is of the first of those.
         */
        index = xfs_dir2_leaf_search_hash(args, lbp);
-       leaf = lbp->data;
+       leaf = lbp->b_addr;
        ltp = xfs_dir2_leaf_tail_p(mp, leaf);
        bestsp = xfs_dir2_leaf_bests_p(ltp);
        length = xfs_dir2_data_entsize(args->namelen);
@@ -402,14 +401,13 @@ xfs_dir2_leaf_addname(
                 */
                if ((args->op_flags & XFS_DA_OP_JUSTCHECK) ||
                                                        args->total == 0) {
-                       xfs_da_brelse(tp, lbp);
+                       xfs_trans_brelse(tp, lbp);
                        return XFS_ERROR(ENOSPC);
                }
                /*
                 * Convert to node form.
                 */
                error = xfs_dir2_leaf_to_node(args, lbp);
-               xfs_da_buf_done(lbp);
                if (error)
                        return error;
                /*
@@ -427,7 +425,7 @@ xfs_dir2_leaf_addname(
         * a new data block.
         */
        if (args->op_flags & XFS_DA_OP_JUSTCHECK) {
-               xfs_da_brelse(tp, lbp);
+               xfs_trans_brelse(tp, lbp);
                return use_block == -1 ? XFS_ERROR(ENOSPC) : 0;
        }
        /*
@@ -435,7 +433,7 @@ xfs_dir2_leaf_addname(
         * changed anything.
         */
        if (args->total == 0 && use_block == -1) {
-               xfs_da_brelse(tp, lbp);
+               xfs_trans_brelse(tp, lbp);
                return XFS_ERROR(ENOSPC);
        }
        /*
@@ -466,14 +464,14 @@ xfs_dir2_leaf_addname(
                 */
                if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE,
                                &use_block))) {
-                       xfs_da_brelse(tp, lbp);
+                       xfs_trans_brelse(tp, lbp);
                        return error;
                }
                /*
                 * Initialize the block.
                 */
                if ((error = xfs_dir2_data_init(args, use_block, &dbp))) {
-                       xfs_da_brelse(tp, lbp);
+                       xfs_trans_brelse(tp, lbp);
                        return error;
                }
                /*
@@ -493,7 +491,7 @@ xfs_dir2_leaf_addname(
                 */
                else
                        xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block);
-               hdr = dbp->data;
+               hdr = dbp->b_addr;
                bestsp[use_block] = hdr->bestfree[0].length;
                grown = 1;
        }
@@ -505,10 +503,10 @@ xfs_dir2_leaf_addname(
                if ((error =
                    xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, use_block),
                            -1, &dbp, XFS_DATA_FORK))) {
-                       xfs_da_brelse(tp, lbp);
+                       xfs_trans_brelse(tp, lbp);
                        return error;
                }
-               hdr = dbp->data;
+               hdr = dbp->b_addr;
                grown = 0;
        }
        xfs_dir2_data_check(dp, dbp);
@@ -570,9 +568,7 @@ xfs_dir2_leaf_addname(
        xfs_dir2_leaf_log_header(tp, lbp);
        xfs_dir2_leaf_log_ents(tp, lbp, lfloglow, lfloghigh);
        xfs_dir2_leaf_check(dp, lbp);
-       xfs_da_buf_done(lbp);
        xfs_dir2_data_check(dp, dbp);
-       xfs_da_buf_done(dbp);
        return 0;
 }
 
@@ -583,8 +579,8 @@ xfs_dir2_leaf_addname(
  */
 STATIC void
 xfs_dir2_leaf_check(
-       xfs_inode_t             *dp,            /* incore directory inode */
-       xfs_dabuf_t             *bp)            /* leaf's buffer */
+       struct xfs_inode        *dp,            /* incore directory inode */
+       struct xfs_buf          *bp)            /* leaf's buffer */
 {
        int                     i;              /* leaf index */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
@@ -592,7 +588,7 @@ xfs_dir2_leaf_check(
        xfs_mount_t             *mp;            /* filesystem mount point */
        int                     stale;          /* count of stale leaves */
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        mp = dp->i_mount;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC));
        /*
@@ -628,14 +624,14 @@ xfs_dir2_leaf_check(
 void
 xfs_dir2_leaf_compact(
        xfs_da_args_t   *args,          /* operation arguments */
-       xfs_dabuf_t     *bp)            /* leaf buffer */
+       struct xfs_buf  *bp)            /* leaf buffer */
 {
        int             from;           /* source leaf index */
        xfs_dir2_leaf_t *leaf;          /* leaf structure */
        int             loglow;         /* first leaf entry to log */
        int             to;             /* target leaf index */
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        if (!leaf->hdr.stale) {
                return;
        }
@@ -677,7 +673,7 @@ xfs_dir2_leaf_compact(
  */
 void
 xfs_dir2_leaf_compact_x1(
-       xfs_dabuf_t     *bp,            /* leaf buffer */
+       struct xfs_buf  *bp,            /* leaf buffer */
        int             *indexp,        /* insertion index */
        int             *lowstalep,     /* out: stale entry before us */
        int             *highstalep,    /* out: stale entry after us */
@@ -693,7 +689,7 @@ xfs_dir2_leaf_compact_x1(
        int             newindex=0;     /* new insertion index */
        int             to;             /* destination copy index */
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(be16_to_cpu(leaf->hdr.stale) > 1);
        index = *indexp;
 
@@ -763,6 +759,218 @@ xfs_dir2_leaf_compact_x1(
        *highstalep = highstale;
 }
 
+struct xfs_dir2_leaf_map_info {
+       xfs_extlen_t    map_blocks;     /* number of fsbs in map */
+       xfs_dablk_t     map_off;        /* last mapped file offset */
+       int             map_size;       /* total entries in *map */
+       int             map_valid;      /* valid entries in *map */
+       int             nmap;           /* mappings to ask xfs_bmapi */
+       xfs_dir2_db_t   curdb;          /* db for current block */
+       int             ra_current;     /* number of read-ahead blks */
+       int             ra_index;       /* *map index for read-ahead */
+       int             ra_offset;      /* map entry offset for ra */
+       int             ra_want;        /* readahead count wanted */
+       struct xfs_bmbt_irec map[];     /* map vector for blocks */
+};
+
+STATIC int
+xfs_dir2_leaf_readbuf(
+       struct xfs_inode        *dp,
+       size_t                  bufsize,
+       struct xfs_dir2_leaf_map_info *mip,
+       xfs_dir2_off_t          *curoff,
+       struct xfs_buf          **bpp)
+{
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_buf          *bp = *bpp;
+       struct xfs_bmbt_irec    *map = mip->map;
+       int                     error = 0;
+       int                     length;
+       int                     i;
+       int                     j;
+
+       /*
+        * If we have a buffer, we need to release it and
+        * take it out of the mapping.
+        */
+
+       if (bp) {
+               xfs_trans_brelse(NULL, bp);
+               bp = NULL;
+               mip->map_blocks -= mp->m_dirblkfsbs;
+               /*
+                * Loop to get rid of the extents for the
+                * directory block.
+                */
+               for (i = mp->m_dirblkfsbs; i > 0; ) {
+                       j = min_t(int, map->br_blockcount, i);
+                       map->br_blockcount -= j;
+                       map->br_startblock += j;
+                       map->br_startoff += j;
+                       /*
+                        * If mapping is done, pitch it from
+                        * the table.
+                        */
+                       if (!map->br_blockcount && --mip->map_valid)
+                               memmove(&map[0], &map[1],
+                                       sizeof(map[0]) * mip->map_valid);
+                       i -= j;
+               }
+       }
+
+       /*
+        * Recalculate the readahead blocks wanted.
+        */
+       mip->ra_want = howmany(bufsize + mp->m_dirblksize,
+                              mp->m_sb.sb_blocksize) - 1;
+       ASSERT(mip->ra_want >= 0);
+
+       /*
+        * If we don't have as many as we want, and we haven't
+        * run out of data blocks, get some more mappings.
+        */
+       if (1 + mip->ra_want > mip->map_blocks &&
+           mip->map_off < xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) {
+               /*
+                * Get more bmaps, fill in after the ones
+                * we already have in the table.
+                */
+               mip->nmap = mip->map_size - mip->map_valid;
+               error = xfs_bmapi_read(dp, mip->map_off,
+                               xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET) -
+                                                               mip->map_off,
+                               &map[mip->map_valid], &mip->nmap, 0);
+
+               /*
+                * Don't know if we should ignore this or try to return an
+                * error.  The trouble with returning errors is that readdir
+                * will just stop without actually passing the error through.
+                */
+               if (error)
+                       goto out;       /* XXX */
+
+               /*
+                * If we got all the mappings we asked for, set the final map
+                * offset based on the last bmap value received.  Otherwise,
+                * we've reached the end.
+                */
+               if (mip->nmap == mip->map_size - mip->map_valid) {
+                       i = mip->map_valid + mip->nmap - 1;
+                       mip->map_off = map[i].br_startoff + map[i].br_blockcount;
+               } else
+                       mip->map_off = xfs_dir2_byte_to_da(mp,
+                                                       XFS_DIR2_LEAF_OFFSET);
+
+               /*
+                * Look for holes in the mapping, and eliminate them.  Count up
+                * the valid blocks.
+                */
+               for (i = mip->map_valid; i < mip->map_valid + mip->nmap; ) {
+                       if (map[i].br_startblock == HOLESTARTBLOCK) {
+                               mip->nmap--;
+                               length = mip->map_valid + mip->nmap - i;
+                               if (length)
+                                       memmove(&map[i], &map[i + 1],
+                                               sizeof(map[i]) * length);
+                       } else {
+                               mip->map_blocks += map[i].br_blockcount;
+                               i++;
+                       }
+               }
+               mip->map_valid += mip->nmap;
+       }
+
+       /*
+        * No valid mappings, so no more data blocks.
+        */
+       if (!mip->map_valid) {
+               *curoff = xfs_dir2_da_to_byte(mp, mip->map_off);
+               goto out;
+       }
+
+       /*
+        * Read the directory block starting at the first mapping.
+        */
+       mip->curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
+       error = xfs_da_read_buf(NULL, dp, map->br_startoff,
+                       map->br_blockcount >= mp->m_dirblkfsbs ?
+                           XFS_FSB_TO_DADDR(mp, map->br_startblock) : -1,
+                       &bp, XFS_DATA_FORK);
+
+       /*
+        * Should just skip over the data block instead of giving up.
+        */
+       if (error)
+               goto out;       /* XXX */
+
+       /*
+        * Adjust the current amount of read-ahead: we just read a block that
+        * was previously ra.
+        */
+       if (mip->ra_current)
+               mip->ra_current -= mp->m_dirblkfsbs;
+
+       /*
+        * Do we need more readahead?
+        */
+       for (mip->ra_index = mip->ra_offset = i = 0;
+            mip->ra_want > mip->ra_current && i < mip->map_blocks;
+            i += mp->m_dirblkfsbs) {
+               ASSERT(mip->ra_index < mip->map_valid);
+               /*
+                * Read-ahead a contiguous directory block.
+                */
+               if (i > mip->ra_current &&
+                   map[mip->ra_index].br_blockcount >= mp->m_dirblkfsbs) {
+                       xfs_buf_readahead(mp->m_ddev_targp,
+                               XFS_FSB_TO_DADDR(mp,
+                                       map[mip->ra_index].br_startblock +
+                                                       mip->ra_offset),
+                               (int)BTOBB(mp->m_dirblksize));
+                       mip->ra_current = i;
+               }
+
+               /*
+                * Read-ahead a non-contiguous directory block.  This doesn't
+                * use our mapping, but this is a very rare case.
+                */
+               else if (i > mip->ra_current) {
+                       xfs_da_reada_buf(NULL, dp,
+                                       map[mip->ra_index].br_startoff +
+                                                       mip->ra_offset,
+                                       XFS_DATA_FORK);
+                       mip->ra_current = i;
+               }
+
+               /*
+                * Advance offset through the mapping table.
+                */
+               for (j = 0; j < mp->m_dirblkfsbs; j++) {
+                       /*
+                        * The rest of this extent but not more than a dir
+                        * block.
+                        */
+                       length = min_t(int, mp->m_dirblkfsbs,
+                                       map[mip->ra_index].br_blockcount -
+                                                       mip->ra_offset);
+                       j += length;
+                       mip->ra_offset += length;
+
+                       /*
+                        * Advance to the next mapping if this one is used up.
+                        */
+                       if (mip->ra_offset == map[mip->ra_index].br_blockcount) {
+                               mip->ra_offset = 0;
+                               mip->ra_index++;
+                       }
+               }
+       }
+
+out:
+       *bpp = bp;
+       return error;
+}
+
 /*
  * Getdents (readdir) for leaf and node directories.
  * This reads the data blocks only, so is the same for both forms.
@@ -775,30 +983,18 @@ xfs_dir2_leaf_getdents(
        xfs_off_t               *offset,
        filldir_t               filldir)
 {
-       xfs_dabuf_t             *bp;            /* data block buffer */
-       int                     byteoff;        /* offset in current block */
-       xfs_dir2_db_t           curdb;          /* db for current block */
-       xfs_dir2_off_t          curoff;         /* current overall offset */
+       struct xfs_buf          *bp = NULL;     /* data block buffer */
        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
        xfs_dir2_data_entry_t   *dep;           /* data entry */
        xfs_dir2_data_unused_t  *dup;           /* unused entry */
        int                     error = 0;      /* error return value */
-       int                     i;              /* temporary loop index */
-       int                     j;              /* temporary loop index */
        int                     length;         /* temporary length value */
-       xfs_bmbt_irec_t         *map;           /* map vector for blocks */
-       xfs_extlen_t            map_blocks;     /* number of fsbs in map */
-       xfs_dablk_t             map_off;        /* last mapped file offset */
-       int                     map_size;       /* total entries in *map */
-       int                     map_valid;      /* valid entries in *map */
        xfs_mount_t             *mp;            /* filesystem mount point */
+       int                     byteoff;        /* offset in current block */
+       xfs_dir2_off_t          curoff;         /* current overall offset */
        xfs_dir2_off_t          newoff;         /* new curoff after new blk */
-       int                     nmap;           /* mappings to ask xfs_bmapi */
        char                    *ptr = NULL;    /* pointer to current data */
-       int                     ra_current;     /* number of read-ahead blks */
-       int                     ra_index;       /* *map index for read-ahead */
-       int                     ra_offset;      /* map entry offset for ra */
-       int                     ra_want;        /* readahead count wanted */
+       struct xfs_dir2_leaf_map_info *map_info;
 
        /*
         * If the offset is at or past the largest allowed value,
@@ -814,10 +1010,12 @@ xfs_dir2_leaf_getdents(
         * buffer size, the directory block size, and the filesystem
         * block size.
         */
-       map_size = howmany(bufsize + mp->m_dirblksize, mp->m_sb.sb_blocksize);
-       map = kmem_alloc(map_size * sizeof(*map), KM_SLEEP);
-       map_valid = ra_index = ra_offset = ra_current = map_blocks = 0;
-       bp = NULL;
+       length = howmany(bufsize + mp->m_dirblksize,
+                                    mp->m_sb.sb_blocksize);
+       map_info = kmem_zalloc(offsetof(struct xfs_dir2_leaf_map_info, map) +
+                               (length * sizeof(struct xfs_bmbt_irec)),
+                              KM_SLEEP);
+       map_info->map_size = length;
 
        /*
         * Inside the loop we keep the main offset value as a byte offset
@@ -829,7 +1027,9 @@ xfs_dir2_leaf_getdents(
         * Force this conversion through db so we truncate the offset
         * down to get the start of the data block.
         */
-       map_off = xfs_dir2_db_to_da(mp, xfs_dir2_byte_to_db(mp, curoff));
+       map_info->map_off = xfs_dir2_db_to_da(mp,
+                                             xfs_dir2_byte_to_db(mp, curoff));
+
        /*
         * Loop over directory entries until we reach the end offset.
         * Get more blocks and readahead as necessary.
@@ -839,191 +1039,17 @@ xfs_dir2_leaf_getdents(
                 * If we have no buffer, or we're off the end of the
                 * current buffer, need to get another one.
                 */
-               if (!bp || ptr >= (char *)bp->data + mp->m_dirblksize) {
-                       /*
-                        * If we have a buffer, we need to release it and
-                        * take it out of the mapping.
-                        */
-                       if (bp) {
-                               xfs_da_brelse(NULL, bp);
-                               bp = NULL;
-                               map_blocks -= mp->m_dirblkfsbs;
-                               /*
-                                * Loop to get rid of the extents for the
-                                * directory block.
-                                */
-                               for (i = mp->m_dirblkfsbs; i > 0; ) {
-                                       j = MIN((int)map->br_blockcount, i);
-                                       map->br_blockcount -= j;
-                                       map->br_startblock += j;
-                                       map->br_startoff += j;
-                                       /*
-                                        * If mapping is done, pitch it from
-                                        * the table.
-                                        */
-                                       if (!map->br_blockcount && --map_valid)
-                                               memmove(&map[0], &map[1],
-                                                       sizeof(map[0]) *
-                                                       map_valid);
-                                       i -= j;
-                               }
-                       }
-                       /*
-                        * Recalculate the readahead blocks wanted.
-                        */
-                       ra_want = howmany(bufsize + mp->m_dirblksize,
-                                         mp->m_sb.sb_blocksize) - 1;
-                       ASSERT(ra_want >= 0);
+               if (!bp || ptr >= (char *)bp->b_addr + mp->m_dirblksize) {
 
-                       /*
-                        * If we don't have as many as we want, and we haven't
-                        * run out of data blocks, get some more mappings.
-                        */
-                       if (1 + ra_want > map_blocks &&
-                           map_off <
-                           xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) {
-                               /*
-                                * Get more bmaps, fill in after the ones
-                                * we already have in the table.
-                                */
-                               nmap = map_size - map_valid;
-                               error = xfs_bmapi_read(dp, map_off,
-                                       xfs_dir2_byte_to_da(mp,
-                                               XFS_DIR2_LEAF_OFFSET) - map_off,
-                                       &map[map_valid], &nmap, 0);
-                               /*
-                                * Don't know if we should ignore this or
-                                * try to return an error.
-                                * The trouble with returning errors
-                                * is that readdir will just stop without
-                                * actually passing the error through.
-                                */
-                               if (error)
-                                       break;  /* XXX */
-                               /*
-                                * If we got all the mappings we asked for,
-                                * set the final map offset based on the
-                                * last bmap value received.
-                                * Otherwise, we've reached the end.
-                                */
-                               if (nmap == map_size - map_valid)
-                                       map_off =
-                                       map[map_valid + nmap - 1].br_startoff +
-                                       map[map_valid + nmap - 1].br_blockcount;
-                               else
-                                       map_off =
-                                               xfs_dir2_byte_to_da(mp,
-                                                       XFS_DIR2_LEAF_OFFSET);
-                               /*
-                                * Look for holes in the mapping, and
-                                * eliminate them.  Count up the valid blocks.
-                                */
-                               for (i = map_valid; i < map_valid + nmap; ) {
-                                       if (map[i].br_startblock ==
-                                           HOLESTARTBLOCK) {
-                                               nmap--;
-                                               length = map_valid + nmap - i;
-                                               if (length)
-                                                       memmove(&map[i],
-                                                               &map[i + 1],
-                                                               sizeof(map[i]) *
-                                                               length);
-                                       } else {
-                                               map_blocks +=
-                                                       map[i].br_blockcount;
-                                               i++;
-                                       }
-                               }
-                               map_valid += nmap;
-                       }
-                       /*
-                        * No valid mappings, so no more data blocks.
-                        */
-                       if (!map_valid) {
-                               curoff = xfs_dir2_da_to_byte(mp, map_off);
+                       error = xfs_dir2_leaf_readbuf(dp, bufsize, map_info,
+                                                     &curoff, &bp);
+                       if (error || !map_info->map_valid)
                                break;
-                       }
-                       /*
-                        * Read the directory block starting at the first
-                        * mapping.
-                        */
-                       curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
-                       error = xfs_da_read_buf(NULL, dp, map->br_startoff,
-                               map->br_blockcount >= mp->m_dirblkfsbs ?
-                                   XFS_FSB_TO_DADDR(mp, map->br_startblock) :
-                                   -1,
-                               &bp, XFS_DATA_FORK);
-                       /*
-                        * Should just skip over the data block instead
-                        * of giving up.
-                        */
-                       if (error)
-                               break;  /* XXX */
-                       /*
-                        * Adjust the current amount of read-ahead: we just
-                        * read a block that was previously ra.
-                        */
-                       if (ra_current)
-                               ra_current -= mp->m_dirblkfsbs;
-                       /*
-                        * Do we need more readahead?
-                        */
-                       for (ra_index = ra_offset = i = 0;
-                            ra_want > ra_current && i < map_blocks;
-                            i += mp->m_dirblkfsbs) {
-                               ASSERT(ra_index < map_valid);
-                               /*
-                                * Read-ahead a contiguous directory block.
-                                */
-                               if (i > ra_current &&
-                                   map[ra_index].br_blockcount >=
-                                   mp->m_dirblkfsbs) {
-                                       xfs_buf_readahead(mp->m_ddev_targp,
-                                               XFS_FSB_TO_DADDR(mp,
-                                                  map[ra_index].br_startblock +
-                                                  ra_offset),
-                                               (int)BTOBB(mp->m_dirblksize));
-                                       ra_current = i;
-                               }
-                               /*
-                                * Read-ahead a non-contiguous directory block.
-                                * This doesn't use our mapping, but this
-                                * is a very rare case.
-                                */
-                               else if (i > ra_current) {
-                                       (void)xfs_da_reada_buf(NULL, dp,
-                                               map[ra_index].br_startoff +
-                                               ra_offset, XFS_DATA_FORK);
-                                       ra_current = i;
-                               }
-                               /*
-                                * Advance offset through the mapping table.
-                                */
-                               for (j = 0; j < mp->m_dirblkfsbs; j++) {
-                                       /*
-                                        * The rest of this extent but not
-                                        * more than a dir block.
-                                        */
-                                       length = MIN(mp->m_dirblkfsbs,
-                                               (int)(map[ra_index].br_blockcount -
-                                               ra_offset));
-                                       j += length;
-                                       ra_offset += length;
-                                       /*
-                                        * Advance to the next mapping if
-                                        * this one is used up.
-                                        */
-                                       if (ra_offset ==
-                                           map[ra_index].br_blockcount) {
-                                               ra_offset = 0;
-                                               ra_index++;
-                                       }
-                               }
-                       }
+
                        /*
                         * Having done a read, we need to set a new offset.
                         */
-                       newoff = xfs_dir2_db_off_to_byte(mp, curdb, 0);
+                       newoff = xfs_dir2_db_off_to_byte(mp, map_info->curdb, 0);
                        /*
                         * Start of the current block.
                         */
@@ -1034,8 +1060,8 @@ xfs_dir2_leaf_getdents(
                         */
                        else if (curoff > newoff)
                                ASSERT(xfs_dir2_byte_to_db(mp, curoff) ==
-                                      curdb);
-                       hdr = bp->data;
+                                      map_info->curdb);
+                       hdr = bp->b_addr;
                        xfs_dir2_data_check(dp, bp);
                        /*
                         * Find our position in the block.
@@ -1117,9 +1143,9 @@ xfs_dir2_leaf_getdents(
                *offset = XFS_DIR2_MAX_DATAPTR & 0x7fffffff;
        else
                *offset = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
-       kmem_free(map);
+       kmem_free(map_info);
        if (bp)
-               xfs_da_brelse(NULL, bp);
+               xfs_trans_brelse(NULL, bp);
        return error;
 }
 
@@ -1130,10 +1156,10 @@ int
 xfs_dir2_leaf_init(
        xfs_da_args_t           *args,          /* operation arguments */
        xfs_dir2_db_t           bno,            /* directory block number */
-       xfs_dabuf_t             **bpp,          /* out: leaf buffer */
+       struct xfs_buf          **bpp,          /* out: leaf buffer */
        int                     magic)          /* magic number for block */
 {
-       xfs_dabuf_t             *bp;            /* leaf buffer */
+       struct xfs_buf          *bp;            /* leaf buffer */
        xfs_inode_t             *dp;            /* incore directory inode */
        int                     error;          /* error return code */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
@@ -1156,7 +1182,7 @@ xfs_dir2_leaf_init(
                return error;
        }
        ASSERT(bp != NULL);
-       leaf = bp->data;
+       leaf = bp->b_addr;
        /*
         * Initialize the header.
         */
@@ -1186,7 +1212,7 @@ xfs_dir2_leaf_init(
 static void
 xfs_dir2_leaf_log_bests(
        xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_dabuf_t             *bp,            /* leaf buffer */
+       struct xfs_buf          *bp,            /* leaf buffer */
        int                     first,          /* first entry to log */
        int                     last)           /* last entry to log */
 {
@@ -1195,12 +1221,12 @@ xfs_dir2_leaf_log_bests(
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        xfs_dir2_leaf_tail_t    *ltp;           /* leaf tail structure */
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC));
        ltp = xfs_dir2_leaf_tail_p(tp->t_mountp, leaf);
        firstb = xfs_dir2_leaf_bests_p(ltp) + first;
        lastb = xfs_dir2_leaf_bests_p(ltp) + last;
-       xfs_da_log_buf(tp, bp, (uint)((char *)firstb - (char *)leaf),
+       xfs_trans_log_buf(tp, bp, (uint)((char *)firstb - (char *)leaf),
                (uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1));
 }
 
@@ -1210,7 +1236,7 @@ xfs_dir2_leaf_log_bests(
 void
 xfs_dir2_leaf_log_ents(
        xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_dabuf_t             *bp,            /* leaf buffer */
+       struct xfs_buf          *bp,            /* leaf buffer */
        int                     first,          /* first entry to log */
        int                     last)           /* last entry to log */
 {
@@ -1218,12 +1244,12 @@ xfs_dir2_leaf_log_ents(
        xfs_dir2_leaf_entry_t   *lastlep;       /* pointer to last entry */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) ||
               leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
        firstlep = &leaf->ents[first];
        lastlep = &leaf->ents[last];
-       xfs_da_log_buf(tp, bp, (uint)((char *)firstlep - (char *)leaf),
+       xfs_trans_log_buf(tp, bp, (uint)((char *)firstlep - (char *)leaf),
                (uint)((char *)lastlep - (char *)leaf + sizeof(*lastlep) - 1));
 }
 
@@ -1232,15 +1258,15 @@ xfs_dir2_leaf_log_ents(
  */
 void
 xfs_dir2_leaf_log_header(
-       xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_dabuf_t             *bp)            /* leaf buffer */
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp)
 {
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) ||
               leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
-       xfs_da_log_buf(tp, bp, (uint)((char *)&leaf->hdr - (char *)leaf),
+       xfs_trans_log_buf(tp, bp, (uint)((char *)&leaf->hdr - (char *)leaf),
                (uint)(sizeof(leaf->hdr) - 1));
 }
 
@@ -1249,18 +1275,18 @@ xfs_dir2_leaf_log_header(
  */
 STATIC void
 xfs_dir2_leaf_log_tail(
-       xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_dabuf_t             *bp)            /* leaf buffer */
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp)
 {
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        xfs_dir2_leaf_tail_t    *ltp;           /* leaf tail structure */
        xfs_mount_t             *mp;            /* filesystem mount point */
 
        mp = tp->t_mountp;
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC));
        ltp = xfs_dir2_leaf_tail_p(mp, leaf);
-       xfs_da_log_buf(tp, bp, (uint)((char *)ltp - (char *)leaf),
+       xfs_trans_log_buf(tp, bp, (uint)((char *)ltp - (char *)leaf),
                (uint)(mp->m_dirblksize - 1));
 }
 
@@ -1273,12 +1299,12 @@ int
 xfs_dir2_leaf_lookup(
        xfs_da_args_t           *args)          /* operation arguments */
 {
-       xfs_dabuf_t             *dbp;           /* data block buffer */
+       struct xfs_buf          *dbp;           /* data block buffer */
        xfs_dir2_data_entry_t   *dep;           /* data block entry */
        xfs_inode_t             *dp;            /* incore directory inode */
        int                     error;          /* error return code */
        int                     index;          /* found entry index */
-       xfs_dabuf_t             *lbp;           /* leaf buffer */
+       struct xfs_buf          *lbp;           /* leaf buffer */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        xfs_dir2_leaf_entry_t   *lep;           /* leaf entry */
        xfs_trans_t             *tp;            /* transaction pointer */
@@ -1294,7 +1320,7 @@ xfs_dir2_leaf_lookup(
        tp = args->trans;
        dp = args->dp;
        xfs_dir2_leaf_check(dp, lbp);
-       leaf = lbp->data;
+       leaf = lbp->b_addr;
        /*
         * Get to the leaf entry and contained data entry address.
         */
@@ -1303,15 +1329,15 @@ xfs_dir2_leaf_lookup(
         * Point to the data entry.
         */
        dep = (xfs_dir2_data_entry_t *)
-             ((char *)dbp->data +
+             ((char *)dbp->b_addr +
               xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address)));
        /*
         * Return the found inode number & CI name if appropriate
         */
        args->inumber = be64_to_cpu(dep->inumber);
        error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
-       xfs_da_brelse(tp, dbp);
-       xfs_da_brelse(tp, lbp);
+       xfs_trans_brelse(tp, dbp);
+       xfs_trans_brelse(tp, lbp);
        return XFS_ERROR(error);
 }
 
@@ -1324,17 +1350,17 @@ xfs_dir2_leaf_lookup(
 static int                                     /* error */
 xfs_dir2_leaf_lookup_int(
        xfs_da_args_t           *args,          /* operation arguments */
-       xfs_dabuf_t             **lbpp,         /* out: leaf buffer */
+       struct xfs_buf          **lbpp,         /* out: leaf buffer */
        int                     *indexp,        /* out: index in leaf block */
-       xfs_dabuf_t             **dbpp)         /* out: data buffer */
+       struct xfs_buf          **dbpp)         /* out: data buffer */
 {
        xfs_dir2_db_t           curdb = -1;     /* current data block number */
-       xfs_dabuf_t             *dbp = NULL;    /* data buffer */
+       struct xfs_buf          *dbp = NULL;    /* data buffer */
        xfs_dir2_data_entry_t   *dep;           /* data entry */
        xfs_inode_t             *dp;            /* incore directory inode */
        int                     error;          /* error return code */
        int                     index;          /* index in leaf block */
-       xfs_dabuf_t             *lbp;           /* leaf buffer */
+       struct xfs_buf          *lbp;           /* leaf buffer */
        xfs_dir2_leaf_entry_t   *lep;           /* leaf entry */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        xfs_mount_t             *mp;            /* filesystem mount point */
@@ -1354,7 +1380,7 @@ xfs_dir2_leaf_lookup_int(
        if (error)
                return error;
        *lbpp = lbp;
-       leaf = lbp->data;
+       leaf = lbp->b_addr;
        xfs_dir2_leaf_check(dp, lbp);
        /*
         * Look for the first leaf entry with our hash value.
@@ -1382,12 +1408,12 @@ xfs_dir2_leaf_lookup_int(
                 */
                if (newdb != curdb) {
                        if (dbp)
-                               xfs_da_brelse(tp, dbp);
+                               xfs_trans_brelse(tp, dbp);
                        error = xfs_da_read_buf(tp, dp,
                                                xfs_dir2_db_to_da(mp, newdb),
                                                -1, &dbp, XFS_DATA_FORK);
                        if (error) {
-                               xfs_da_brelse(tp, lbp);
+                               xfs_trans_brelse(tp, lbp);
                                return error;
                        }
                        xfs_dir2_data_check(dp, dbp);
@@ -1396,7 +1422,7 @@ xfs_dir2_leaf_lookup_int(
                /*
                 * Point to the data entry.
                 */
-               dep = (xfs_dir2_data_entry_t *)((char *)dbp->data +
+               dep = (xfs_dir2_data_entry_t *)((char *)dbp->b_addr +
                        xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
                /*
                 * Compare name and if it's an exact match, return the index
@@ -1424,12 +1450,12 @@ xfs_dir2_leaf_lookup_int(
        if (args->cmpresult == XFS_CMP_CASE) {
                ASSERT(cidb != -1);
                if (cidb != curdb) {
-                       xfs_da_brelse(tp, dbp);
+                       xfs_trans_brelse(tp, dbp);
                        error = xfs_da_read_buf(tp, dp,
                                                xfs_dir2_db_to_da(mp, cidb),
                                                -1, &dbp, XFS_DATA_FORK);
                        if (error) {
-                               xfs_da_brelse(tp, lbp);
+                               xfs_trans_brelse(tp, lbp);
                                return error;
                        }
                }
@@ -1441,8 +1467,8 @@ xfs_dir2_leaf_lookup_int(
         */
        ASSERT(cidb == -1);
        if (dbp)
-               xfs_da_brelse(tp, dbp);
-       xfs_da_brelse(tp, lbp);
+               xfs_trans_brelse(tp, dbp);
+       xfs_trans_brelse(tp, lbp);
        return XFS_ERROR(ENOENT);
 }
 
@@ -1456,13 +1482,13 @@ xfs_dir2_leaf_removename(
        __be16                  *bestsp;        /* leaf block best freespace */
        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
        xfs_dir2_db_t           db;             /* data block number */
-       xfs_dabuf_t             *dbp;           /* data block buffer */
+       struct xfs_buf          *dbp;           /* data block buffer */
        xfs_dir2_data_entry_t   *dep;           /* data entry structure */
        xfs_inode_t             *dp;            /* incore directory inode */
        int                     error;          /* error return code */
        xfs_dir2_db_t           i;              /* temporary data block # */
        int                     index;          /* index into leaf entries */
-       xfs_dabuf_t             *lbp;           /* leaf buffer */
+       struct xfs_buf          *lbp;           /* leaf buffer */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        xfs_dir2_leaf_entry_t   *lep;           /* leaf entry */
        xfs_dir2_leaf_tail_t    *ltp;           /* leaf tail structure */
@@ -1483,8 +1509,8 @@ xfs_dir2_leaf_removename(
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
-       leaf = lbp->data;
-       hdr = dbp->data;
+       leaf = lbp->b_addr;
+       hdr = dbp->b_addr;
        xfs_dir2_data_check(dp, dbp);
        /*
         * Point to the leaf entry, use that to point to the data entry.
@@ -1541,12 +1567,9 @@ xfs_dir2_leaf_removename(
                         * Just go on, returning success, leaving the
                         * empty block in place.
                         */
-                       if (error == ENOSPC && args->total == 0) {
-                               xfs_da_buf_done(dbp);
+                       if (error == ENOSPC && args->total == 0)
                                error = 0;
-                       }
                        xfs_dir2_leaf_check(dp, lbp);
-                       xfs_da_buf_done(lbp);
                        return error;
                }
                dbp = NULL;
@@ -1577,10 +1600,9 @@ xfs_dir2_leaf_removename(
        /*
         * If the data block was not the first one, drop it.
         */
-       else if (db != mp->m_dirdatablk && dbp != NULL) {
-               xfs_da_buf_done(dbp);
+       else if (db != mp->m_dirdatablk)
                dbp = NULL;
-       }
+
        xfs_dir2_leaf_check(dp, lbp);
        /*
         * See if we can convert to block form.
@@ -1595,12 +1617,12 @@ int                                             /* error */
 xfs_dir2_leaf_replace(
        xfs_da_args_t           *args)          /* operation arguments */
 {
-       xfs_dabuf_t             *dbp;           /* data block buffer */
+       struct xfs_buf          *dbp;           /* data block buffer */
        xfs_dir2_data_entry_t   *dep;           /* data block entry */
        xfs_inode_t             *dp;            /* incore directory inode */
        int                     error;          /* error return code */
        int                     index;          /* index of leaf entry */
-       xfs_dabuf_t             *lbp;           /* leaf buffer */
+       struct xfs_buf          *lbp;           /* leaf buffer */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        xfs_dir2_leaf_entry_t   *lep;           /* leaf entry */
        xfs_trans_t             *tp;            /* transaction pointer */
@@ -1614,7 +1636,7 @@ xfs_dir2_leaf_replace(
                return error;
        }
        dp = args->dp;
-       leaf = lbp->data;
+       leaf = lbp->b_addr;
        /*
         * Point to the leaf entry, get data address from it.
         */
@@ -1623,7 +1645,7 @@ xfs_dir2_leaf_replace(
         * Point to the data entry.
         */
        dep = (xfs_dir2_data_entry_t *)
-             ((char *)dbp->data +
+             ((char *)dbp->b_addr +
               xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address)));
        ASSERT(args->inumber != be64_to_cpu(dep->inumber));
        /*
@@ -1632,9 +1654,8 @@ xfs_dir2_leaf_replace(
        dep->inumber = cpu_to_be64(args->inumber);
        tp = args->trans;
        xfs_dir2_data_log_entry(tp, dbp, dep);
-       xfs_da_buf_done(dbp);
        xfs_dir2_leaf_check(dp, lbp);
-       xfs_da_brelse(tp, lbp);
+       xfs_trans_brelse(tp, lbp);
        return 0;
 }
 
@@ -1646,7 +1667,7 @@ xfs_dir2_leaf_replace(
 int                                            /* index value */
 xfs_dir2_leaf_search_hash(
        xfs_da_args_t           *args,          /* operation arguments */
-       xfs_dabuf_t             *lbp)           /* leaf buffer */
+       struct xfs_buf          *lbp)           /* leaf buffer */
 {
        xfs_dahash_t            hash=0;         /* hash from this entry */
        xfs_dahash_t            hashwant;       /* hash value looking for */
@@ -1656,7 +1677,7 @@ xfs_dir2_leaf_search_hash(
        xfs_dir2_leaf_entry_t   *lep;           /* leaf entry */
        int                     mid=0;          /* current leaf index */
 
-       leaf = lbp->data;
+       leaf = lbp->b_addr;
 #ifndef __KERNEL__
        if (!leaf->hdr.count)
                return 0;
@@ -1699,11 +1720,11 @@ xfs_dir2_leaf_search_hash(
 int                                            /* error */
 xfs_dir2_leaf_trim_data(
        xfs_da_args_t           *args,          /* operation arguments */
-       xfs_dabuf_t             *lbp,           /* leaf buffer */
+       struct xfs_buf          *lbp,           /* leaf buffer */
        xfs_dir2_db_t           db)             /* data block number */
 {
        __be16                  *bestsp;        /* leaf bests table */
-       xfs_dabuf_t             *dbp;           /* data block buffer */
+       struct xfs_buf          *dbp;           /* data block buffer */
        xfs_inode_t             *dp;            /* incore directory inode */
        int                     error;          /* error return value */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
@@ -1722,12 +1743,12 @@ xfs_dir2_leaf_trim_data(
                return error;
        }
 
-       leaf = lbp->data;
+       leaf = lbp->b_addr;
        ltp = xfs_dir2_leaf_tail_p(mp, leaf);
 
 #ifdef DEBUG
 {
-       struct xfs_dir2_data_hdr *hdr = dbp->data;
+       struct xfs_dir2_data_hdr *hdr = dbp->b_addr;
 
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC));
        ASSERT(be16_to_cpu(hdr->bestfree[0].length) ==
@@ -1741,7 +1762,7 @@ xfs_dir2_leaf_trim_data(
         */
        if ((error = xfs_dir2_shrink_inode(args, db, dbp))) {
                ASSERT(error != ENOSPC);
-               xfs_da_brelse(tp, dbp);
+               xfs_trans_brelse(tp, dbp);
                return error;
        }
        /*
@@ -1781,10 +1802,10 @@ xfs_dir2_node_to_leaf(
        xfs_da_args_t           *args;          /* operation arguments */
        xfs_inode_t             *dp;            /* incore directory inode */
        int                     error;          /* error return code */
-       xfs_dabuf_t             *fbp;           /* buffer for freespace block */
+       struct xfs_buf          *fbp;           /* buffer for freespace block */
        xfs_fileoff_t           fo;             /* freespace file offset */
        xfs_dir2_free_t         *free;          /* freespace structure */
-       xfs_dabuf_t             *lbp;           /* buffer for leaf block */
+       struct xfs_buf          *lbp;           /* buffer for leaf block */
        xfs_dir2_leaf_tail_t    *ltp;           /* tail of leaf structure */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
        xfs_mount_t             *mp;            /* filesystem mount point */
@@ -1838,7 +1859,7 @@ xfs_dir2_node_to_leaf(
        if (XFS_FSB_TO_B(mp, fo) > XFS_DIR2_LEAF_OFFSET + mp->m_dirblksize)
                return 0;
        lbp = state->path.blk[0].bp;
-       leaf = lbp->data;
+       leaf = lbp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
        /*
         * Read the freespace block.
@@ -1847,7 +1868,7 @@ xfs_dir2_node_to_leaf(
                        XFS_DATA_FORK))) {
                return error;
        }
-       free = fbp->data;
+       free = fbp->b_addr;
        ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));
        ASSERT(!free->hdr.firstdb);
 
@@ -1857,7 +1878,7 @@ xfs_dir2_node_to_leaf(
         */
        if (xfs_dir2_leaf_size(&leaf->hdr, be32_to_cpu(free->hdr.nvalid)) >
                        mp->m_dirblksize) {
-               xfs_da_brelse(tp, fbp);
+               xfs_trans_brelse(tp, fbp);
                return 0;
        }
 
index b0f26780449d5ebabca4d4b3b448a40728615e56..6c70524066051381f823d1043b857b5421a6490e 100644 (file)
 /*
  * Function declarations.
  */
-static void xfs_dir2_free_log_header(xfs_trans_t *tp, xfs_dabuf_t *bp);
-static int xfs_dir2_leafn_add(xfs_dabuf_t *bp, xfs_da_args_t *args, int index);
+static int xfs_dir2_leafn_add(struct xfs_buf *bp, xfs_da_args_t *args,
+                             int index);
 #ifdef DEBUG
-static void xfs_dir2_leafn_check(xfs_inode_t *dp, xfs_dabuf_t *bp);
+static void xfs_dir2_leafn_check(struct xfs_inode *dp, struct xfs_buf *bp);
 #else
 #define        xfs_dir2_leafn_check(dp, bp)
 #endif
-static void xfs_dir2_leafn_moveents(xfs_da_args_t *args, xfs_dabuf_t *bp_s,
-                                   int start_s, xfs_dabuf_t *bp_d, int start_d,
-                                   int count);
+static void xfs_dir2_leafn_moveents(xfs_da_args_t *args, struct xfs_buf *bp_s,
+                                   int start_s, struct xfs_buf *bp_d,
+                                   int start_d, int count);
 static void xfs_dir2_leafn_rebalance(xfs_da_state_t *state,
                                     xfs_da_state_blk_t *blk1,
                                     xfs_da_state_blk_t *blk2);
-static int xfs_dir2_leafn_remove(xfs_da_args_t *args, xfs_dabuf_t *bp,
+static int xfs_dir2_leafn_remove(xfs_da_args_t *args, struct xfs_buf *bp,
                                 int index, xfs_da_state_blk_t *dblk,
                                 int *rval);
 static int xfs_dir2_node_addname_int(xfs_da_args_t *args,
@@ -60,16 +60,16 @@ static int xfs_dir2_node_addname_int(xfs_da_args_t *args,
  */
 STATIC void
 xfs_dir2_free_log_bests(
-       xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_dabuf_t             *bp,            /* freespace buffer */
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp,
        int                     first,          /* first entry to log */
        int                     last)           /* last entry to log */
 {
        xfs_dir2_free_t         *free;          /* freespace structure */
 
-       free = bp->data;
+       free = bp->b_addr;
        ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));
-       xfs_da_log_buf(tp, bp,
+       xfs_trans_log_buf(tp, bp,
                (uint)((char *)&free->bests[first] - (char *)free),
                (uint)((char *)&free->bests[last] - (char *)free +
                       sizeof(free->bests[0]) - 1));
@@ -80,14 +80,14 @@ xfs_dir2_free_log_bests(
  */
 static void
 xfs_dir2_free_log_header(
-       xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_dabuf_t             *bp)            /* freespace buffer */
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp)
 {
        xfs_dir2_free_t         *free;          /* freespace structure */
 
-       free = bp->data;
+       free = bp->b_addr;
        ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));
-       xfs_da_log_buf(tp, bp, (uint)((char *)&free->hdr - (char *)free),
+       xfs_trans_log_buf(tp, bp, (uint)((char *)&free->hdr - (char *)free),
                (uint)(sizeof(xfs_dir2_free_hdr_t) - 1));
 }
 
@@ -99,11 +99,11 @@ xfs_dir2_free_log_header(
 int                                            /* error */
 xfs_dir2_leaf_to_node(
        xfs_da_args_t           *args,          /* operation arguments */
-       xfs_dabuf_t             *lbp)           /* leaf buffer */
+       struct xfs_buf          *lbp)           /* leaf buffer */
 {
        xfs_inode_t             *dp;            /* incore directory inode */
        int                     error;          /* error return value */
-       xfs_dabuf_t             *fbp;           /* freespace buffer */
+       struct xfs_buf          *fbp;           /* freespace buffer */
        xfs_dir2_db_t           fdb;            /* freespace block number */
        xfs_dir2_free_t         *free;          /* freespace structure */
        __be16                  *from;          /* pointer to freespace entry */
@@ -136,8 +136,8 @@ xfs_dir2_leaf_to_node(
                return error;
        }
        ASSERT(fbp != NULL);
-       free = fbp->data;
-       leaf = lbp->data;
+       free = fbp->b_addr;
+       leaf = lbp->b_addr;
        ltp = xfs_dir2_leaf_tail_p(mp, leaf);
        /*
         * Initialize the freespace block header.
@@ -164,7 +164,6 @@ xfs_dir2_leaf_to_node(
        xfs_dir2_leaf_log_header(tp, lbp);
        xfs_dir2_free_log_header(tp, fbp);
        xfs_dir2_free_log_bests(tp, fbp, 0, be32_to_cpu(free->hdr.nvalid) - 1);
-       xfs_da_buf_done(fbp);
        xfs_dir2_leafn_check(dp, lbp);
        return 0;
 }
@@ -175,7 +174,7 @@ xfs_dir2_leaf_to_node(
  */
 static int                                     /* error */
 xfs_dir2_leafn_add(
-       xfs_dabuf_t             *bp,            /* leaf buffer */
+       struct xfs_buf          *bp,            /* leaf buffer */
        xfs_da_args_t           *args,          /* operation arguments */
        int                     index)          /* insertion pt for new entry */
 {
@@ -195,7 +194,7 @@ xfs_dir2_leafn_add(
        dp = args->dp;
        mp = dp->i_mount;
        tp = args->trans;
-       leaf = bp->data;
+       leaf = bp->b_addr;
 
        /*
         * Quick check just to make sure we are not going to index
@@ -261,15 +260,15 @@ xfs_dir2_leafn_add(
  */
 void
 xfs_dir2_leafn_check(
-       xfs_inode_t     *dp,                    /* incore directory inode */
-       xfs_dabuf_t     *bp)                    /* leaf buffer */
+       struct xfs_inode *dp,
+       struct xfs_buf  *bp)
 {
        int             i;                      /* leaf index */
        xfs_dir2_leaf_t *leaf;                  /* leaf structure */
        xfs_mount_t     *mp;                    /* filesystem mount point */
        int             stale;                  /* count of stale leaves */
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        mp = dp->i_mount;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
        ASSERT(be16_to_cpu(leaf->hdr.count) <= xfs_dir2_max_leaf_ents(mp));
@@ -291,12 +290,12 @@ xfs_dir2_leafn_check(
  */
 xfs_dahash_t                                   /* hash value */
 xfs_dir2_leafn_lasthash(
-       xfs_dabuf_t     *bp,                    /* leaf buffer */
+       struct xfs_buf  *bp,                    /* leaf buffer */
        int             *count)                 /* count of entries in leaf */
 {
        xfs_dir2_leaf_t *leaf;                  /* leaf structure */
 
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
        if (count)
                *count = be16_to_cpu(leaf->hdr.count);
@@ -311,12 +310,12 @@ xfs_dir2_leafn_lasthash(
  */
 STATIC int
 xfs_dir2_leafn_lookup_for_addname(
-       xfs_dabuf_t             *bp,            /* leaf buffer */
+       struct xfs_buf          *bp,            /* leaf buffer */
        xfs_da_args_t           *args,          /* operation arguments */
        int                     *indexp,        /* out: leaf entry index */
        xfs_da_state_t          *state)         /* state to fill in */
 {
-       xfs_dabuf_t             *curbp = NULL;  /* current data/free buffer */
+       struct xfs_buf          *curbp = NULL;  /* current data/free buffer */
        xfs_dir2_db_t           curdb = -1;     /* current data block number */
        xfs_dir2_db_t           curfdb = -1;    /* current free block number */
        xfs_inode_t             *dp;            /* incore directory inode */
@@ -335,7 +334,7 @@ xfs_dir2_leafn_lookup_for_addname(
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
 #ifdef __KERNEL__
        ASSERT(be16_to_cpu(leaf->hdr.count) > 0);
@@ -352,7 +351,7 @@ xfs_dir2_leafn_lookup_for_addname(
                /* If so, it's a free block buffer, get the block number. */
                curbp = state->extrablk.bp;
                curfdb = state->extrablk.blkno;
-               free = curbp->data;
+               free = curbp->b_addr;
                ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));
        }
        length = xfs_dir2_data_entsize(args->namelen);
@@ -394,7 +393,7 @@ xfs_dir2_leafn_lookup_for_addname(
                                 * If we had one before, drop it.
                                 */
                                if (curbp)
-                                       xfs_da_brelse(tp, curbp);
+                                       xfs_trans_brelse(tp, curbp);
                                /*
                                 * Read the free block.
                                 */
@@ -403,7 +402,7 @@ xfs_dir2_leafn_lookup_for_addname(
                                                -1, &curbp, XFS_DATA_FORK);
                                if (error)
                                        return error;
-                               free = curbp->data;
+                               free = curbp->b_addr;
                                ASSERT(be32_to_cpu(free->hdr.magic) ==
                                        XFS_DIR2_FREE_MAGIC);
                                ASSERT((be32_to_cpu(free->hdr.firstdb) %
@@ -424,7 +423,7 @@ xfs_dir2_leafn_lookup_for_addname(
                                XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int",
                                                        XFS_ERRLEVEL_LOW, mp);
                                if (curfdb != newfdb)
-                                       xfs_da_brelse(tp, curbp);
+                                       xfs_trans_brelse(tp, curbp);
                                return XFS_ERROR(EFSCORRUPTED);
                        }
                        curfdb = newfdb;
@@ -459,12 +458,12 @@ out:
  */
 STATIC int
 xfs_dir2_leafn_lookup_for_entry(
-       xfs_dabuf_t             *bp,            /* leaf buffer */
+       struct xfs_buf          *bp,            /* leaf buffer */
        xfs_da_args_t           *args,          /* operation arguments */
        int                     *indexp,        /* out: leaf entry index */
        xfs_da_state_t          *state)         /* state to fill in */
 {
-       xfs_dabuf_t             *curbp = NULL;  /* current data/free buffer */
+       struct xfs_buf          *curbp = NULL;  /* current data/free buffer */
        xfs_dir2_db_t           curdb = -1;     /* current data block number */
        xfs_dir2_data_entry_t   *dep;           /* data block entry */
        xfs_inode_t             *dp;            /* incore directory inode */
@@ -480,7 +479,7 @@ xfs_dir2_leafn_lookup_for_entry(
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
 #ifdef __KERNEL__
        ASSERT(be16_to_cpu(leaf->hdr.count) > 0);
@@ -525,7 +524,7 @@ xfs_dir2_leafn_lookup_for_entry(
                         */
                        if (curbp && (args->cmpresult == XFS_CMP_DIFFERENT ||
                                                curdb != state->extrablk.blkno))
-                               xfs_da_brelse(tp, curbp);
+                               xfs_trans_brelse(tp, curbp);
                        /*
                         * If needing the block that is saved with a CI match,
                         * use it otherwise read in the new data block.
@@ -547,7 +546,7 @@ xfs_dir2_leafn_lookup_for_entry(
                /*
                 * Point to the data entry.
                 */
-               dep = (xfs_dir2_data_entry_t *)((char *)curbp->data +
+               dep = (xfs_dir2_data_entry_t *)((char *)curbp->b_addr +
                        xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
                /*
                 * Compare the entry and if it's an exact match, return
@@ -559,7 +558,7 @@ xfs_dir2_leafn_lookup_for_entry(
                        /* If there is a CI match block, drop it */
                        if (args->cmpresult != XFS_CMP_DIFFERENT &&
                                                curdb != state->extrablk.blkno)
-                               xfs_da_brelse(tp, state->extrablk.bp);
+                               xfs_trans_brelse(tp, state->extrablk.bp);
                        args->cmpresult = cmp;
                        args->inumber = be64_to_cpu(dep->inumber);
                        *indexp = index;
@@ -567,7 +566,7 @@ xfs_dir2_leafn_lookup_for_entry(
                        state->extrablk.bp = curbp;
                        state->extrablk.blkno = curdb;
                        state->extrablk.index = (int)((char *)dep -
-                                                       (char *)curbp->data);
+                                                       (char *)curbp->b_addr);
                        state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
                        if (cmp == XFS_CMP_EXACT)
                                return XFS_ERROR(EEXIST);
@@ -586,7 +585,7 @@ xfs_dir2_leafn_lookup_for_entry(
                } else {
                        /* If the curbp is not the CI match block, drop it */
                        if (state->extrablk.bp != curbp)
-                               xfs_da_brelse(tp, curbp);
+                               xfs_trans_brelse(tp, curbp);
                }
        } else {
                state->extravalid = 0;
@@ -602,7 +601,7 @@ xfs_dir2_leafn_lookup_for_entry(
  */
 int
 xfs_dir2_leafn_lookup_int(
-       xfs_dabuf_t             *bp,            /* leaf buffer */
+       struct xfs_buf          *bp,            /* leaf buffer */
        xfs_da_args_t           *args,          /* operation arguments */
        int                     *indexp,        /* out: leaf entry index */
        xfs_da_state_t          *state)         /* state to fill in */
@@ -620,9 +619,9 @@ xfs_dir2_leafn_lookup_int(
 static void
 xfs_dir2_leafn_moveents(
        xfs_da_args_t   *args,                  /* operation arguments */
-       xfs_dabuf_t     *bp_s,                  /* source leaf buffer */
+       struct xfs_buf  *bp_s,                  /* source leaf buffer */
        int             start_s,                /* source leaf index */
-       xfs_dabuf_t     *bp_d,                  /* destination leaf buffer */
+       struct xfs_buf  *bp_d,                  /* destination leaf buffer */
        int             start_d,                /* destination leaf index */
        int             count)                  /* count of leaves to copy */
 {
@@ -640,8 +639,8 @@ xfs_dir2_leafn_moveents(
                return;
        }
        tp = args->trans;
-       leaf_s = bp_s->data;
-       leaf_d = bp_d->data;
+       leaf_s = bp_s->b_addr;
+       leaf_d = bp_d->b_addr;
        /*
         * If the destination index is not the end of the current
         * destination leaf entries, open up a hole in the destination
@@ -702,14 +701,14 @@ xfs_dir2_leafn_moveents(
  */
 int                                            /* sort order */
 xfs_dir2_leafn_order(
-       xfs_dabuf_t     *leaf1_bp,              /* leaf1 buffer */
-       xfs_dabuf_t     *leaf2_bp)              /* leaf2 buffer */
+       struct xfs_buf  *leaf1_bp,              /* leaf1 buffer */
+       struct xfs_buf  *leaf2_bp)              /* leaf2 buffer */
 {
        xfs_dir2_leaf_t *leaf1;                 /* leaf1 structure */
        xfs_dir2_leaf_t *leaf2;                 /* leaf2 structure */
 
-       leaf1 = leaf1_bp->data;
-       leaf2 = leaf2_bp->data;
+       leaf1 = leaf1_bp->b_addr;
+       leaf2 = leaf2_bp->b_addr;
        ASSERT(leaf1->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
        ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
        if (be16_to_cpu(leaf1->hdr.count) > 0 &&
@@ -757,8 +756,8 @@ xfs_dir2_leafn_rebalance(
                blk1 = blk2;
                blk2 = tmp;
        }
-       leaf1 = blk1->bp->data;
-       leaf2 = blk2->bp->data;
+       leaf1 = blk1->bp->b_addr;
+       leaf2 = blk2->bp->b_addr;
        oldsum = be16_to_cpu(leaf1->hdr.count) + be16_to_cpu(leaf2->hdr.count);
 #ifdef DEBUG
        oldstale = be16_to_cpu(leaf1->hdr.stale) + be16_to_cpu(leaf2->hdr.stale);
@@ -834,14 +833,14 @@ xfs_dir2_leafn_rebalance(
 static int                                     /* error */
 xfs_dir2_leafn_remove(
        xfs_da_args_t           *args,          /* operation arguments */
-       xfs_dabuf_t             *bp,            /* leaf buffer */
+       struct xfs_buf          *bp,            /* leaf buffer */
        int                     index,          /* leaf entry index */
        xfs_da_state_blk_t      *dblk,          /* data block */
        int                     *rval)          /* resulting block needs join */
 {
        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
        xfs_dir2_db_t           db;             /* data block number */
-       xfs_dabuf_t             *dbp;           /* data block buffer */
+       struct xfs_buf          *dbp;           /* data block buffer */
        xfs_dir2_data_entry_t   *dep;           /* data block entry */
        xfs_inode_t             *dp;            /* incore directory inode */
        xfs_dir2_leaf_t         *leaf;          /* leaf structure */
@@ -858,7 +857,7 @@ xfs_dir2_leafn_remove(
        dp = args->dp;
        tp = args->trans;
        mp = dp->i_mount;
-       leaf = bp->data;
+       leaf = bp->b_addr;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
        /*
         * Point to the entry we're removing.
@@ -884,7 +883,7 @@ xfs_dir2_leafn_remove(
         * in the data block in case it changes.
         */
        dbp = dblk->bp;
-       hdr = dbp->data;
+       hdr = dbp->b_addr;
        dep = (xfs_dir2_data_entry_t *)((char *)hdr + off);
        longest = be16_to_cpu(hdr->bestfree[0].length);
        needlog = needscan = 0;
@@ -905,7 +904,7 @@ xfs_dir2_leafn_remove(
         */
        if (longest < be16_to_cpu(hdr->bestfree[0].length)) {
                int             error;          /* error return value */
-               xfs_dabuf_t     *fbp;           /* freeblock buffer */
+               struct xfs_buf  *fbp;           /* freeblock buffer */
                xfs_dir2_db_t   fdb;            /* freeblock block number */
                int             findex;         /* index in freeblock entries */
                xfs_dir2_free_t *free;          /* freeblock structure */
@@ -920,7 +919,7 @@ xfs_dir2_leafn_remove(
                                -1, &fbp, XFS_DATA_FORK))) {
                        return error;
                }
-               free = fbp->data;
+               free = fbp->b_addr;
                ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));
                ASSERT(be32_to_cpu(free->hdr.firstdb) ==
                       xfs_dir2_free_max_bests(mp) *
@@ -948,9 +947,7 @@ xfs_dir2_leafn_remove(
                         * In this case just drop the buffer and some one else
                         * will eventually get rid of the empty block.
                         */
-                       else if (error == ENOSPC && args->total == 0)
-                               xfs_da_buf_done(dbp);
-                       else
+                       else if (!(error == ENOSPC && args->total == 0))
                                return error;
                }
                /*
@@ -1018,11 +1015,6 @@ xfs_dir2_leafn_remove(
                 */
                if (logfree)
                        xfs_dir2_free_log_bests(tp, fbp, findex, findex);
-               /*
-                * Drop the buffer if we still have it.
-                */
-               if (fbp)
-                       xfs_da_buf_done(fbp);
        }
        xfs_dir2_leafn_check(dp, bp);
        /*
@@ -1114,7 +1106,7 @@ xfs_dir2_leafn_toosmall(
 {
        xfs_da_state_blk_t      *blk;           /* leaf block */
        xfs_dablk_t             blkno;          /* leaf block number */
-       xfs_dabuf_t             *bp;            /* leaf buffer */
+       struct xfs_buf          *bp;            /* leaf buffer */
        int                     bytes;          /* bytes in use */
        int                     count;          /* leaf live entry count */
        int                     error;          /* error return value */
@@ -1130,7 +1122,7 @@ xfs_dir2_leafn_toosmall(
         * to coalesce with a sibling.
         */
        blk = &state->path.blk[state->path.active - 1];
-       info = blk->bp->data;
+       info = blk->bp->b_addr;
        ASSERT(info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
        leaf = (xfs_dir2_leaf_t *)info;
        count = be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale);
@@ -1189,7 +1181,7 @@ xfs_dir2_leafn_toosmall(
                leaf = (xfs_dir2_leaf_t *)info;
                count = be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale);
                bytes = state->blocksize - (state->blocksize >> 2);
-               leaf = bp->data;
+               leaf = bp->b_addr;
                ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
                count += be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale);
                bytes -= count * (uint)sizeof(leaf->ents[0]);
@@ -1198,7 +1190,7 @@ xfs_dir2_leafn_toosmall(
                 */
                if (bytes >= 0)
                        break;
-               xfs_da_brelse(state->args->trans, bp);
+               xfs_trans_brelse(state->args->trans, bp);
        }
        /*
         * Didn't like either block, give up.
@@ -1207,11 +1199,7 @@ xfs_dir2_leafn_toosmall(
                *action = 0;
                return 0;
        }
-       /*
-        * Done with the sibling leaf block here, drop the dabuf
-        * so path_shift can get it.
-        */
-       xfs_da_buf_done(bp);
+
        /*
         * Make altpath point to the block we want to keep (the lower
         * numbered block) and path point to the block we want to drop.
@@ -1247,8 +1235,8 @@ xfs_dir2_leafn_unbalance(
        args = state->args;
        ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC);
        ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC);
-       drop_leaf = drop_blk->bp->data;
-       save_leaf = save_blk->bp->data;
+       drop_leaf = drop_blk->bp->b_addr;
+       save_leaf = save_blk->bp->b_addr;
        ASSERT(drop_leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
        ASSERT(save_leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
        /*
@@ -1356,13 +1344,13 @@ xfs_dir2_node_addname_int(
 {
        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
        xfs_dir2_db_t           dbno;           /* data block number */
-       xfs_dabuf_t             *dbp;           /* data block buffer */
+       struct xfs_buf          *dbp;           /* data block buffer */
        xfs_dir2_data_entry_t   *dep;           /* data entry pointer */
        xfs_inode_t             *dp;            /* incore directory inode */
        xfs_dir2_data_unused_t  *dup;           /* data unused entry pointer */
        int                     error;          /* error return value */
        xfs_dir2_db_t           fbno;           /* freespace block number */
-       xfs_dabuf_t             *fbp;           /* freespace buffer */
+       struct xfs_buf          *fbp;           /* freespace buffer */
        int                     findex;         /* freespace entry index */
        xfs_dir2_free_t         *free=NULL;     /* freespace block structure */
        xfs_dir2_db_t           ifbno;          /* initial freespace block no */
@@ -1390,7 +1378,7 @@ xfs_dir2_node_addname_int(
                 * Remember initial freespace block number.
                 */
                ifbno = fblk->blkno;
-               free = fbp->data;
+               free = fbp->b_addr;
                ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));
                findex = fblk->index;
                /*
@@ -1474,7 +1462,7 @@ xfs_dir2_node_addname_int(
                        if (unlikely(fbp == NULL)) {
                                continue;
                        }
-                       free = fbp->data;
+                       free = fbp->b_addr;
                        ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));
                        findex = 0;
                }
@@ -1492,7 +1480,7 @@ xfs_dir2_node_addname_int(
                                /*
                                 * Drop the block.
                                 */
-                               xfs_da_brelse(tp, fbp);
+                               xfs_trans_brelse(tp, fbp);
                                fbp = NULL;
                                if (fblk && fblk->bp)
                                        fblk->bp = NULL;
@@ -1507,36 +1495,23 @@ xfs_dir2_node_addname_int(
                /*
                 * Not allowed to allocate, return failure.
                 */
-               if ((args->op_flags & XFS_DA_OP_JUSTCHECK) ||
-                                                       args->total == 0) {
-                       /*
-                        * Drop the freespace buffer unless it came from our
-                        * caller.
-                        */
-                       if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)
-                               xfs_da_buf_done(fbp);
+               if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0)
                        return XFS_ERROR(ENOSPC);
-               }
+
                /*
                 * Allocate and initialize the new data block.
                 */
                if (unlikely((error = xfs_dir2_grow_inode(args,
                                                         XFS_DIR2_DATA_SPACE,
                                                         &dbno)) ||
-                   (error = xfs_dir2_data_init(args, dbno, &dbp)))) {
-                       /*
-                        * Drop the freespace buffer unless it came from our
-                        * caller.
-                        */
-                       if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)
-                               xfs_da_buf_done(fbp);
+                   (error = xfs_dir2_data_init(args, dbno, &dbp))))
                        return error;
-               }
+
                /*
                 * If (somehow) we have a freespace block, get rid of it.
                 */
                if (fbp)
-                       xfs_da_brelse(tp, fbp);
+                       xfs_trans_brelse(tp, fbp);
                if (fblk && fblk->bp)
                        fblk->bp = NULL;
 
@@ -1547,10 +1522,9 @@ xfs_dir2_node_addname_int(
                fbno = xfs_dir2_db_to_fdb(mp, dbno);
                if (unlikely(error = xfs_da_read_buf(tp, dp,
                                xfs_dir2_db_to_da(mp, fbno), -2, &fbp,
-                               XFS_DATA_FORK))) {
-                       xfs_da_buf_done(dbp);
+                               XFS_DATA_FORK)))
                        return error;
-               }
+
                /*
                 * If there wasn't a freespace block, the read will
                 * return a NULL fbp.  Allocate and initialize a new one.
@@ -1598,7 +1572,7 @@ xfs_dir2_node_addname_int(
                         * Initialize the new block to be empty, and remember
                         * its first slot as our empty slot.
                         */
-                       free = fbp->data;
+                       free = fbp->b_addr;
                        free->hdr.magic = cpu_to_be32(XFS_DIR2_FREE_MAGIC);
                        free->hdr.firstdb = cpu_to_be32(
                                (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) *
@@ -1606,7 +1580,7 @@ xfs_dir2_node_addname_int(
                        free->hdr.nvalid = 0;
                        free->hdr.nused = 0;
                } else {
-                       free = fbp->data;
+                       free = fbp->b_addr;
                        ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));
                }
 
@@ -1639,7 +1613,7 @@ xfs_dir2_node_addname_int(
                 * We haven't allocated the data entry yet so this will
                 * change again.
                 */
-               hdr = dbp->data;
+               hdr = dbp->b_addr;
                free->bests[findex] = hdr->bestfree[0].length;
                logfree = 1;
        }
@@ -1650,22 +1624,17 @@ xfs_dir2_node_addname_int(
                /*
                 * If just checking, we succeeded.
                 */
-               if (args->op_flags & XFS_DA_OP_JUSTCHECK) {
-                       if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)
-                               xfs_da_buf_done(fbp);
+               if (args->op_flags & XFS_DA_OP_JUSTCHECK)
                        return 0;
-               }
+
                /*
                 * Read the data block in.
                 */
-               if (unlikely(
-                   error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, dbno),
-                               -1, &dbp, XFS_DATA_FORK))) {
-                       if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)
-                               xfs_da_buf_done(fbp);
+               error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, dbno),
+                               -1, &dbp, XFS_DATA_FORK);
+               if (error)
                        return error;
-               }
-               hdr = dbp->data;
+               hdr = dbp->b_addr;
                logfree = 0;
        }
        ASSERT(be16_to_cpu(hdr->bestfree[0].length) >= length);
@@ -1713,17 +1682,11 @@ xfs_dir2_node_addname_int(
         */
        if (logfree)
                xfs_dir2_free_log_bests(tp, fbp, findex, findex);
-       /*
-        * If the caller didn't hand us the freespace block, drop it.
-        */
-       if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)
-               xfs_da_buf_done(fbp);
        /*
         * Return the data block and offset in args, then drop the data block.
         */
        args->blkno = (xfs_dablk_t)dbno;
        args->index = be16_to_cpu(*tagp);
-       xfs_da_buf_done(dbp);
        return 0;
 }
 
@@ -1761,22 +1724,23 @@ xfs_dir2_node_lookup(
                /* If a CI match, dup the actual name and return EEXIST */
                xfs_dir2_data_entry_t   *dep;
 
-               dep = (xfs_dir2_data_entry_t *)((char *)state->extrablk.bp->
-                                               data + state->extrablk.index);
+               dep = (xfs_dir2_data_entry_t *)
+                       ((char *)state->extrablk.bp->b_addr +
+                                                state->extrablk.index);
                rval = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
        }
        /*
         * Release the btree blocks and leaf block.
         */
        for (i = 0; i < state->path.active; i++) {
-               xfs_da_brelse(args->trans, state->path.blk[i].bp);
+               xfs_trans_brelse(args->trans, state->path.blk[i].bp);
                state->path.blk[i].bp = NULL;
        }
        /*
         * Release the data block if we have it.
         */
        if (state->extravalid && state->extrablk.bp) {
-               xfs_da_brelse(args->trans, state->extrablk.bp);
+               xfs_trans_brelse(args->trans, state->extrablk.bp);
                state->extrablk.bp = NULL;
        }
        xfs_da_state_free(state);
@@ -1893,13 +1857,13 @@ xfs_dir2_node_replace(
                 */
                blk = &state->path.blk[state->path.active - 1];
                ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC);
-               leaf = blk->bp->data;
+               leaf = blk->bp->b_addr;
                lep = &leaf->ents[blk->index];
                ASSERT(state->extravalid);
                /*
                 * Point to the data entry.
                 */
-               hdr = state->extrablk.bp->data;
+               hdr = state->extrablk.bp->b_addr;
                ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC));
                dep = (xfs_dir2_data_entry_t *)
                      ((char *)hdr +
@@ -1916,14 +1880,14 @@ xfs_dir2_node_replace(
         * Didn't find it, and we're holding a data block.  Drop it.
         */
        else if (state->extravalid) {
-               xfs_da_brelse(args->trans, state->extrablk.bp);
+               xfs_trans_brelse(args->trans, state->extrablk.bp);
                state->extrablk.bp = NULL;
        }
        /*
         * Release all the buffers in the cursor.
         */
        for (i = 0; i < state->path.active; i++) {
-               xfs_da_brelse(args->trans, state->path.blk[i].bp);
+               xfs_trans_brelse(args->trans, state->path.blk[i].bp);
                state->path.blk[i].bp = NULL;
        }
        xfs_da_state_free(state);
@@ -1940,7 +1904,7 @@ xfs_dir2_node_trim_free(
        xfs_fileoff_t           fo,             /* free block number */
        int                     *rvalp)         /* out: did something */
 {
-       xfs_dabuf_t             *bp;            /* freespace buffer */
+       struct xfs_buf          *bp;            /* freespace buffer */
        xfs_inode_t             *dp;            /* incore directory inode */
        int                     error;          /* error return code */
        xfs_dir2_free_t         *free;          /* freespace structure */
@@ -1965,13 +1929,13 @@ xfs_dir2_node_trim_free(
        if (bp == NULL) {
                return 0;
        }
-       free = bp->data;
+       free = bp->b_addr;
        ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));
        /*
         * If there are used entries, there's nothing to do.
         */
        if (be32_to_cpu(free->hdr.nused) > 0) {
-               xfs_da_brelse(tp, bp);
+               xfs_trans_brelse(tp, bp);
                *rvalp = 0;
                return 0;
        }
@@ -1987,7 +1951,7 @@ xfs_dir2_node_trim_free(
                 * pieces.  This is the last block of an extent.
                 */
                ASSERT(error != ENOSPC);
-               xfs_da_brelse(tp, bp);
+               xfs_trans_brelse(tp, bp);
                return error;
        }
        /*
index 067f403ecf8a41c4367c07d46cb6bd0c86b75cca..3523d3e15aa8ad3fd3f86aaf65f322ad13c956bf 100644 (file)
@@ -25,7 +25,7 @@ extern int xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp, int *r);
 extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space,
                                xfs_dir2_db_t *dbp);
 extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db,
-                               struct xfs_dabuf *bp);
+                               struct xfs_buf *bp);
 extern int xfs_dir_cilookup_result(struct xfs_da_args *args,
                                const unsigned char *name, int len);
 
@@ -37,11 +37,11 @@ extern int xfs_dir2_block_lookup(struct xfs_da_args *args);
 extern int xfs_dir2_block_removename(struct xfs_da_args *args);
 extern int xfs_dir2_block_replace(struct xfs_da_args *args);
 extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args,
-               struct xfs_dabuf *lbp, struct xfs_dabuf *dbp);
+               struct xfs_buf *lbp, struct xfs_buf *dbp);
 
 /* xfs_dir2_data.c */
 #ifdef DEBUG
-extern void xfs_dir2_data_check(struct xfs_inode *dp, struct xfs_dabuf *bp);
+extern void xfs_dir2_data_check(struct xfs_inode *dp, struct xfs_buf *bp);
 #else
 #define        xfs_dir2_data_check(dp,bp)
 #endif
@@ -51,43 +51,43 @@ xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr,
 extern void xfs_dir2_data_freescan(struct xfs_mount *mp,
                struct xfs_dir2_data_hdr *hdr, int *loghead);
 extern int xfs_dir2_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno,
-               struct xfs_dabuf **bpp);
-extern void xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_dabuf *bp,
+               struct xfs_buf **bpp);
+extern void xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_buf *bp,
                struct xfs_dir2_data_entry *dep);
 extern void xfs_dir2_data_log_header(struct xfs_trans *tp,
-               struct xfs_dabuf *bp);
-extern void xfs_dir2_data_log_unused(struct xfs_trans *tp, struct xfs_dabuf *bp,
+               struct xfs_buf *bp);
+extern void xfs_dir2_data_log_unused(struct xfs_trans *tp, struct xfs_buf *bp,
                struct xfs_dir2_data_unused *dup);
-extern void xfs_dir2_data_make_free(struct xfs_trans *tp, struct xfs_dabuf *bp,
+extern void xfs_dir2_data_make_free(struct xfs_trans *tp, struct xfs_buf *bp,
                xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len,
                int *needlogp, int *needscanp);
-extern void xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_dabuf *bp,
+extern void xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_buf *bp,
                struct xfs_dir2_data_unused *dup, xfs_dir2_data_aoff_t offset,
                xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp);
 
 /* xfs_dir2_leaf.c */
 extern int xfs_dir2_block_to_leaf(struct xfs_da_args *args,
-               struct xfs_dabuf *dbp);
+               struct xfs_buf *dbp);
 extern int xfs_dir2_leaf_addname(struct xfs_da_args *args);
 extern void xfs_dir2_leaf_compact(struct xfs_da_args *args,
-               struct xfs_dabuf *bp);
-extern void xfs_dir2_leaf_compact_x1(struct xfs_dabuf *bp, int *indexp,
+               struct xfs_buf *bp);
+extern void xfs_dir2_leaf_compact_x1(struct xfs_buf *bp, int *indexp,
                int *lowstalep, int *highstalep, int *lowlogp, int *highlogp);
 extern int xfs_dir2_leaf_getdents(struct xfs_inode *dp, void *dirent,
                size_t bufsize, xfs_off_t *offset, filldir_t filldir);
 extern int xfs_dir2_leaf_init(struct xfs_da_args *args, xfs_dir2_db_t bno,
-               struct xfs_dabuf **bpp, int magic);
-extern void xfs_dir2_leaf_log_ents(struct xfs_trans *tp, struct xfs_dabuf *bp,
+               struct xfs_buf **bpp, int magic);
+extern void xfs_dir2_leaf_log_ents(struct xfs_trans *tp, struct xfs_buf *bp,
                int first, int last);
 extern void xfs_dir2_leaf_log_header(struct xfs_trans *tp,
-               struct xfs_dabuf *bp);
+               struct xfs_buf *bp);
 extern int xfs_dir2_leaf_lookup(struct xfs_da_args *args);
 extern int xfs_dir2_leaf_removename(struct xfs_da_args *args);
 extern int xfs_dir2_leaf_replace(struct xfs_da_args *args);
 extern int xfs_dir2_leaf_search_hash(struct xfs_da_args *args,
-               struct xfs_dabuf *lbp);
+               struct xfs_buf *lbp);
 extern int xfs_dir2_leaf_trim_data(struct xfs_da_args *args,
-               struct xfs_dabuf *lbp, xfs_dir2_db_t db);
+               struct xfs_buf *lbp, xfs_dir2_db_t db);
 extern struct xfs_dir2_leaf_entry *
 xfs_dir2_leaf_find_entry(struct xfs_dir2_leaf *leaf, int index, int compact,
                int lowstale, int highstale,
@@ -96,13 +96,13 @@ extern int xfs_dir2_node_to_leaf(struct xfs_da_state *state);
 
 /* xfs_dir2_node.c */
 extern int xfs_dir2_leaf_to_node(struct xfs_da_args *args,
-               struct xfs_dabuf *lbp);
-extern xfs_dahash_t xfs_dir2_leafn_lasthash(struct xfs_dabuf *bp, int *count);
-extern int xfs_dir2_leafn_lookup_int(struct xfs_dabuf *bp,
+               struct xfs_buf *lbp);
+extern xfs_dahash_t xfs_dir2_leafn_lasthash(struct xfs_buf *bp, int *count);
+extern int xfs_dir2_leafn_lookup_int(struct xfs_buf *bp,
                struct xfs_da_args *args, int *indexp,
                struct xfs_da_state *state);
-extern int xfs_dir2_leafn_order(struct xfs_dabuf *leaf1_bp,
-               struct xfs_dabuf *leaf2_bp);
+extern int xfs_dir2_leafn_order(struct xfs_buf *leaf1_bp,
+               struct xfs_buf *leaf2_bp);
 extern int xfs_dir2_leafn_split(struct xfs_da_state *state,
        struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk);
 extern int xfs_dir2_leafn_toosmall(struct xfs_da_state *state, int *action);
@@ -122,7 +122,7 @@ extern xfs_ino_t xfs_dir2_sfe_get_ino(struct xfs_dir2_sf_hdr *sfp,
                struct xfs_dir2_sf_entry *sfep);
 extern int xfs_dir2_block_sfsize(struct xfs_inode *dp,
                struct xfs_dir2_data_hdr *block, struct xfs_dir2_sf_hdr *sfhp);
-extern int xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_dabuf *bp,
+extern int xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_buf *bp,
                int size, xfs_dir2_sf_hdr_t *sfhp);
 extern int xfs_dir2_sf_addname(struct xfs_da_args *args);
 extern int xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino);
index 19bf0c5e38f456e815a11806098ee675a9ed6134..1b9fc3ec7e4b393f573b1861b0b12db315872d32 100644 (file)
@@ -222,7 +222,7 @@ xfs_dir2_block_sfsize(
 int                                            /* error */
 xfs_dir2_block_to_sf(
        xfs_da_args_t           *args,          /* operation arguments */
-       xfs_dabuf_t             *bp,            /* block buffer */
+       struct xfs_buf          *bp,
        int                     size,           /* shortform directory size */
        xfs_dir2_sf_hdr_t       *sfhp)          /* shortform directory hdr */
 {
@@ -249,7 +249,7 @@ xfs_dir2_block_to_sf(
         * and add local data.
         */
        hdr = kmem_alloc(mp->m_dirblksize, KM_SLEEP);
-       memcpy(hdr, bp->data, mp->m_dirblksize);
+       memcpy(hdr, bp->b_addr, mp->m_dirblksize);
        logflags = XFS_ILOG_CORE;
        if ((error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp))) {
                ASSERT(error != ENOSPC);
index 9f7ec15a65222e2fe318e0ab81ac9cca0a664b4a..c4559c6e6f2cffbf9783f035dbcdd6e1b39fdcdf 100644 (file)
@@ -236,7 +236,6 @@ xfs_file_aio_read(
        ssize_t                 ret = 0;
        int                     ioflags = 0;
        xfs_fsize_t             n;
-       unsigned long           seg;
 
        XFS_STATS_INC(xs_read_calls);
 
@@ -247,19 +246,9 @@ xfs_file_aio_read(
        if (file->f_mode & FMODE_NOCMTIME)
                ioflags |= IO_INVIS;
 
-       /* START copy & waste from filemap.c */
-       for (seg = 0; seg < nr_segs; seg++) {
-               const struct iovec *iv = &iovp[seg];
-
-               /*
-                * If any segment has a negative length, or the cumulative
-                * length ever wraps negative then return -EINVAL.
-                */
-               size += iv->iov_len;
-               if (unlikely((ssize_t)(size|iv->iov_len) < 0))
-                       return XFS_ERROR(-EINVAL);
-       }
-       /* END copy & waste from filemap.c */
+       ret = generic_segment_checks(iovp, &nr_segs, &size, VERIFY_WRITE);
+       if (ret < 0)
+               return ret;
 
        if (unlikely(ioflags & IO_ISDIRECT)) {
                xfs_buftarg_t   *target =
@@ -273,7 +262,7 @@ xfs_file_aio_read(
                }
        }
 
-       n = XFS_MAXIOFFSET(mp) - iocb->ki_pos;
+       n = mp->m_super->s_maxbytes - iocb->ki_pos;
        if (n <= 0 || size == 0)
                return 0;
 
index 177a21a7ac490983a5a5ca424ff07ff75bb61000..21e37b55f7e596c6d29c0c0125a755f7a8ada7f6 100644 (file)
@@ -442,14 +442,13 @@ xfs_ialloc_next_ag(
  * Select an allocation group to look for a free inode in, based on the parent
  * inode and then mode.  Return the allocation group buffer.
  */
-STATIC xfs_buf_t *                     /* allocation group buffer */
+STATIC xfs_agnumber_t
 xfs_ialloc_ag_select(
        xfs_trans_t     *tp,            /* transaction pointer */
        xfs_ino_t       parent,         /* parent directory inode number */
        umode_t         mode,           /* bits set to indicate file type */
        int             okalloc)        /* ok to allocate more space */
 {
-       xfs_buf_t       *agbp;          /* allocation group header buffer */
        xfs_agnumber_t  agcount;        /* number of ag's in the filesystem */
        xfs_agnumber_t  agno;           /* current ag number */
        int             flags;          /* alloc buffer locking flags */
@@ -459,6 +458,7 @@ xfs_ialloc_ag_select(
        int             needspace;      /* file mode implies space allocated */
        xfs_perag_t     *pag;           /* per allocation group data */
        xfs_agnumber_t  pagno;          /* parent (starting) ag number */
+       int             error;
 
        /*
         * Files of these types need at least one block if length > 0
@@ -474,7 +474,9 @@ xfs_ialloc_ag_select(
                if (pagno >= agcount)
                        pagno = 0;
        }
+
        ASSERT(pagno < agcount);
+
        /*
         * Loop through allocation groups, looking for one with a little
         * free space in it.  Note we don't look for free inodes, exactly.
@@ -486,51 +488,45 @@ xfs_ialloc_ag_select(
        flags = XFS_ALLOC_FLAG_TRYLOCK;
        for (;;) {
                pag = xfs_perag_get(mp, agno);
+               if (!pag->pagi_inodeok) {
+                       xfs_ialloc_next_ag(mp);
+                       goto nextag;
+               }
+
                if (!pag->pagi_init) {
-                       if (xfs_ialloc_read_agi(mp, tp, agno, &agbp)) {
-                               agbp = NULL;
+                       error = xfs_ialloc_pagi_init(mp, tp, agno);
+                       if (error)
                                goto nextag;
-                       }
-               } else
-                       agbp = NULL;
+               }
 
-               if (!pag->pagi_inodeok) {
-                       xfs_ialloc_next_ag(mp);
-                       goto unlock_nextag;
+               if (pag->pagi_freecount) {
+                       xfs_perag_put(pag);
+                       return agno;
                }
 
-               /*
-                * Is there enough free space for the file plus a block
-                * of inodes (if we need to allocate some)?
-                */
-               ineed = pag->pagi_freecount ? 0 : XFS_IALLOC_BLOCKS(mp);
-               if (ineed && !pag->pagf_init) {
-                       if (agbp == NULL &&
-                           xfs_ialloc_read_agi(mp, tp, agno, &agbp)) {
-                               agbp = NULL;
+               if (!okalloc)
+                       goto nextag;
+
+               if (!pag->pagf_init) {
+                       error = xfs_alloc_pagf_init(mp, tp, agno, flags);
+                       if (error)
                                goto nextag;
-                       }
-                       (void)xfs_alloc_pagf_init(mp, tp, agno, flags);
                }
-               if (!ineed || pag->pagf_init) {
-                       if (ineed && !(longest = pag->pagf_longest))
-                               longest = pag->pagf_flcount > 0;
-                       if (!ineed ||
-                           (pag->pagf_freeblks >= needspace + ineed &&
-                            longest >= ineed &&
-                            okalloc)) {
-                               if (agbp == NULL &&
-                                   xfs_ialloc_read_agi(mp, tp, agno, &agbp)) {
-                                       agbp = NULL;
-                                       goto nextag;
-                               }
-                               xfs_perag_put(pag);
-                               return agbp;
-                       }
+
+               /*
+                * Is there enough free space for the file plus a block of
+                * inodes? (if we need to allocate some)?
+                */
+               ineed = XFS_IALLOC_BLOCKS(mp);
+               longest = pag->pagf_longest;
+               if (!longest)
+                       longest = pag->pagf_flcount > 0;
+
+               if (pag->pagf_freeblks >= needspace + ineed &&
+                   longest >= ineed) {
+                       xfs_perag_put(pag);
+                       return agno;
                }
-unlock_nextag:
-               if (agbp)
-                       xfs_trans_brelse(tp, agbp);
 nextag:
                xfs_perag_put(pag);
                /*
@@ -538,13 +534,13 @@ nextag:
                 * down.
                 */
                if (XFS_FORCED_SHUTDOWN(mp))
-                       return NULL;
+                       return NULLAGNUMBER;
                agno++;
                if (agno >= agcount)
                        agno = 0;
                if (agno == pagno) {
                        if (flags == 0)
-                               return NULL;
+                               return NULLAGNUMBER;
                        flags = 0;
                }
        }
@@ -607,195 +603,39 @@ xfs_ialloc_get_rec(
 }
 
 /*
- * Visible inode allocation functions.
- */
-/*
- * Find a free (set) bit in the inode bitmask.
- */
-static inline int xfs_ialloc_find_free(xfs_inofree_t *fp)
-{
-       return xfs_lowbit64(*fp);
-}
-
-/*
- * Allocate an inode on disk.
- * Mode is used to tell whether the new inode will need space, and whether
- * it is a directory.
- *
- * The arguments IO_agbp and alloc_done are defined to work within
- * the constraint of one allocation per transaction.
- * xfs_dialloc() is designed to be called twice if it has to do an
- * allocation to make more free inodes.  On the first call,
- * IO_agbp should be set to NULL. If an inode is available,
- * i.e., xfs_dialloc() did not need to do an allocation, an inode
- * number is returned.  In this case, IO_agbp would be set to the
- * current ag_buf and alloc_done set to false.
- * If an allocation needed to be done, xfs_dialloc would return
- * the current ag_buf in IO_agbp and set alloc_done to true.
- * The caller should then commit the current transaction, allocate a new
- * transaction, and call xfs_dialloc() again, passing in the previous
- * value of IO_agbp.  IO_agbp should be held across the transactions.
- * Since the agbp is locked across the two calls, the second call is
- * guaranteed to have a free inode available.
+ * Allocate an inode.
  *
- * Once we successfully pick an inode its number is returned and the
- * on-disk data structures are updated.  The inode itself is not read
- * in, since doing so would break ordering constraints with xfs_reclaim.
+ * The caller selected an AG for us, and made sure that free inodes are
+ * available.
  */
-int
-xfs_dialloc(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_ino_t       parent,         /* parent inode (directory) */
-       umode_t         mode,           /* mode bits for new inode */
-       int             okalloc,        /* ok to allocate more space */
-       xfs_buf_t       **IO_agbp,      /* in/out ag header's buffer */
-       boolean_t       *alloc_done,    /* true if we needed to replenish
-                                          inode freelist */
-       xfs_ino_t       *inop)          /* inode number allocated */
+STATIC int
+xfs_dialloc_ag(
+       struct xfs_trans        *tp,
+       struct xfs_buf          *agbp,
+       xfs_ino_t               parent,
+       xfs_ino_t               *inop)
 {
-       xfs_agnumber_t  agcount;        /* number of allocation groups */
-       xfs_buf_t       *agbp;          /* allocation group header's buffer */
-       xfs_agnumber_t  agno;           /* allocation group number */
-       xfs_agi_t       *agi;           /* allocation group header structure */
-       xfs_btree_cur_t *cur;           /* inode allocation btree cursor */
-       int             error;          /* error return value */
-       int             i;              /* result code */
-       int             ialloced;       /* inode allocation status */
-       int             noroom = 0;     /* no space for inode blk allocation */
-       xfs_ino_t       ino;            /* fs-relative inode to be returned */
-       /* REFERENCED */
-       int             j;              /* result code */
-       xfs_mount_t     *mp;            /* file system mount structure */
-       int             offset;         /* index of inode in chunk */
-       xfs_agino_t     pagino;         /* parent's AG relative inode # */
-       xfs_agnumber_t  pagno;          /* parent's AG number */
-       xfs_inobt_rec_incore_t rec;     /* inode allocation record */
-       xfs_agnumber_t  tagno;          /* testing allocation group number */
-       xfs_btree_cur_t *tcur;          /* temp cursor */
-       xfs_inobt_rec_incore_t trec;    /* temp inode allocation record */
-       struct xfs_perag *pag;
-
-
-       if (*IO_agbp == NULL) {
-               /*
-                * We do not have an agbp, so select an initial allocation
-                * group for inode allocation.
-                */
-               agbp = xfs_ialloc_ag_select(tp, parent, mode, okalloc);
-               /*
-                * Couldn't find an allocation group satisfying the
-                * criteria, give up.
-                */
-               if (!agbp) {
-                       *inop = NULLFSINO;
-                       return 0;
-               }
-               agi = XFS_BUF_TO_AGI(agbp);
-               ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
-       } else {
-               /*
-                * Continue where we left off before.  In this case, we
-                * know that the allocation group has free inodes.
-                */
-               agbp = *IO_agbp;
-               agi = XFS_BUF_TO_AGI(agbp);
-               ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
-               ASSERT(be32_to_cpu(agi->agi_freecount) > 0);
-       }
-       mp = tp->t_mountp;
-       agcount = mp->m_sb.sb_agcount;
-       agno = be32_to_cpu(agi->agi_seqno);
-       tagno = agno;
-       pagno = XFS_INO_TO_AGNO(mp, parent);
-       pagino = XFS_INO_TO_AGINO(mp, parent);
-
-       /*
-        * If we have already hit the ceiling of inode blocks then clear
-        * okalloc so we scan all available agi structures for a free
-        * inode.
-        */
-
-       if (mp->m_maxicount &&
-           mp->m_sb.sb_icount + XFS_IALLOC_INODES(mp) > mp->m_maxicount) {
-               noroom = 1;
-               okalloc = 0;
-       }
+       struct xfs_mount        *mp = tp->t_mountp;
+       struct xfs_agi          *agi = XFS_BUF_TO_AGI(agbp);
+       xfs_agnumber_t          agno = be32_to_cpu(agi->agi_seqno);
+       xfs_agnumber_t          pagno = XFS_INO_TO_AGNO(mp, parent);
+       xfs_agino_t             pagino = XFS_INO_TO_AGINO(mp, parent);
+       struct xfs_perag        *pag;
+       struct xfs_btree_cur    *cur, *tcur;
+       struct xfs_inobt_rec_incore rec, trec;
+       xfs_ino_t               ino;
+       int                     error;
+       int                     offset;
+       int                     i, j;
 
-       /*
-        * Loop until we find an allocation group that either has free inodes
-        * or in which we can allocate some inodes.  Iterate through the
-        * allocation groups upward, wrapping at the end.
-        */
-       *alloc_done = B_FALSE;
-       while (!agi->agi_freecount) {
-               /*
-                * Don't do anything if we're not supposed to allocate
-                * any blocks, just go on to the next ag.
-                */
-               if (okalloc) {
-                       /*
-                        * Try to allocate some new inodes in the allocation
-                        * group.
-                        */
-                       if ((error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced))) {
-                               xfs_trans_brelse(tp, agbp);
-                               if (error == ENOSPC) {
-                                       *inop = NULLFSINO;
-                                       return 0;
-                               } else
-                                       return error;
-                       }
-                       if (ialloced) {
-                               /*
-                                * We successfully allocated some inodes, return
-                                * the current context to the caller so that it
-                                * can commit the current transaction and call
-                                * us again where we left off.
-                                */
-                               ASSERT(be32_to_cpu(agi->agi_freecount) > 0);
-                               *alloc_done = B_TRUE;
-                               *IO_agbp = agbp;
-                               *inop = NULLFSINO;
-                               return 0;
-                       }
-               }
-               /*
-                * If it failed, give up on this ag.
-                */
-               xfs_trans_brelse(tp, agbp);
-               /*
-                * Go on to the next ag: get its ag header.
-                */
-nextag:
-               if (++tagno == agcount)
-                       tagno = 0;
-               if (tagno == agno) {
-                       *inop = NULLFSINO;
-                       return noroom ? ENOSPC : 0;
-               }
-               pag = xfs_perag_get(mp, tagno);
-               if (pag->pagi_inodeok == 0) {
-                       xfs_perag_put(pag);
-                       goto nextag;
-               }
-               error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp);
-               xfs_perag_put(pag);
-               if (error)
-                       goto nextag;
-               agi = XFS_BUF_TO_AGI(agbp);
-               ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
-       }
-       /*
-        * Here with an allocation group that has a free inode.
-        * Reset agno since we may have chosen a new ag in the
-        * loop above.
-        */
-       agno = tagno;
-       *IO_agbp = NULL;
        pag = xfs_perag_get(mp, agno);
 
+       ASSERT(pag->pagi_init);
+       ASSERT(pag->pagi_inodeok);
+       ASSERT(pag->pagi_freecount > 0);
+
  restart_pagno:
-       cur = xfs_inobt_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno));
+       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
        /*
         * If pagino is 0 (this is the root inode allocation) use newino.
         * This must work because we've just allocated some.
@@ -995,7 +835,7 @@ newino:
        }
 
 alloc_inode:
-       offset = xfs_ialloc_find_free(&rec.ir_free);
+       offset = xfs_lowbit64(rec.ir_free);
        ASSERT(offset >= 0);
        ASSERT(offset < XFS_INODES_PER_CHUNK);
        ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
@@ -1027,6 +867,164 @@ error0:
        return error;
 }
 
+/*
+ * Allocate an inode on disk.
+ *
+ * Mode is used to tell whether the new inode will need space, and whether it
+ * is a directory.
+ *
+ * This function is designed to be called twice if it has to do an allocation
+ * to make more free inodes.  On the first call, *IO_agbp should be set to NULL.
+ * If an inode is available without having to performn an allocation, an inode
+ * number is returned.  In this case, *IO_agbp would be NULL.  If an allocation
+ * needes to be done, xfs_dialloc would return the current AGI buffer in
+ * *IO_agbp.  The caller should then commit the current transaction, allocate a
+ * new transaction, and call xfs_dialloc() again, passing in the previous value
+ * of *IO_agbp.  IO_agbp should be held across the transactions. Since the AGI
+ * buffer is locked across the two calls, the second call is guaranteed to have
+ * a free inode available.
+ *
+ * Once we successfully pick an inode its number is returned and the on-disk
+ * data structures are updated.  The inode itself is not read in, since doing so
+ * would break ordering constraints with xfs_reclaim.
+ */
+int
+xfs_dialloc(
+       struct xfs_trans        *tp,
+       xfs_ino_t               parent,
+       umode_t                 mode,
+       int                     okalloc,
+       struct xfs_buf          **IO_agbp,
+       xfs_ino_t               *inop)
+{
+       struct xfs_mount        *mp = tp->t_mountp;
+       struct xfs_buf          *agbp;
+       xfs_agnumber_t          agno;
+       int                     error;
+       int                     ialloced;
+       int                     noroom = 0;
+       xfs_agnumber_t          start_agno;
+       struct xfs_perag        *pag;
+
+       if (*IO_agbp) {
+               /*
+                * If the caller passes in a pointer to the AGI buffer,
+                * continue where we left off before.  In this case, we
+                * know that the allocation group has free inodes.
+                */
+               agbp = *IO_agbp;
+               goto out_alloc;
+       }
+
+       /*
+        * We do not have an agbp, so select an initial allocation
+        * group for inode allocation.
+        */
+       start_agno = xfs_ialloc_ag_select(tp, parent, mode, okalloc);
+       if (start_agno == NULLAGNUMBER) {
+               *inop = NULLFSINO;
+               return 0;
+       }
+
+       /*
+        * If we have already hit the ceiling of inode blocks then clear
+        * okalloc so we scan all available agi structures for a free
+        * inode.
+        */
+       if (mp->m_maxicount &&
+           mp->m_sb.sb_icount + XFS_IALLOC_INODES(mp) > mp->m_maxicount) {
+               noroom = 1;
+               okalloc = 0;
+       }
+
+       /*
+        * Loop until we find an allocation group that either has free inodes
+        * or in which we can allocate some inodes.  Iterate through the
+        * allocation groups upward, wrapping at the end.
+        */
+       agno = start_agno;
+       for (;;) {
+               pag = xfs_perag_get(mp, agno);
+               if (!pag->pagi_inodeok) {
+                       xfs_ialloc_next_ag(mp);
+                       goto nextag;
+               }
+
+               if (!pag->pagi_init) {
+                       error = xfs_ialloc_pagi_init(mp, tp, agno);
+                       if (error)
+                               goto out_error;
+               }
+
+               /*
+                * Do a first racy fast path check if this AG is usable.
+                */
+               if (!pag->pagi_freecount && !okalloc)
+                       goto nextag;
+
+               error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
+               if (error)
+                       goto out_error;
+
+               /*
+                * Once the AGI has been read in we have to recheck
+                * pagi_freecount with the AGI buffer lock held.
+                */
+               if (pag->pagi_freecount) {
+                       xfs_perag_put(pag);
+                       goto out_alloc;
+               }
+
+               if (!okalloc) {
+                       xfs_trans_brelse(tp, agbp);
+                       goto nextag;
+               }
+
+               error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced);
+               if (error) {
+                       xfs_trans_brelse(tp, agbp);
+
+                       if (error != ENOSPC)
+                               goto out_error;
+
+                       xfs_perag_put(pag);
+                       *inop = NULLFSINO;
+                       return 0;
+               }
+
+               if (ialloced) {
+                       /*
+                        * We successfully allocated some inodes, return
+                        * the current context to the caller so that it
+                        * can commit the current transaction and call
+                        * us again where we left off.
+                        */
+                       ASSERT(pag->pagi_freecount > 0);
+                       xfs_perag_put(pag);
+
+                       *IO_agbp = agbp;
+                       *inop = NULLFSINO;
+                       return 0;
+               }
+
+nextag:
+               xfs_perag_put(pag);
+               if (++agno == mp->m_sb.sb_agcount)
+                       agno = 0;
+               if (agno == start_agno) {
+                       *inop = NULLFSINO;
+                       return noroom ? ENOSPC : 0;
+               }
+       }
+
+out_alloc:
+       *IO_agbp = NULL;
+       return xfs_dialloc_ag(tp, agbp, parent, inop);
+out_error:
+       xfs_perag_put(pag);
+       return XFS_ERROR(error);
+}
+
 /*
  * Free disk inode.  Carefully avoids touching the incore inode, all
  * manipulations incore are the caller's responsibility.
index 65ac57c8063c78cc066f996db1ddbcce7c6e8a9f..1fd6ea4e9c91cdb09af5c80ff293ad818894a2d1 100644 (file)
@@ -75,8 +75,6 @@ xfs_dialloc(
        umode_t         mode,           /* mode bits for new inode */
        int             okalloc,        /* ok to allocate more space */
        struct xfs_buf  **agbp,         /* buf for a.g. inode header */
-       boolean_t       *alloc_done,    /* an allocation was done to replenish
-                                          the free inodes */
        xfs_ino_t       *inop);         /* inode number allocated */
 
 /*
index 1bb4365e8c25470d8686996401d7996ce1d3b244..784a803383ec01d670366fc6a334dcc9442176ca 100644 (file)
 #include "xfs_trace.h"
 
 
-/*
- * Define xfs inode iolock lockdep classes. We need to ensure that all active
- * inodes are considered the same for lockdep purposes, including inodes that
- * are recycled through the XFS_IRECLAIMABLE state. This is the the only way to
- * guarantee the locks are considered the same when there are multiple lock
- * initialisation siteÑ•. Also, define a reclaimable inode class so it is
- * obvious in lockdep reports which class the report is against.
- */
-static struct lock_class_key xfs_iolock_active;
-struct lock_class_key xfs_iolock_reclaimable;
-
 /*
  * Allocate and initialise an xfs_inode.
  */
@@ -80,8 +69,6 @@ xfs_inode_alloc(
        ASSERT(ip->i_ino == 0);
 
        mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino);
-       lockdep_set_class_and_name(&ip->i_iolock.mr_lock,
-                       &xfs_iolock_active, "xfs_iolock_active");
 
        /* initialise the xfs inode */
        ip->i_ino = ino;
@@ -250,8 +237,6 @@ xfs_iget_cache_hit(
 
                ASSERT(!rwsem_is_locked(&ip->i_iolock.mr_lock));
                mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino);
-               lockdep_set_class_and_name(&ip->i_iolock.mr_lock,
-                               &xfs_iolock_active, "xfs_iolock_active");
 
                spin_unlock(&ip->i_flags_lock);
                spin_unlock(&pag->pag_ici_lock);
index a59eea09930ae3a729cae134f1bd26084e2fbc4c..2778258fcfa239e07dbc79edf6cb4750b7e13dd8 100644 (file)
@@ -132,23 +132,28 @@ xfs_inobp_check(
 #endif
 
 /*
- * Find the buffer associated with the given inode map
- * We do basic validation checks on the buffer once it has been
- * retrieved from disk.
+ * This routine is called to map an inode to the buffer containing the on-disk
+ * version of the inode.  It returns a pointer to the buffer containing the
+ * on-disk inode in the bpp parameter, and in the dipp parameter it returns a
+ * pointer to the on-disk inode within that buffer.
+ *
+ * If a non-zero error is returned, then the contents of bpp and dipp are
+ * undefined.
  */
-STATIC int
+int
 xfs_imap_to_bp(
-       xfs_mount_t     *mp,
-       xfs_trans_t     *tp,
-       struct xfs_imap *imap,
-       xfs_buf_t       **bpp,
-       uint            buf_flags,
-       uint            iget_flags)
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       struct xfs_imap         *imap,
+       struct xfs_dinode       **dipp,
+       struct xfs_buf          **bpp,
+       uint                    buf_flags,
+       uint                    iget_flags)
 {
-       int             error;
-       int             i;
-       int             ni;
-       xfs_buf_t       *bp;
+       struct xfs_buf          *bp;
+       int                     error;
+       int                     i;
+       int                     ni;
 
        buf_flags |= XBF_UNMAPPED;
        error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,
@@ -189,8 +194,8 @@ xfs_imap_to_bp(
                                xfs_trans_brelse(tp, bp);
                                return XFS_ERROR(EINVAL);
                        }
-                       XFS_CORRUPTION_ERROR("xfs_imap_to_bp",
-                                               XFS_ERRLEVEL_HIGH, mp, dip);
+                       XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH,
+                                            mp, dip);
 #ifdef DEBUG
                        xfs_emerg(mp,
                                "bad inode magic/vsn daddr %lld #%d (magic=%x)",
@@ -204,96 +209,9 @@ xfs_imap_to_bp(
        }
 
        xfs_inobp_check(mp, bp);
-       *bpp = bp;
-       return 0;
-}
-
-/*
- * This routine is called to map an inode number within a file
- * system to the buffer containing the on-disk version of the
- * inode.  It returns a pointer to the buffer containing the
- * on-disk inode in the bpp parameter, and in the dip parameter
- * it returns a pointer to the on-disk inode within that buffer.
- *
- * If a non-zero error is returned, then the contents of bpp and
- * dipp are undefined.
- *
- * Use xfs_imap() to determine the size and location of the
- * buffer to read from disk.
- */
-int
-xfs_inotobp(
-       xfs_mount_t     *mp,
-       xfs_trans_t     *tp,
-       xfs_ino_t       ino,
-       xfs_dinode_t    **dipp,
-       xfs_buf_t       **bpp,
-       int             *offset,
-       uint            imap_flags)
-{
-       struct xfs_imap imap;
-       xfs_buf_t       *bp;
-       int             error;
-
-       imap.im_blkno = 0;
-       error = xfs_imap(mp, tp, ino, &imap, imap_flags);
-       if (error)
-               return error;
-
-       error = xfs_imap_to_bp(mp, tp, &imap, &bp, 0, imap_flags);
-       if (error)
-               return error;
-
-       *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset);
-       *bpp = bp;
-       *offset = imap.im_boffset;
-       return 0;
-}
-
-
-/*
- * This routine is called to map an inode to the buffer containing
- * the on-disk version of the inode.  It returns a pointer to the
- * buffer containing the on-disk inode in the bpp parameter, and in
- * the dip parameter it returns a pointer to the on-disk inode within
- * that buffer.
- *
- * If a non-zero error is returned, then the contents of bpp and
- * dipp are undefined.
- *
- * The inode is expected to already been mapped to its buffer and read
- * in once, thus we can use the mapping information stored in the inode
- * rather than calling xfs_imap().  This allows us to avoid the overhead
- * of looking at the inode btree for small block file systems
- * (see xfs_imap()).
- */
-int
-xfs_itobp(
-       xfs_mount_t     *mp,
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip,
-       xfs_dinode_t    **dipp,
-       xfs_buf_t       **bpp,
-       uint            buf_flags)
-{
-       xfs_buf_t       *bp;
-       int             error;
-
-       ASSERT(ip->i_imap.im_blkno != 0);
-
-       error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &bp, buf_flags, 0);
-       if (error)
-               return error;
 
-       if (!bp) {
-               ASSERT(buf_flags & XBF_TRYLOCK);
-               ASSERT(tp == NULL);
-               *bpp = NULL;
-               return EAGAIN;
-       }
-
-       *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
        *bpp = bp;
+       *dipp = (struct xfs_dinode *)xfs_buf_offset(bp, imap->im_boffset);
        return 0;
 }
 
@@ -796,10 +714,9 @@ xfs_iread(
        /*
         * Get pointers to the on-disk inode and the buffer containing it.
         */
-       error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &bp, 0, iget_flags);
+       error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &bp, 0, iget_flags);
        if (error)
                return error;
-       dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
 
        /*
         * If we got something that isn't an inode it means someone
@@ -876,7 +793,7 @@ xfs_iread(
        /*
         * Use xfs_trans_brelse() to release the buffer containing the
         * on-disk inode, because it was acquired with xfs_trans_read_buf()
-        * in xfs_itobp() above.  If tp is NULL, this is just a normal
+        * in xfs_imap_to_bp() above.  If tp is NULL, this is just a normal
         * brelse().  If we're within a transaction, then xfs_trans_brelse()
         * will only release the buffer if it is not dirty within the
         * transaction.  It will be OK to release the buffer in this case,
@@ -970,7 +887,6 @@ xfs_ialloc(
        prid_t          prid,
        int             okalloc,
        xfs_buf_t       **ialloc_context,
-       boolean_t       *call_again,
        xfs_inode_t     **ipp)
 {
        xfs_ino_t       ino;
@@ -985,10 +901,10 @@ xfs_ialloc(
         * the on-disk inode to be allocated.
         */
        error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc,
-                           ialloc_context, call_again, &ino);
+                           ialloc_context, &ino);
        if (error)
                return error;
-       if (*call_again || ino == NULLFSINO) {
+       if (*ialloc_context || ino == NULLFSINO) {
                *ipp = NULL;
                return 0;
        }
@@ -1207,7 +1123,9 @@ xfs_itruncate_extents(
        int                     error = 0;
        int                     done = 0;
 
-       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+       ASSERT(!atomic_read(&VFS_I(ip)->i_count) ||
+              xfs_isilocked(ip, XFS_IOLOCK_EXCL));
        ASSERT(new_size <= XFS_ISIZE(ip));
        ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
        ASSERT(ip->i_itemp != NULL);
@@ -1226,7 +1144,7 @@ xfs_itruncate_extents(
         * then there is nothing to do.
         */
        first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size);
-       last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
+       last_block = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
        if (first_unmap_block == last_block)
                return 0;
 
@@ -1355,7 +1273,8 @@ xfs_iunlink(
                 * Here we put the head pointer into our next pointer,
                 * and then we fall through to point the head at us.
                 */
-               error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0);
+               error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp,
+                                      0, 0);
                if (error)
                        return error;
 
@@ -1429,16 +1348,16 @@ xfs_iunlink_remove(
 
        if (be32_to_cpu(agi->agi_unlinked[bucket_index]) == agino) {
                /*
-                * We're at the head of the list.  Get the inode's
-                * on-disk buffer to see if there is anyone after us
-                * on the list.  Only modify our next pointer if it
-                * is not already NULLAGINO.  This saves us the overhead
-                * of dealing with the buffer when there is no need to
-                * change it.
+                * We're at the head of the list.  Get the inode's on-disk
+                * buffer to see if there is anyone after us on the list.
+                * Only modify our next pointer if it is not already NULLAGINO.
+                * This saves us the overhead of dealing with the buffer when
+                * there is no need to change it.
                 */
-               error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0);
+               error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp,
+                                      0, 0);
                if (error) {
-                       xfs_warn(mp, "%s: xfs_itobp() returned error %d.",
+                       xfs_warn(mp, "%s: xfs_imap_to_bp returned error %d.",
                                __func__, error);
                        return error;
                }
@@ -1472,34 +1391,45 @@ xfs_iunlink_remove(
                next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
                last_ibp = NULL;
                while (next_agino != agino) {
-                       /*
-                        * If the last inode wasn't the one pointing to
-                        * us, then release its buffer since we're not
-                        * going to do anything with it.
-                        */
-                       if (last_ibp != NULL) {
+                       struct xfs_imap imap;
+
+                       if (last_ibp)
                                xfs_trans_brelse(tp, last_ibp);
-                       }
+
+                       imap.im_blkno = 0;
                        next_ino = XFS_AGINO_TO_INO(mp, agno, next_agino);
-                       error = xfs_inotobp(mp, tp, next_ino, &last_dip,
-                                           &last_ibp, &last_offset, 0);
+
+                       error = xfs_imap(mp, tp, next_ino, &imap, 0);
+                       if (error) {
+                               xfs_warn(mp,
+       "%s: xfs_imap returned error %d.",
+                                        __func__, error);
+                               return error;
+                       }
+
+                       error = xfs_imap_to_bp(mp, tp, &imap, &last_dip,
+                                              &last_ibp, 0, 0);
                        if (error) {
                                xfs_warn(mp,
-                                       "%s: xfs_inotobp() returned error %d.",
+       "%s: xfs_imap_to_bp returned error %d.",
                                        __func__, error);
                                return error;
                        }
+
+                       last_offset = imap.im_boffset;
                        next_agino = be32_to_cpu(last_dip->di_next_unlinked);
                        ASSERT(next_agino != NULLAGINO);
                        ASSERT(next_agino != 0);
                }
+
                /*
-                * Now last_ibp points to the buffer previous to us on
-                * the unlinked list.  Pull us from the list.
+                * Now last_ibp points to the buffer previous to us on the
+                * unlinked list.  Pull us from the list.
                 */
-               error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0);
+               error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp,
+                                      0, 0);
                if (error) {
-                       xfs_warn(mp, "%s: xfs_itobp(2) returned error %d.",
+                       xfs_warn(mp, "%s: xfs_imap_to_bp(2) returned error %d.",
                                __func__, error);
                        return error;
                }
@@ -1749,7 +1679,8 @@ xfs_ifree(
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 
-       error = xfs_itobp(ip->i_mount, tp, ip, &dip, &ibp, 0);
+       error = xfs_imap_to_bp(ip->i_mount, tp, &ip->i_imap, &dip, &ibp,
+                              0, 0);
        if (error)
                return error;
 
@@ -2428,7 +2359,7 @@ xfs_iflush(
        /*
         * For stale inodes we cannot rely on the backing buffer remaining
         * stale in cache for the remaining life of the stale inode and so
-        * xfs_itobp() below may give us a buffer that no longer contains
+        * xfs_imap_to_bp() below may give us a buffer that no longer contains
         * inodes below. We have to check this after ensuring the inode is
         * unpinned so that it is safe to reclaim the stale inode after the
         * flush call.
@@ -2454,7 +2385,8 @@ xfs_iflush(
        /*
         * Get the buffer containing the on-disk inode.
         */
-       error = xfs_itobp(mp, NULL, ip, &dip, &bp, XBF_TRYLOCK);
+       error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, XBF_TRYLOCK,
+                              0);
        if (error || !bp) {
                xfs_ifunlock(ip);
                return error;
index 1efff36a75b6961150ec8fb342d6fd47994eb79a..94b32f906e7903a32cc1e1474f3d4a6fed267f93 100644 (file)
@@ -487,8 +487,6 @@ static inline int xfs_isiflocked(struct xfs_inode *ip)
 #define XFS_IOLOCK_DEP(flags)  (((flags) & XFS_IOLOCK_DEP_MASK) >> XFS_IOLOCK_SHIFT)
 #define XFS_ILOCK_DEP(flags)   (((flags) & XFS_ILOCK_DEP_MASK) >> XFS_ILOCK_SHIFT)
 
-extern struct lock_class_key xfs_iolock_reclaimable;
-
 /*
  * For multiple groups support: if S_ISGID bit is set in the parent
  * directory, group of new file is set to that of the parent, and
@@ -517,7 +515,7 @@ void                xfs_inode_free(struct xfs_inode *ip);
  */
 int            xfs_ialloc(struct xfs_trans *, xfs_inode_t *, umode_t,
                           xfs_nlink_t, xfs_dev_t, prid_t, int,
-                          struct xfs_buf **, boolean_t *, xfs_inode_t **);
+                          struct xfs_buf **, xfs_inode_t **);
 
 uint           xfs_ip2xflags(struct xfs_inode *);
 uint           xfs_dic2xflags(struct xfs_dinode *);
@@ -557,12 +555,9 @@ do { \
 #define XFS_IGET_UNTRUSTED     0x2
 #define XFS_IGET_DONTCACHE     0x4
 
-int            xfs_inotobp(struct xfs_mount *, struct xfs_trans *,
-                           xfs_ino_t, struct xfs_dinode **,
-                           struct xfs_buf **, int *, uint);
-int            xfs_itobp(struct xfs_mount *, struct xfs_trans *,
-                         struct xfs_inode *, struct xfs_dinode **,
-                         struct xfs_buf **, uint);
+int            xfs_imap_to_bp(struct xfs_mount *, struct xfs_trans *,
+                              struct xfs_imap *, struct xfs_dinode **,
+                              struct xfs_buf **, uint, uint);
 int            xfs_iread(struct xfs_mount *, struct xfs_trans *,
                          struct xfs_inode *, uint);
 void           xfs_dinode_to_disk(struct xfs_dinode *,
index aadfce6681ee0d501b5c7df3c65abb712b2333bb..915edf6639f0267a1a34b145c868d2023e111daf 100644 (file)
@@ -285,7 +285,7 @@ xfs_iomap_eof_want_preallocate(
         * do any speculative allocation.
         */
        start_fsb = XFS_B_TO_FSBT(mp, ((xfs_ufsize_t)(offset + count - 1)));
-       count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
+       count_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
        while (count_fsb > 0) {
                imaps = nimaps;
                firstblock = NULLFSBLOCK;
@@ -416,8 +416,8 @@ retry:
         * Make sure preallocation does not create extents beyond the range we
         * actually support in this filesystem.
         */
-       if (last_fsb > XFS_B_TO_FSB(mp, mp->m_maxioffset))
-               last_fsb = XFS_B_TO_FSB(mp, mp->m_maxioffset);
+       if (last_fsb > XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes))
+               last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
 
        ASSERT(last_fsb > offset_fsb);
 
index 9c4340f5c3e0ff92bb84505155c3ba4f9a4bac54..4e00cf091d2ccac6b0a9e65113a67b2b5169f21f 100644 (file)
@@ -897,6 +897,47 @@ xfs_vn_setattr(
        return -xfs_setattr_nonsize(XFS_I(dentry->d_inode), iattr, 0);
 }
 
+STATIC int
+xfs_vn_update_time(
+       struct inode            *inode,
+       struct timespec         *now,
+       int                     flags)
+{
+       struct xfs_inode        *ip = XFS_I(inode);
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_trans        *tp;
+       int                     error;
+
+       trace_xfs_update_time(ip);
+
+       tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
+       error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
+       if (error) {
+               xfs_trans_cancel(tp, 0);
+               return -error;
+       }
+
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       if (flags & S_CTIME) {
+               inode->i_ctime = *now;
+               ip->i_d.di_ctime.t_sec = (__int32_t)now->tv_sec;
+               ip->i_d.di_ctime.t_nsec = (__int32_t)now->tv_nsec;
+       }
+       if (flags & S_MTIME) {
+               inode->i_mtime = *now;
+               ip->i_d.di_mtime.t_sec = (__int32_t)now->tv_sec;
+               ip->i_d.di_mtime.t_nsec = (__int32_t)now->tv_nsec;
+       }
+       if (flags & S_ATIME) {
+               inode->i_atime = *now;
+               ip->i_d.di_atime.t_sec = (__int32_t)now->tv_sec;
+               ip->i_d.di_atime.t_nsec = (__int32_t)now->tv_nsec;
+       }
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP);
+       return -xfs_trans_commit(tp, 0);
+}
+
 #define XFS_FIEMAP_FLAGS       (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR)
 
 /*
@@ -991,6 +1032,7 @@ static const struct inode_operations xfs_inode_operations = {
        .removexattr            = generic_removexattr,
        .listxattr              = xfs_vn_listxattr,
        .fiemap                 = xfs_vn_fiemap,
+       .update_time            = xfs_vn_update_time,
 };
 
 static const struct inode_operations xfs_dir_inode_operations = {
@@ -1016,6 +1058,7 @@ static const struct inode_operations xfs_dir_inode_operations = {
        .getxattr               = generic_getxattr,
        .removexattr            = generic_removexattr,
        .listxattr              = xfs_vn_listxattr,
+       .update_time            = xfs_vn_update_time,
 };
 
 static const struct inode_operations xfs_dir_ci_inode_operations = {
@@ -1041,6 +1084,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
        .getxattr               = generic_getxattr,
        .removexattr            = generic_removexattr,
        .listxattr              = xfs_vn_listxattr,
+       .update_time            = xfs_vn_update_time,
 };
 
 static const struct inode_operations xfs_symlink_inode_operations = {
@@ -1054,6 +1098,7 @@ static const struct inode_operations xfs_symlink_inode_operations = {
        .getxattr               = generic_getxattr,
        .removexattr            = generic_removexattr,
        .listxattr              = xfs_vn_listxattr,
+       .update_time            = xfs_vn_update_time,
 };
 
 STATIC void
index eff577a9b67ffe0d47f7d1834b5776d76122ba40..01d10a66e30243518d293f2c72a29b6135f7977b 100644 (file)
@@ -555,7 +555,7 @@ xfs_bulkstat_single(
 
        /*
         * note that requesting valid inode numbers which are not allocated
-        * to inodes will most likely cause xfs_itobp to generate warning
+        * to inodes will most likely cause xfs_imap_to_bp to generate warning
         * messages about bad magic numbers. This is ok. The fact that
         * the inode isn't actually an inode is handled by the
         * error check below. Done this way to make the usual case faster
index d90d4a388609af9da0cd40eb786a1fdd225a8d62..7f4f9370d0e7438df3820fab9b0026b37292623b 100644 (file)
@@ -45,51 +45,85 @@ xlog_commit_record(
        struct xlog_in_core     **iclog,
        xfs_lsn_t               *commitlsnp);
 
-STATIC xlog_t *  xlog_alloc_log(xfs_mount_t    *mp,
-                               xfs_buftarg_t   *log_target,
-                               xfs_daddr_t     blk_offset,
-                               int             num_bblks);
+STATIC struct xlog *
+xlog_alloc_log(
+       struct xfs_mount        *mp,
+       struct xfs_buftarg      *log_target,
+       xfs_daddr_t             blk_offset,
+       int                     num_bblks);
 STATIC int
 xlog_space_left(
        struct xlog             *log,
        atomic64_t              *head);
-STATIC int      xlog_sync(xlog_t *log, xlog_in_core_t *iclog);
-STATIC void     xlog_dealloc_log(xlog_t *log);
+STATIC int
+xlog_sync(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog);
+STATIC void
+xlog_dealloc_log(
+       struct xlog             *log);
 
 /* local state machine functions */
 STATIC void xlog_state_done_syncing(xlog_in_core_t *iclog, int);
-STATIC void xlog_state_do_callback(xlog_t *log,int aborted, xlog_in_core_t *iclog);
-STATIC int  xlog_state_get_iclog_space(xlog_t          *log,
-                                      int              len,
-                                      xlog_in_core_t   **iclog,
-                                      xlog_ticket_t    *ticket,
-                                      int              *continued_write,
-                                      int              *logoffsetp);
-STATIC int  xlog_state_release_iclog(xlog_t            *log,
-                                    xlog_in_core_t     *iclog);
-STATIC void xlog_state_switch_iclogs(xlog_t            *log,
-                                    xlog_in_core_t *iclog,
-                                    int                eventual_size);
-STATIC void xlog_state_want_sync(xlog_t        *log, xlog_in_core_t *iclog);
+STATIC void
+xlog_state_do_callback(
+       struct xlog             *log,
+       int                     aborted,
+       struct xlog_in_core     *iclog);
+STATIC int
+xlog_state_get_iclog_space(
+       struct xlog             *log,
+       int                     len,
+       struct xlog_in_core     **iclog,
+       struct xlog_ticket      *ticket,
+       int                     *continued_write,
+       int                     *logoffsetp);
+STATIC int
+xlog_state_release_iclog(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog);
+STATIC void
+xlog_state_switch_iclogs(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog,
+       int                     eventual_size);
+STATIC void
+xlog_state_want_sync(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog);
 
 STATIC void
 xlog_grant_push_ail(
-       struct xlog     *log,
-       int             need_bytes);
-STATIC void xlog_regrant_reserve_log_space(xlog_t       *log,
-                                          xlog_ticket_t *ticket);
-STATIC void xlog_ungrant_log_space(xlog_t       *log,
-                                  xlog_ticket_t *ticket);
+       struct xlog             *log,
+       int                     need_bytes);
+STATIC void
+xlog_regrant_reserve_log_space(
+       struct xlog             *log,
+       struct xlog_ticket      *ticket);
+STATIC void
+xlog_ungrant_log_space(
+       struct xlog             *log,
+       struct xlog_ticket      *ticket);
 
 #if defined(DEBUG)
-STATIC void    xlog_verify_dest_ptr(xlog_t *log, char *ptr);
+STATIC void
+xlog_verify_dest_ptr(
+       struct xlog             *log,
+       char                    *ptr);
 STATIC void
 xlog_verify_grant_tail(
-       struct xlog     *log);
-STATIC void    xlog_verify_iclog(xlog_t *log, xlog_in_core_t *iclog,
-                                 int count, boolean_t syncing);
-STATIC void    xlog_verify_tail_lsn(xlog_t *log, xlog_in_core_t *iclog,
-                                    xfs_lsn_t tail_lsn);
+       struct xlog *log);
+STATIC void
+xlog_verify_iclog(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog,
+       int                     count,
+       boolean_t               syncing);
+STATIC void
+xlog_verify_tail_lsn(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog,
+       xfs_lsn_t               tail_lsn);
 #else
 #define xlog_verify_dest_ptr(a,b)
 #define xlog_verify_grant_tail(a)
@@ -97,7 +131,9 @@ STATIC void  xlog_verify_tail_lsn(xlog_t *log, xlog_in_core_t *iclog,
 #define xlog_verify_tail_lsn(a,b,c)
 #endif
 
-STATIC int     xlog_iclogs_empty(xlog_t *log);
+STATIC int
+xlog_iclogs_empty(
+       struct xlog             *log);
 
 static void
 xlog_grant_sub_space(
@@ -684,7 +720,7 @@ xfs_log_mount_finish(xfs_mount_t *mp)
 int
 xfs_log_unmount_write(xfs_mount_t *mp)
 {
-       xlog_t           *log = mp->m_log;
+       struct xlog      *log = mp->m_log;
        xlog_in_core_t   *iclog;
 #ifdef DEBUG
        xlog_in_core_t   *first_iclog;
@@ -893,7 +929,7 @@ int
 xfs_log_need_covered(xfs_mount_t *mp)
 {
        int             needed = 0;
-       xlog_t          *log = mp->m_log;
+       struct xlog     *log = mp->m_log;
 
        if (!xfs_fs_writable(mp))
                return 0;
@@ -1024,9 +1060,9 @@ xlog_space_left(
 void
 xlog_iodone(xfs_buf_t *bp)
 {
-       xlog_in_core_t  *iclog = bp->b_fspriv;
-       xlog_t          *l = iclog->ic_log;
-       int             aborted = 0;
+       struct xlog_in_core     *iclog = bp->b_fspriv;
+       struct xlog             *l = iclog->ic_log;
+       int                     aborted = 0;
 
        /*
         * Race to shutdown the filesystem if we see an error.
@@ -1067,8 +1103,9 @@ xlog_iodone(xfs_buf_t *bp)
  */
 
 STATIC void
-xlog_get_iclog_buffer_size(xfs_mount_t *mp,
-                          xlog_t       *log)
+xlog_get_iclog_buffer_size(
+       struct xfs_mount        *mp,
+       struct xlog             *log)
 {
        int size;
        int xhdrs;
@@ -1129,13 +1166,14 @@ done:
  * Its primary purpose is to fill in enough, so recovery can occur.  However,
  * some other stuff may be filled in too.
  */
-STATIC xlog_t *
-xlog_alloc_log(xfs_mount_t     *mp,
-              xfs_buftarg_t    *log_target,
-              xfs_daddr_t      blk_offset,
-              int              num_bblks)
+STATIC struct xlog *
+xlog_alloc_log(
+       struct xfs_mount        *mp,
+       struct xfs_buftarg      *log_target,
+       xfs_daddr_t             blk_offset,
+       int                     num_bblks)
 {
-       xlog_t                  *log;
+       struct xlog             *log;
        xlog_rec_header_t       *head;
        xlog_in_core_t          **iclogp;
        xlog_in_core_t          *iclog, *prev_iclog=NULL;
@@ -1144,7 +1182,7 @@ xlog_alloc_log(xfs_mount_t        *mp,
        int                     error = ENOMEM;
        uint                    log2_size = 0;
 
-       log = kmem_zalloc(sizeof(xlog_t), KM_MAYFAIL);
+       log = kmem_zalloc(sizeof(struct xlog), KM_MAYFAIL);
        if (!log) {
                xfs_warn(mp, "Log allocation failed: No memory!");
                goto out;
@@ -1434,8 +1472,9 @@ xlog_bdstrat(
  */
 
 STATIC int
-xlog_sync(xlog_t               *log,
-         xlog_in_core_t        *iclog)
+xlog_sync(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog)
 {
        xfs_caddr_t     dptr;           /* pointer to byte sized element */
        xfs_buf_t       *bp;
@@ -1584,7 +1623,8 @@ xlog_sync(xlog_t          *log,
  * Deallocate a log structure
  */
 STATIC void
-xlog_dealloc_log(xlog_t *log)
+xlog_dealloc_log(
+       struct xlog     *log)
 {
        xlog_in_core_t  *iclog, *next_iclog;
        int             i;
@@ -1616,10 +1656,11 @@ xlog_dealloc_log(xlog_t *log)
  */
 /* ARGSUSED */
 static inline void
-xlog_state_finish_copy(xlog_t          *log,
-                      xlog_in_core_t   *iclog,
-                      int              record_cnt,
-                      int              copy_bytes)
+xlog_state_finish_copy(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog,
+       int                     record_cnt,
+       int                     copy_bytes)
 {
        spin_lock(&log->l_icloglock);
 
@@ -2142,7 +2183,8 @@ xlog_write(
  * State Change: DIRTY -> ACTIVE
  */
 STATIC void
-xlog_state_clean_log(xlog_t *log)
+xlog_state_clean_log(
+       struct xlog *log)
 {
        xlog_in_core_t  *iclog;
        int changed = 0;
@@ -2222,7 +2264,7 @@ xlog_state_clean_log(xlog_t *log)
 
 STATIC xfs_lsn_t
 xlog_get_lowest_lsn(
-       xlog_t          *log)
+       struct xlog     *log)
 {
        xlog_in_core_t  *lsn_log;
        xfs_lsn_t       lowest_lsn, lsn;
@@ -2245,9 +2287,9 @@ xlog_get_lowest_lsn(
 
 STATIC void
 xlog_state_do_callback(
-       xlog_t          *log,
-       int             aborted,
-       xlog_in_core_t  *ciclog)
+       struct xlog             *log,
+       int                     aborted,
+       struct xlog_in_core     *ciclog)
 {
        xlog_in_core_t     *iclog;
        xlog_in_core_t     *first_iclog;        /* used to know when we've
@@ -2467,7 +2509,7 @@ xlog_state_done_syncing(
        xlog_in_core_t  *iclog,
        int             aborted)
 {
-       xlog_t             *log = iclog->ic_log;
+       struct xlog        *log = iclog->ic_log;
 
        spin_lock(&log->l_icloglock);
 
@@ -2521,12 +2563,13 @@ xlog_state_done_syncing(
  *             is copied.
  */
 STATIC int
-xlog_state_get_iclog_space(xlog_t        *log,
-                          int            len,
-                          xlog_in_core_t **iclogp,
-                          xlog_ticket_t  *ticket,
-                          int            *continued_write,
-                          int            *logoffsetp)
+xlog_state_get_iclog_space(
+       struct xlog             *log,
+       int                     len,
+       struct xlog_in_core     **iclogp,
+       struct xlog_ticket      *ticket,
+       int                     *continued_write,
+       int                     *logoffsetp)
 {
        int               log_offset;
        xlog_rec_header_t *head;
@@ -2631,8 +2674,9 @@ restart:
  * move grant reservation head forward.
  */
 STATIC void
-xlog_regrant_reserve_log_space(xlog_t       *log,
-                              xlog_ticket_t *ticket)
+xlog_regrant_reserve_log_space(
+       struct xlog             *log,
+       struct xlog_ticket      *ticket)
 {
        trace_xfs_log_regrant_reserve_enter(log, ticket);
 
@@ -2677,8 +2721,9 @@ xlog_regrant_reserve_log_space(xlog_t          *log,
  * in the current reservation field.
  */
 STATIC void
-xlog_ungrant_log_space(xlog_t       *log,
-                      xlog_ticket_t *ticket)
+xlog_ungrant_log_space(
+       struct xlog             *log,
+       struct xlog_ticket      *ticket)
 {
        int     bytes;
 
@@ -2717,8 +2762,8 @@ xlog_ungrant_log_space(xlog_t          *log,
  */
 STATIC int
 xlog_state_release_iclog(
-       xlog_t          *log,
-       xlog_in_core_t  *iclog)
+       struct xlog             *log,
+       struct xlog_in_core     *iclog)
 {
        int             sync = 0;       /* do we sync? */
 
@@ -2768,9 +2813,10 @@ xlog_state_release_iclog(
  * that every data block.  We have run out of space in this log record.
  */
 STATIC void
-xlog_state_switch_iclogs(xlog_t                *log,
-                        xlog_in_core_t *iclog,
-                        int            eventual_size)
+xlog_state_switch_iclogs(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog,
+       int                     eventual_size)
 {
        ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE);
        if (!eventual_size)
@@ -3114,7 +3160,9 @@ xfs_log_force_lsn(
  * disk.
  */
 STATIC void
-xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog)
+xlog_state_want_sync(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog)
 {
        assert_spin_locked(&log->l_icloglock);
 
@@ -3158,7 +3206,7 @@ xfs_log_ticket_get(
 /*
  * Allocate and initialise a new log ticket.
  */
-xlog_ticket_t *
+struct xlog_ticket *
 xlog_ticket_alloc(
        struct xlog     *log,
        int             unit_bytes,
@@ -3346,9 +3394,10 @@ xlog_verify_grant_tail(
 
 /* check if it will fit */
 STATIC void
-xlog_verify_tail_lsn(xlog_t        *log,
-                    xlog_in_core_t *iclog,
-                    xfs_lsn_t      tail_lsn)
+xlog_verify_tail_lsn(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog,
+       xfs_lsn_t               tail_lsn)
 {
     int blocks;
 
@@ -3385,10 +3434,11 @@ xlog_verify_tail_lsn(xlog_t         *log,
  *     the cycle numbers agree with the current cycle number.
  */
 STATIC void
-xlog_verify_iclog(xlog_t        *log,
-                 xlog_in_core_t *iclog,
-                 int            count,
-                 boolean_t      syncing)
+xlog_verify_iclog(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog,
+       int                     count,
+       boolean_t               syncing)
 {
        xlog_op_header_t        *ophead;
        xlog_in_core_t          *icptr;
@@ -3482,7 +3532,7 @@ xlog_verify_iclog(xlog_t   *log,
  */
 STATIC int
 xlog_state_ioerror(
-       xlog_t  *log)
+       struct xlog     *log)
 {
        xlog_in_core_t  *iclog, *ic;
 
@@ -3527,7 +3577,7 @@ xfs_log_force_umount(
        struct xfs_mount        *mp,
        int                     logerror)
 {
-       xlog_t          *log;
+       struct xlog     *log;
        int             retval;
 
        log = mp->m_log;
@@ -3634,7 +3684,8 @@ xfs_log_force_umount(
 }
 
 STATIC int
-xlog_iclogs_empty(xlog_t *log)
+xlog_iclogs_empty(
+       struct xlog     *log)
 {
        xlog_in_core_t  *iclog;
 
index 72eba2201b1449aee4d52f5c0863549c9aedf7e9..18a801d76a4234e550427a83b6d6a65b7092d670 100644 (file)
@@ -487,7 +487,7 @@ struct xlog_grant_head {
  * overflow 31 bits worth of byte offset, so using a byte number will mean
  * that round off problems won't occur when releasing partial reservations.
  */
-typedef struct xlog {
+struct xlog {
        /* The following fields don't need locking */
        struct xfs_mount        *l_mp;          /* mount point */
        struct xfs_ail          *l_ailp;        /* AIL log is working with */
@@ -540,7 +540,7 @@ typedef struct xlog {
        char                    *l_iclog_bak[XLOG_MAX_ICLOGS];
 #endif
 
-} xlog_t;
+};
 
 #define XLOG_BUF_CANCEL_BUCKET(log, blkno) \
        ((log)->l_buf_cancel_table + ((__uint64_t)blkno % XLOG_BC_TABLE_SIZE))
@@ -548,9 +548,17 @@ typedef struct xlog {
 #define XLOG_FORCED_SHUTDOWN(log)      ((log)->l_flags & XLOG_IO_ERROR)
 
 /* common routines */
-extern int      xlog_recover(xlog_t *log);
-extern int      xlog_recover_finish(xlog_t *log);
-extern void     xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int);
+extern int
+xlog_recover(
+       struct xlog             *log);
+extern int
+xlog_recover_finish(
+       struct xlog             *log);
+extern void
+xlog_pack_data(
+       struct xlog             *log,
+       struct xlog_in_core     *iclog,
+       int);
 
 extern kmem_zone_t *xfs_log_ticket_zone;
 struct xlog_ticket *
index a7be98abd6a90327ae9a0993ef65f2bc7f005e1c..5da3ace352bffe6ca32d16ae76fc131291914a00 100644 (file)
 #include "xfs_utils.h"
 #include "xfs_trace.h"
 
-STATIC int     xlog_find_zeroed(xlog_t *, xfs_daddr_t *);
-STATIC int     xlog_clear_stale_blocks(xlog_t *, xfs_lsn_t);
+STATIC int
+xlog_find_zeroed(
+       struct xlog     *,
+       xfs_daddr_t     *);
+STATIC int
+xlog_clear_stale_blocks(
+       struct xlog     *,
+       xfs_lsn_t);
 #if defined(DEBUG)
-STATIC void    xlog_recover_check_summary(xlog_t *);
+STATIC void
+xlog_recover_check_summary(
+       struct xlog *);
 #else
 #define        xlog_recover_check_summary(log)
 #endif
@@ -74,7 +82,7 @@ struct xfs_buf_cancel {
 
 static inline int
 xlog_buf_bbcount_valid(
-       xlog_t          *log,
+       struct xlog     *log,
        int             bbcount)
 {
        return bbcount > 0 && bbcount <= log->l_logBBsize;
@@ -87,7 +95,7 @@ xlog_buf_bbcount_valid(
  */
 STATIC xfs_buf_t *
 xlog_get_bp(
-       xlog_t          *log,
+       struct xlog     *log,
        int             nbblks)
 {
        struct xfs_buf  *bp;
@@ -138,10 +146,10 @@ xlog_put_bp(
  */
 STATIC xfs_caddr_t
 xlog_align(
-       xlog_t          *log,
+       struct xlog     *log,
        xfs_daddr_t     blk_no,
        int             nbblks,
-       xfs_buf_t       *bp)
+       struct xfs_buf  *bp)
 {
        xfs_daddr_t     offset = blk_no & ((xfs_daddr_t)log->l_sectBBsize - 1);
 
@@ -155,10 +163,10 @@ xlog_align(
  */
 STATIC int
 xlog_bread_noalign(
-       xlog_t          *log,
+       struct xlog     *log,
        xfs_daddr_t     blk_no,
        int             nbblks,
-       xfs_buf_t       *bp)
+       struct xfs_buf  *bp)
 {
        int             error;
 
@@ -189,10 +197,10 @@ xlog_bread_noalign(
 
 STATIC int
 xlog_bread(
-       xlog_t          *log,
+       struct xlog     *log,
        xfs_daddr_t     blk_no,
        int             nbblks,
-       xfs_buf_t       *bp,
+       struct xfs_buf  *bp,
        xfs_caddr_t     *offset)
 {
        int             error;
@@ -211,10 +219,10 @@ xlog_bread(
  */
 STATIC int
 xlog_bread_offset(
-       xlog_t          *log,
+       struct xlog     *log,
        xfs_daddr_t     blk_no,         /* block to read from */
        int             nbblks,         /* blocks to read */
-       xfs_buf_t       *bp,
+       struct xfs_buf  *bp,
        xfs_caddr_t     offset)
 {
        xfs_caddr_t     orig_offset = bp->b_addr;
@@ -241,10 +249,10 @@ xlog_bread_offset(
  */
 STATIC int
 xlog_bwrite(
-       xlog_t          *log,
+       struct xlog     *log,
        xfs_daddr_t     blk_no,
        int             nbblks,
-       xfs_buf_t       *bp)
+       struct xfs_buf  *bp)
 {
        int             error;
 
@@ -378,8 +386,8 @@ xlog_recover_iodone(
  */
 STATIC int
 xlog_find_cycle_start(
-       xlog_t          *log,
-       xfs_buf_t       *bp,
+       struct xlog     *log,
+       struct xfs_buf  *bp,
        xfs_daddr_t     first_blk,
        xfs_daddr_t     *last_blk,
        uint            cycle)
@@ -421,7 +429,7 @@ xlog_find_cycle_start(
  */
 STATIC int
 xlog_find_verify_cycle(
-       xlog_t          *log,
+       struct xlog     *log,
        xfs_daddr_t     start_blk,
        int             nbblks,
        uint            stop_on_cycle_no,
@@ -490,7 +498,7 @@ out:
  */
 STATIC int
 xlog_find_verify_log_record(
-       xlog_t                  *log,
+       struct xlog             *log,
        xfs_daddr_t             start_blk,
        xfs_daddr_t             *last_blk,
        int                     extra_bblks)
@@ -600,7 +608,7 @@ out:
  */
 STATIC int
 xlog_find_head(
-       xlog_t          *log,
+       struct xlog     *log,
        xfs_daddr_t     *return_head_blk)
 {
        xfs_buf_t       *bp;
@@ -871,7 +879,7 @@ validate_head:
  */
 STATIC int
 xlog_find_tail(
-       xlog_t                  *log,
+       struct xlog             *log,
        xfs_daddr_t             *head_blk,
        xfs_daddr_t             *tail_blk)
 {
@@ -1080,7 +1088,7 @@ done:
  */
 STATIC int
 xlog_find_zeroed(
-       xlog_t          *log,
+       struct xlog     *log,
        xfs_daddr_t     *blk_no)
 {
        xfs_buf_t       *bp;
@@ -1183,7 +1191,7 @@ bp_err:
  */
 STATIC void
 xlog_add_record(
-       xlog_t                  *log,
+       struct xlog             *log,
        xfs_caddr_t             buf,
        int                     cycle,
        int                     block,
@@ -1205,7 +1213,7 @@ xlog_add_record(
 
 STATIC int
 xlog_write_log_records(
-       xlog_t          *log,
+       struct xlog     *log,
        int             cycle,
        int             start_block,
        int             blocks,
@@ -1305,7 +1313,7 @@ xlog_write_log_records(
  */
 STATIC int
 xlog_clear_stale_blocks(
-       xlog_t          *log,
+       struct xlog     *log,
        xfs_lsn_t       tail_lsn)
 {
        int             tail_cycle, head_cycle;
@@ -2050,11 +2058,11 @@ xfs_qm_dqcheck(
  */
 STATIC void
 xlog_recover_do_dquot_buffer(
-       xfs_mount_t             *mp,
-       xlog_t                  *log,
-       xlog_recover_item_t     *item,
-       xfs_buf_t               *bp,
-       xfs_buf_log_format_t    *buf_f)
+       struct xfs_mount                *mp,
+       struct xlog                     *log,
+       struct xlog_recover_item        *item,
+       struct xfs_buf                  *bp,
+       struct xfs_buf_log_format       *buf_f)
 {
        uint                    type;
 
@@ -2108,9 +2116,9 @@ xlog_recover_do_dquot_buffer(
  */
 STATIC int
 xlog_recover_buffer_pass2(
-       xlog_t                  *log,
-       struct list_head        *buffer_list,
-       xlog_recover_item_t     *item)
+       struct xlog                     *log,
+       struct list_head                *buffer_list,
+       struct xlog_recover_item        *item)
 {
        xfs_buf_log_format_t    *buf_f = item->ri_buf[0].i_addr;
        xfs_mount_t             *mp = log->l_mp;
@@ -2189,9 +2197,9 @@ xlog_recover_buffer_pass2(
 
 STATIC int
 xlog_recover_inode_pass2(
-       xlog_t                  *log,
-       struct list_head        *buffer_list,
-       xlog_recover_item_t     *item)
+       struct xlog                     *log,
+       struct list_head                *buffer_list,
+       struct xlog_recover_item        *item)
 {
        xfs_inode_log_format_t  *in_f;
        xfs_mount_t             *mp = log->l_mp;
@@ -2452,14 +2460,14 @@ error:
 }
 
 /*
- * Recover QUOTAOFF records. We simply make a note of it in the xlog_t
+ * Recover QUOTAOFF records. We simply make a note of it in the xlog
  * structure, so that we know not to do any dquot item or dquot buffer recovery,
  * of that type.
  */
 STATIC int
 xlog_recover_quotaoff_pass1(
-       xlog_t                  *log,
-       xlog_recover_item_t     *item)
+       struct xlog                     *log,
+       struct xlog_recover_item        *item)
 {
        xfs_qoff_logformat_t    *qoff_f = item->ri_buf[0].i_addr;
        ASSERT(qoff_f);
@@ -2483,9 +2491,9 @@ xlog_recover_quotaoff_pass1(
  */
 STATIC int
 xlog_recover_dquot_pass2(
-       xlog_t                  *log,
-       struct list_head        *buffer_list,
-       xlog_recover_item_t     *item)
+       struct xlog                     *log,
+       struct list_head                *buffer_list,
+       struct xlog_recover_item        *item)
 {
        xfs_mount_t             *mp = log->l_mp;
        xfs_buf_t               *bp;
@@ -2578,9 +2586,9 @@ xlog_recover_dquot_pass2(
  */
 STATIC int
 xlog_recover_efi_pass2(
-       xlog_t                  *log,
-       xlog_recover_item_t     *item,
-       xfs_lsn_t               lsn)
+       struct xlog                     *log,
+       struct xlog_recover_item        *item,
+       xfs_lsn_t                       lsn)
 {
        int                     error;
        xfs_mount_t             *mp = log->l_mp;
@@ -2616,8 +2624,8 @@ xlog_recover_efi_pass2(
  */
 STATIC int
 xlog_recover_efd_pass2(
-       xlog_t                  *log,
-       xlog_recover_item_t     *item)
+       struct xlog                     *log,
+       struct xlog_recover_item        *item)
 {
        xfs_efd_log_format_t    *efd_formatp;
        xfs_efi_log_item_t      *efip = NULL;
@@ -2812,9 +2820,9 @@ xlog_recover_unmount_trans(
  */
 STATIC int
 xlog_recover_process_data(
-       xlog_t                  *log,
+       struct xlog             *log,
        struct hlist_head       rhash[],
-       xlog_rec_header_t       *rhead,
+       struct xlog_rec_header  *rhead,
        xfs_caddr_t             dp,
        int                     pass)
 {
@@ -2986,7 +2994,7 @@ abort_error:
  */
 STATIC int
 xlog_recover_process_efis(
-       xlog_t                  *log)
+       struct xlog     *log)
 {
        xfs_log_item_t          *lip;
        xfs_efi_log_item_t      *efip;
@@ -3098,7 +3106,7 @@ xlog_recover_process_one_iunlink(
        /*
         * Get the on disk inode to find the next inode in the bucket.
         */
-       error = xfs_itobp(mp, NULL, ip, &dip, &ibp, 0);
+       error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &ibp, 0, 0);
        if (error)
                goto fail_iput;
 
@@ -3147,7 +3155,7 @@ xlog_recover_process_one_iunlink(
  */
 STATIC void
 xlog_recover_process_iunlinks(
-       xlog_t          *log)
+       struct xlog     *log)
 {
        xfs_mount_t     *mp;
        xfs_agnumber_t  agno;
@@ -3209,9 +3217,9 @@ xlog_recover_process_iunlinks(
 #ifdef DEBUG
 STATIC void
 xlog_pack_data_checksum(
-       xlog_t          *log,
-       xlog_in_core_t  *iclog,
-       int             size)
+       struct xlog             *log,
+       struct xlog_in_core     *iclog,
+       int                     size)
 {
        int             i;
        __be32          *up;
@@ -3234,8 +3242,8 @@ xlog_pack_data_checksum(
  */
 void
 xlog_pack_data(
-       xlog_t                  *log,
-       xlog_in_core_t          *iclog,
+       struct xlog             *log,
+       struct xlog_in_core     *iclog,
        int                     roundoff)
 {
        int                     i, j, k;
@@ -3274,9 +3282,9 @@ xlog_pack_data(
 
 STATIC void
 xlog_unpack_data(
-       xlog_rec_header_t       *rhead,
+       struct xlog_rec_header  *rhead,
        xfs_caddr_t             dp,
-       xlog_t                  *log)
+       struct xlog             *log)
 {
        int                     i, j, k;
 
@@ -3299,8 +3307,8 @@ xlog_unpack_data(
 
 STATIC int
 xlog_valid_rec_header(
-       xlog_t                  *log,
-       xlog_rec_header_t       *rhead,
+       struct xlog             *log,
+       struct xlog_rec_header  *rhead,
        xfs_daddr_t             blkno)
 {
        int                     hlen;
@@ -3343,7 +3351,7 @@ xlog_valid_rec_header(
  */
 STATIC int
 xlog_do_recovery_pass(
-       xlog_t                  *log,
+       struct xlog             *log,
        xfs_daddr_t             head_blk,
        xfs_daddr_t             tail_blk,
        int                     pass)
@@ -3595,7 +3603,7 @@ xlog_do_recovery_pass(
  */
 STATIC int
 xlog_do_log_recovery(
-       xlog_t          *log,
+       struct xlog     *log,
        xfs_daddr_t     head_blk,
        xfs_daddr_t     tail_blk)
 {
@@ -3646,7 +3654,7 @@ xlog_do_log_recovery(
  */
 STATIC int
 xlog_do_recover(
-       xlog_t          *log,
+       struct xlog     *log,
        xfs_daddr_t     head_blk,
        xfs_daddr_t     tail_blk)
 {
@@ -3721,7 +3729,7 @@ xlog_do_recover(
  */
 int
 xlog_recover(
-       xlog_t          *log)
+       struct xlog     *log)
 {
        xfs_daddr_t     head_blk, tail_blk;
        int             error;
@@ -3767,7 +3775,7 @@ xlog_recover(
  */
 int
 xlog_recover_finish(
-       xlog_t          *log)
+       struct xlog     *log)
 {
        /*
         * Now we're ready to do the transactions needed for the
@@ -3814,7 +3822,7 @@ xlog_recover_finish(
  */
 void
 xlog_recover_check_summary(
-       xlog_t          *log)
+       struct xlog     *log)
 {
        xfs_mount_t     *mp;
        xfs_agf_t       *agfp;
index 536021fb3d4e338a0e694ac069191c0b0d4d0cf0..711ca51ca3d70b61d2abae52abcc4b4a29fdde02 100644 (file)
@@ -1200,8 +1200,6 @@ xfs_mountfs(
 
        xfs_set_maxicount(mp);
 
-       mp->m_maxioffset = xfs_max_file_offset(sbp->sb_blocklog);
-
        error = xfs_uuid_mount(mp);
        if (error)
                goto out;
@@ -1531,6 +1529,15 @@ xfs_unmountfs(
        xfs_ail_push_all_sync(mp->m_ail);
        xfs_wait_buftarg(mp->m_ddev_targp);
 
+       /*
+        * The superblock buffer is uncached and xfsaild_push() will lock and
+        * set the XBF_ASYNC flag on the buffer. We cannot do xfs_buf_iowait()
+        * here but a lock on the superblock buffer will block until iodone()
+        * has completed.
+        */
+       xfs_buf_lock(mp->m_sb_bp);
+       xfs_buf_unlock(mp->m_sb_bp);
+
        xfs_log_unmount_write(mp);
        xfs_log_unmount(mp);
        xfs_uuid_unmount(mp);
index 90c1fc9eaea4d9c7be48c5ef219e7598f6e47f54..8724336a9a08ce2528ffd3bb521f89ace2c97428 100644 (file)
@@ -176,7 +176,6 @@ typedef struct xfs_mount {
        uint                    m_qflags;       /* quota status flags */
        xfs_trans_reservations_t m_reservations;/* precomputed res values */
        __uint64_t              m_maxicount;    /* maximum inode count */
-       __uint64_t              m_maxioffset;   /* maximum inode offset */
        __uint64_t              m_resblks;      /* total reserved blocks */
        __uint64_t              m_resblks_avail;/* available reserved blocks */
        __uint64_t              m_resblks_save; /* reserved blks @ remount,ro */
@@ -297,8 +296,6 @@ xfs_preferred_iosize(xfs_mount_t *mp)
                        PAGE_CACHE_SIZE));
 }
 
-#define XFS_MAXIOFFSET(mp)     ((mp)->m_maxioffset)
-
 #define XFS_LAST_UNMOUNT_WAS_CLEAN(mp) \
                                ((mp)->m_flags & XFS_MOUNT_WAS_CLEAN)
 #define XFS_FORCED_SHUTDOWN(mp)        ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN)
index 249db1987764586c37c3b6d75a2fd1c78cae3c48..2e86fa0cfc0d660374b2d8860f7c30e059b94e2b 100644 (file)
@@ -940,7 +940,7 @@ xfs_qm_dqiterate(
        map = kmem_alloc(XFS_DQITER_MAP_SIZE * sizeof(*map), KM_SLEEP);
 
        lblkno = 0;
-       maxlblkcnt = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
+       maxlblkcnt = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
        do {
                nmaps = XFS_DQITER_MAP_SIZE;
                /*
index 0d9de41a7151568621cfad89a1a95a97b2ba8b4a..bdaf4cb9f4a2d19fc8b781f232f61d88c529ac2a 100644 (file)
@@ -868,67 +868,14 @@ xfs_fs_inode_init_once(
                     "xfsino", ip->i_ino);
 }
 
-/*
- * This is called by the VFS when dirtying inode metadata.  This can happen
- * for a few reasons, but we only care about timestamp updates, given that
- * we handled the rest ourselves.  In theory no other calls should happen,
- * but for example generic_write_end() keeps dirtying the inode after
- * updating i_size.  Thus we check that the flags are exactly I_DIRTY_SYNC,
- * and skip this call otherwise.
- *
- * We'll hopefull get a different method just for updating timestamps soon,
- * at which point this hack can go away, and maybe we'll also get real
- * error handling here.
- */
-STATIC void
-xfs_fs_dirty_inode(
-       struct inode            *inode,
-       int                     flags)
-{
-       struct xfs_inode        *ip = XFS_I(inode);
-       struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_trans        *tp;
-       int                     error;
-
-       if (flags != I_DIRTY_SYNC)
-               return;
-
-       trace_xfs_dirty_inode(ip);
-
-       tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
-       error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
-       if (error) {
-               xfs_trans_cancel(tp, 0);
-               goto trouble;
-       }
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       /*
-        * Grab all the latest timestamps from the Linux inode.
-        */
-       ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec;
-       ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec;
-       ip->i_d.di_ctime.t_sec = (__int32_t)inode->i_ctime.tv_sec;
-       ip->i_d.di_ctime.t_nsec = (__int32_t)inode->i_ctime.tv_nsec;
-       ip->i_d.di_mtime.t_sec = (__int32_t)inode->i_mtime.tv_sec;
-       ip->i_d.di_mtime.t_nsec = (__int32_t)inode->i_mtime.tv_nsec;
-
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-       xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP);
-       error = xfs_trans_commit(tp, 0);
-       if (error)
-               goto trouble;
-       return;
-
-trouble:
-       xfs_warn(mp, "failed to update timestamps for inode 0x%llx", ip->i_ino);
-}
-
 STATIC void
 xfs_fs_evict_inode(
        struct inode            *inode)
 {
        xfs_inode_t             *ip = XFS_I(inode);
 
+       ASSERT(!rwsem_is_locked(&ip->i_iolock.mr_lock));
+
        trace_xfs_evict_inode(ip);
 
        truncate_inode_pages(&inode->i_data, 0);
@@ -937,22 +884,6 @@ xfs_fs_evict_inode(
        XFS_STATS_INC(vn_remove);
        XFS_STATS_DEC(vn_active);
 
-       /*
-        * The iolock is used by the file system to coordinate reads,
-        * writes, and block truncates.  Up to this point the lock
-        * protected concurrent accesses by users of the inode.  But
-        * from here forward we're doing some final processing of the
-        * inode because we're done with it, and although we reuse the
-        * iolock for protection it is really a distinct lock class
-        * (in the lockdep sense) from before.  To keep lockdep happy
-        * (and basically indicate what we are doing), we explicitly
-        * re-init the iolock here.
-        */
-       ASSERT(!rwsem_is_locked(&ip->i_iolock.mr_lock));
-       mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino);
-       lockdep_set_class_and_name(&ip->i_iolock.mr_lock,
-                       &xfs_iolock_reclaimable, "xfs_iolock_reclaimable");
-
        xfs_inactive(ip);
 }
 
@@ -1436,7 +1367,6 @@ xfs_fs_free_cached_objects(
 static const struct super_operations xfs_super_operations = {
        .alloc_inode            = xfs_fs_alloc_inode,
        .destroy_inode          = xfs_fs_destroy_inode,
-       .dirty_inode            = xfs_fs_dirty_inode,
        .evict_inode            = xfs_fs_evict_inode,
        .drop_inode             = xfs_fs_drop_inode,
        .put_super              = xfs_fs_put_super,
@@ -1491,13 +1421,9 @@ xfs_init_zones(void)
        if (!xfs_da_state_zone)
                goto out_destroy_btree_cur_zone;
 
-       xfs_dabuf_zone = kmem_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf");
-       if (!xfs_dabuf_zone)
-               goto out_destroy_da_state_zone;
-
        xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork");
        if (!xfs_ifork_zone)
-               goto out_destroy_dabuf_zone;
+               goto out_destroy_da_state_zone;
 
        xfs_trans_zone = kmem_zone_init(sizeof(xfs_trans_t), "xfs_trans");
        if (!xfs_trans_zone)
@@ -1514,9 +1440,8 @@ xfs_init_zones(void)
         * size possible under XFS.  This wastes a little bit of memory,
         * but it is much faster.
         */
-       xfs_buf_item_zone = kmem_zone_init((sizeof(xfs_buf_log_item_t) +
-                               (((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) /
-                                 NBWORD) * sizeof(int))), "xfs_buf_item");
+       xfs_buf_item_zone = kmem_zone_init(sizeof(struct xfs_buf_log_item),
+                                          "xfs_buf_item");
        if (!xfs_buf_item_zone)
                goto out_destroy_log_item_desc_zone;
 
@@ -1561,8 +1486,6 @@ xfs_init_zones(void)
        kmem_zone_destroy(xfs_trans_zone);
  out_destroy_ifork_zone:
        kmem_zone_destroy(xfs_ifork_zone);
- out_destroy_dabuf_zone:
-       kmem_zone_destroy(xfs_dabuf_zone);
  out_destroy_da_state_zone:
        kmem_zone_destroy(xfs_da_state_zone);
  out_destroy_btree_cur_zone:
@@ -1590,7 +1513,6 @@ xfs_destroy_zones(void)
        kmem_zone_destroy(xfs_log_item_desc_zone);
        kmem_zone_destroy(xfs_trans_zone);
        kmem_zone_destroy(xfs_ifork_zone);
-       kmem_zone_destroy(xfs_dabuf_zone);
        kmem_zone_destroy(xfs_da_state_zone);
        kmem_zone_destroy(xfs_btree_cur_zone);
        kmem_zone_destroy(xfs_bmap_free_item_zone);
index 1e9ee064dbb28c7cb491d4c41dce53007eebc7e9..97304f10e78a4970516e3d235ab8d1585c94d40b 100644 (file)
@@ -359,6 +359,15 @@ xfs_quiesce_attr(
         * added an item to the AIL, thus flush it again.
         */
        xfs_ail_push_all_sync(mp->m_ail);
+
+       /*
+        * The superblock buffer is uncached and xfsaild_push() will lock and
+        * set the XBF_ASYNC flag on the buffer. We cannot do xfs_buf_iowait()
+        * here but a lock on the superblock buffer will block until iodone()
+        * has completed.
+        */
+       xfs_buf_lock(mp->m_sb_bp);
+       xfs_buf_unlock(mp->m_sb_bp);
 }
 
 static void
@@ -712,8 +721,8 @@ restart:
         * Note that xfs_iflush will never block on the inode buffer lock, as
         * xfs_ifree_cluster() can lock the inode buffer before it locks the
         * ip->i_lock, and we are doing the exact opposite here.  As a result,
-        * doing a blocking xfs_itobp() to get the cluster buffer would result
-        * in an ABBA deadlock with xfs_ifree_cluster().
+        * doing a blocking xfs_imap_to_bp() to get the cluster buffer would
+        * result in an ABBA deadlock with xfs_ifree_cluster().
         *
         * As xfs_ifree_cluser() must gather all inodes that are active in the
         * cache to mark them stale, if we hit this case we don't actually want
index caf5dabfd55347b292664e86654f04bbe62d7a98..e5795dd6013ad2b34d5a208d1cf7ad448c937387 100644 (file)
@@ -578,8 +578,8 @@ DEFINE_INODE_EVENT(xfs_ioctl_setattr);
 DEFINE_INODE_EVENT(xfs_dir_fsync);
 DEFINE_INODE_EVENT(xfs_file_fsync);
 DEFINE_INODE_EVENT(xfs_destroy_inode);
-DEFINE_INODE_EVENT(xfs_dirty_inode);
 DEFINE_INODE_EVENT(xfs_evict_inode);
+DEFINE_INODE_EVENT(xfs_update_time);
 
 DEFINE_INODE_EVENT(xfs_dquot_dqalloc);
 DEFINE_INODE_EVENT(xfs_dquot_dqdetach);
index 7c37b533aa8e5c169f0ef98643f96958df3788df..bc2afd52a0b7eed5d3e039c7474f9dcac3ed41cb 100644 (file)
@@ -448,11 +448,51 @@ xfs_trans_t       *xfs_trans_dup(xfs_trans_t *);
 int            xfs_trans_reserve(xfs_trans_t *, uint, uint, uint,
                                  uint, uint);
 void           xfs_trans_mod_sb(xfs_trans_t *, uint, int64_t);
-struct xfs_buf *xfs_trans_get_buf(xfs_trans_t *, struct xfs_buftarg *, xfs_daddr_t,
-                                  int, uint);
-int            xfs_trans_read_buf(struct xfs_mount *, xfs_trans_t *,
-                                  struct xfs_buftarg *, xfs_daddr_t, int, uint,
-                                  struct xfs_buf **);
+
+struct xfs_buf *xfs_trans_get_buf_map(struct xfs_trans *tp,
+                                      struct xfs_buftarg *target,
+                                      struct xfs_buf_map *map, int nmaps,
+                                      uint flags);
+
+static inline struct xfs_buf *
+xfs_trans_get_buf(
+       struct xfs_trans        *tp,
+       struct xfs_buftarg      *target,
+       xfs_daddr_t             blkno,
+       int                     numblks,
+       uint                    flags)
+{
+       struct xfs_buf_map      map = {
+               .bm_bn = blkno,
+               .bm_len = numblks,
+       };
+       return xfs_trans_get_buf_map(tp, target, &map, 1, flags);
+}
+
+int            xfs_trans_read_buf_map(struct xfs_mount *mp,
+                                      struct xfs_trans *tp,
+                                      struct xfs_buftarg *target,
+                                      struct xfs_buf_map *map, int nmaps,
+                                      xfs_buf_flags_t flags,
+                                      struct xfs_buf **bpp);
+
+static inline int
+xfs_trans_read_buf(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       struct xfs_buftarg      *target,
+       xfs_daddr_t             blkno,
+       int                     numblks,
+       xfs_buf_flags_t         flags,
+       struct xfs_buf          **bpp)
+{
+       struct xfs_buf_map      map = {
+               .bm_bn = blkno,
+               .bm_len = numblks,
+       };
+       return xfs_trans_read_buf_map(mp, tp, target, &map, 1, flags, bpp);
+}
+
 struct xfs_buf *xfs_trans_getsb(xfs_trans_t *, struct xfs_mount *, int);
 
 void           xfs_trans_brelse(xfs_trans_t *, struct xfs_buf *);
index 9c514483e59924eecb6e64c95bb198af2de5e606..6011ee6613396f9b325418fde28e07c2147f0e5e 100644 (file)
@@ -383,6 +383,12 @@ xfsaild_push(
        }
 
        spin_lock(&ailp->xa_lock);
+
+       /* barrier matches the xa_target update in xfs_ail_push() */
+       smp_rmb();
+       target = ailp->xa_target;
+       ailp->xa_target_prev = target;
+
        lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->xa_last_pushed_lsn);
        if (!lip) {
                /*
@@ -397,7 +403,6 @@ xfsaild_push(
        XFS_STATS_INC(xs_push_ail);
 
        lsn = lip->li_lsn;
-       target = ailp->xa_target;
        while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) {
                int     lock_result;
 
@@ -527,8 +532,32 @@ xfsaild(
                        __set_current_state(TASK_KILLABLE);
                else
                        __set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(tout ?
-                                msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT);
+
+               spin_lock(&ailp->xa_lock);
+
+               /*
+                * Idle if the AIL is empty and we are not racing with a target
+                * update. We check the AIL after we set the task to a sleep
+                * state to guarantee that we either catch an xa_target update
+                * or that a wake_up resets the state to TASK_RUNNING.
+                * Otherwise, we run the risk of sleeping indefinitely.
+                *
+                * The barrier matches the xa_target update in xfs_ail_push().
+                */
+               smp_rmb();
+               if (!xfs_ail_min(ailp) &&
+                   ailp->xa_target == ailp->xa_target_prev) {
+                       spin_unlock(&ailp->xa_lock);
+                       schedule();
+                       tout = 0;
+                       continue;
+               }
+               spin_unlock(&ailp->xa_lock);
+
+               if (tout)
+                       schedule_timeout(msecs_to_jiffies(tout));
+
+               __set_current_state(TASK_RUNNING);
 
                try_to_freeze();
 
index 21c5a5e3700d066d05b19fa2ac1a47f19e952eb1..6311b99c267f69fe3ac1e7cc4d72a7681e96415d 100644 (file)
@@ -41,20 +41,26 @@ STATIC struct xfs_buf *
 xfs_trans_buf_item_match(
        struct xfs_trans        *tp,
        struct xfs_buftarg      *target,
-       xfs_daddr_t             blkno,
-       int                     len)
+       struct xfs_buf_map      *map,
+       int                     nmaps)
 {
        struct xfs_log_item_desc *lidp;
        struct xfs_buf_log_item *blip;
+       int                     len = 0;
+       int                     i;
+
+       for (i = 0; i < nmaps; i++)
+               len += map[i].bm_len;
 
-       len = BBTOB(len);
        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 &&
                    blip->bli_buf->b_target == target &&
-                   XFS_BUF_ADDR(blip->bli_buf) == blkno &&
-                   BBTOB(blip->bli_buf->b_length) == len)
+                   XFS_BUF_ADDR(blip->bli_buf) == map[0].bm_bn &&
+                   blip->bli_buf->b_length == len) {
+                       ASSERT(blip->bli_buf->b_map_count == nmaps);
                        return blip->bli_buf;
+               }
        }
 
        return NULL;
@@ -128,21 +134,19 @@ xfs_trans_bjoin(
  * If the transaction pointer is NULL, make this just a normal
  * get_buf() call.
  */
-xfs_buf_t *
-xfs_trans_get_buf(xfs_trans_t  *tp,
-                 xfs_buftarg_t *target_dev,
-                 xfs_daddr_t   blkno,
-                 int           len,
-                 uint          flags)
+struct xfs_buf *
+xfs_trans_get_buf_map(
+       struct xfs_trans        *tp,
+       struct xfs_buftarg      *target,
+       struct xfs_buf_map      *map,
+       int                     nmaps,
+       xfs_buf_flags_t         flags)
 {
        xfs_buf_t               *bp;
        xfs_buf_log_item_t      *bip;
 
-       /*
-        * Default to a normal get_buf() call if the tp is NULL.
-        */
-       if (tp == NULL)
-               return xfs_buf_get(target_dev, blkno, len, flags);
+       if (!tp)
+               return xfs_buf_get_map(target, map, nmaps, flags);
 
        /*
         * If we find the buffer in the cache with this transaction
@@ -150,7 +154,7 @@ xfs_trans_get_buf(xfs_trans_t       *tp,
         * have it locked.  In this case we just increment the lock
         * recursion count and return the buffer to the caller.
         */
-       bp = xfs_trans_buf_item_match(tp, target_dev, blkno, len);
+       bp = xfs_trans_buf_item_match(tp, target, map, nmaps);
        if (bp != NULL) {
                ASSERT(xfs_buf_islocked(bp));
                if (XFS_FORCED_SHUTDOWN(tp->t_mountp)) {
@@ -167,7 +171,7 @@ xfs_trans_get_buf(xfs_trans_t       *tp,
                return (bp);
        }
 
-       bp = xfs_buf_get(target_dev, blkno, len, flags);
+       bp = xfs_buf_get_map(target, map, nmaps, flags);
        if (bp == NULL) {
                return NULL;
        }
@@ -246,26 +250,22 @@ int       xfs_error_mod = 33;
  * read_buf() call.
  */
 int
-xfs_trans_read_buf(
-       xfs_mount_t     *mp,
-       xfs_trans_t     *tp,
-       xfs_buftarg_t   *target,
-       xfs_daddr_t     blkno,
-       int             len,
-       uint            flags,
-       xfs_buf_t       **bpp)
+xfs_trans_read_buf_map(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       struct xfs_buftarg      *target,
+       struct xfs_buf_map      *map,
+       int                     nmaps,
+       xfs_buf_flags_t         flags,
+       struct xfs_buf          **bpp)
 {
        xfs_buf_t               *bp;
        xfs_buf_log_item_t      *bip;
        int                     error;
 
        *bpp = NULL;
-
-       /*
-        * Default to a normal get_buf() call if the tp is NULL.
-        */
-       if (tp == NULL) {
-               bp = xfs_buf_read(target, blkno, len, flags);
+       if (!tp) {
+               bp = xfs_buf_read_map(target, map, nmaps, flags);
                if (!bp)
                        return (flags & XBF_TRYLOCK) ?
                                        EAGAIN : XFS_ERROR(ENOMEM);
@@ -303,7 +303,7 @@ xfs_trans_read_buf(
         * If the buffer is not yet read in, then we read it in, increment
         * the lock recursion count, and return it to the caller.
         */
-       bp = xfs_trans_buf_item_match(tp, target, blkno, len);
+       bp = xfs_trans_buf_item_match(tp, target, map, nmaps);
        if (bp != NULL) {
                ASSERT(xfs_buf_islocked(bp));
                ASSERT(bp->b_transp == tp);
@@ -349,7 +349,7 @@ xfs_trans_read_buf(
                return 0;
        }
 
-       bp = xfs_buf_read(target, blkno, len, flags);
+       bp = xfs_buf_read_map(target, map, nmaps, flags);
        if (bp == NULL) {
                *bpp = NULL;
                return (flags & XBF_TRYLOCK) ?
index fb62377d1cbc73305ab84afc360afb6eb24c9d9c..53b7c9b0f8f7a6fa3c96a3f73298c2862eb3d107 100644 (file)
@@ -67,6 +67,7 @@ struct xfs_ail {
        struct task_struct      *xa_task;
        struct list_head        xa_ail;
        xfs_lsn_t               xa_target;
+       xfs_lsn_t               xa_target_prev;
        struct list_head        xa_cursors;
        spinlock_t              xa_lock;
        xfs_lsn_t               xa_last_pushed_lsn;
index 398cf681d025d9c5de3cb189d212acd0224acb7b..7a41874f4c209b7a405486ce123be374efa9c148 100644 (file)
@@ -132,6 +132,20 @@ typedef __uint64_t xfs_filblks_t;  /* number of blocks in a file */
 #define        MAXEXTNUM       ((xfs_extnum_t)0x7fffffff)      /* signed int */
 #define        MAXAEXTNUM      ((xfs_aextnum_t)0x7fff)         /* signed short */
 
+/*
+ * Minimum and maximum blocksize and sectorsize.
+ * The blocksize upper limit is pretty much arbitrary.
+ * The sectorsize upper limit is due to sizeof(sb_sectsize).
+ */
+#define XFS_MIN_BLOCKSIZE_LOG  9       /* i.e. 512 bytes */
+#define XFS_MAX_BLOCKSIZE_LOG  16      /* i.e. 65536 bytes */
+#define XFS_MIN_BLOCKSIZE      (1 << XFS_MIN_BLOCKSIZE_LOG)
+#define XFS_MAX_BLOCKSIZE      (1 << XFS_MAX_BLOCKSIZE_LOG)
+#define XFS_MIN_SECTORSIZE_LOG 9       /* i.e. 512 bytes */
+#define XFS_MAX_SECTORSIZE_LOG 15      /* i.e. 32768 bytes */
+#define XFS_MIN_SECTORSIZE     (1 << XFS_MIN_SECTORSIZE_LOG)
+#define XFS_MAX_SECTORSIZE     (1 << XFS_MAX_SECTORSIZE_LOG)
+
 /*
  * Min numbers of data/attr fork btree root pointers.
  */
index 4e5b9ad5cb97c733332f7d95b321949f1b168996..0025c78ac03cc7fbf44479e080766e5925494b25 100644 (file)
@@ -65,7 +65,6 @@ xfs_dir_ialloc(
        xfs_trans_t     *ntp;
        xfs_inode_t     *ip;
        xfs_buf_t       *ialloc_context = NULL;
-       boolean_t       call_again = B_FALSE;
        int             code;
        uint            log_res;
        uint            log_count;
@@ -91,7 +90,7 @@ xfs_dir_ialloc(
         * the inode(s) that we've just allocated.
         */
        code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, okalloc,
-                         &ialloc_context, &call_again, &ip);
+                         &ialloc_context, &ip);
 
        /*
         * Return an error if we were unable to allocate a new inode.
@@ -102,19 +101,18 @@ xfs_dir_ialloc(
                *ipp = NULL;
                return code;
        }
-       if (!call_again && (ip == NULL)) {
+       if (!ialloc_context && !ip) {
                *ipp = NULL;
                return XFS_ERROR(ENOSPC);
        }
 
        /*
-        * If call_again is set, then we were unable to get an
+        * If the AGI buffer is non-NULL, then we were unable to get an
         * inode in one operation.  We need to commit the current
         * transaction and call xfs_ialloc() again.  It is guaranteed
         * to succeed the second time.
         */
-       if (call_again) {
-
+       if (ialloc_context) {
                /*
                 * Normally, xfs_trans_commit releases all the locks.
                 * We call bhold to hang on to the ialloc_context across
@@ -195,7 +193,7 @@ xfs_dir_ialloc(
                 * this call should always succeed.
                 */
                code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid,
-                                 okalloc, &ialloc_context, &call_again, &ip);
+                                 okalloc, &ialloc_context, &ip);
 
                /*
                 * If we get an error at this point, return to the caller
@@ -206,12 +204,11 @@ xfs_dir_ialloc(
                        *ipp = NULL;
                        return code;
                }
-               ASSERT ((!call_again) && (ip != NULL));
+               ASSERT(!ialloc_context && ip);
 
        } else {
-               if (committed != NULL) {
+               if (committed != NULL)
                        *committed = 0;
-               }
        }
 
        *ipp = ip;
index b6a82d817a82b67cf8f3791bd1d6509dcd8fd95e..2a5c637344b4f310cd28586eec082d38176cbfcb 100644 (file)
@@ -145,11 +145,6 @@ xfs_readlink(
        return error;
 }
 
-/*
- * Flags for xfs_free_eofblocks
- */
-#define XFS_FREE_EOF_TRYLOCK   (1<<0)
-
 /*
  * This is called by xfs_inactive to free any blocks beyond eof
  * when the link count isn't zero and by xfs_dm_punch_hole() when
@@ -159,7 +154,7 @@ STATIC int
 xfs_free_eofblocks(
        xfs_mount_t     *mp,
        xfs_inode_t     *ip,
-       int             flags)
+       bool            need_iolock)
 {
        xfs_trans_t     *tp;
        int             error;
@@ -174,7 +169,7 @@ xfs_free_eofblocks(
         * of the file.  If not, then there is nothing to do.
         */
        end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip));
-       last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
+       last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
        if (last_fsb <= end_fsb)
                return 0;
        map_len = last_fsb - end_fsb;
@@ -201,13 +196,11 @@ xfs_free_eofblocks(
                 */
                tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
 
-               if (flags & XFS_FREE_EOF_TRYLOCK) {
+               if (need_iolock) {
                        if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
                                xfs_trans_cancel(tp, 0);
                                return 0;
                        }
-               } else {
-                       xfs_ilock(ip, XFS_IOLOCK_EXCL);
                }
 
                error = xfs_trans_reserve(tp, 0,
@@ -217,7 +210,8 @@ xfs_free_eofblocks(
                if (error) {
                        ASSERT(XFS_FORCED_SHUTDOWN(mp));
                        xfs_trans_cancel(tp, 0);
-                       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+                       if (need_iolock)
+                               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
                        return error;
                }
 
@@ -244,7 +238,10 @@ xfs_free_eofblocks(
                        error = xfs_trans_commit(tp,
                                                XFS_TRANS_RELEASE_LOG_RES);
                }
-               xfs_iunlock(ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL);
+
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+               if (need_iolock)
+                       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
        }
        return error;
 }
@@ -282,23 +279,15 @@ xfs_inactive_symlink_rmt(
         * free them all in one bunmapi call.
         */
        ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2);
-       if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
-                       XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) {
-               ASSERT(XFS_FORCED_SHUTDOWN(mp));
-               xfs_trans_cancel(tp, 0);
-               *tpp = NULL;
-               return error;
-       }
+
        /*
         * Lock the inode, fix the size, and join it to the transaction.
         * Hold it so in the normal path, we still have it locked for
         * the second transaction.  In the error paths we need it
         * held so the cancel won't rele it, see below.
         */
-       xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
        size = (int)ip->i_d.di_size;
        ip->i_d.di_size = 0;
-       xfs_trans_ijoin(tp, ip, 0);
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        /*
         * Find the block(s) so we can inval and unmap them.
@@ -385,114 +374,14 @@ xfs_inactive_symlink_rmt(
                ASSERT(XFS_FORCED_SHUTDOWN(mp));
                goto error0;
        }
-       /*
-        * Return with the inode locked but not joined to the transaction.
-        */
+
+       xfs_trans_ijoin(tp, ip, 0);
        *tpp = tp;
        return 0;
 
  error1:
        xfs_bmap_cancel(&free_list);
  error0:
-       /*
-        * Have to come here with the inode locked and either
-        * (held and in the transaction) or (not in the transaction).
-        * If the inode isn't held then cancel would iput it, but
-        * that's wrong since this is inactive and the vnode ref
-        * count is 0 already.
-        * Cancel won't do anything to the inode if held, but it still
-        * needs to be locked until the cancel is done, if it was
-        * joined to the transaction.
-        */
-       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
-       xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-       *tpp = NULL;
-       return error;
-
-}
-
-STATIC int
-xfs_inactive_symlink_local(
-       xfs_inode_t     *ip,
-       xfs_trans_t     **tpp)
-{
-       int             error;
-
-       ASSERT(ip->i_d.di_size <= XFS_IFORK_DSIZE(ip));
-       /*
-        * We're freeing a symlink which fit into
-        * the inode.  Just free the memory used
-        * to hold the old symlink.
-        */
-       error = xfs_trans_reserve(*tpp, 0,
-                                 XFS_ITRUNCATE_LOG_RES(ip->i_mount),
-                                 0, XFS_TRANS_PERM_LOG_RES,
-                                 XFS_ITRUNCATE_LOG_COUNT);
-
-       if (error) {
-               xfs_trans_cancel(*tpp, 0);
-               *tpp = NULL;
-               return error;
-       }
-       xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-
-       /*
-        * Zero length symlinks _can_ exist.
-        */
-       if (ip->i_df.if_bytes > 0) {
-               xfs_idata_realloc(ip,
-                                 -(ip->i_df.if_bytes),
-                                 XFS_DATA_FORK);
-               ASSERT(ip->i_df.if_bytes == 0);
-       }
-       return 0;
-}
-
-STATIC int
-xfs_inactive_attrs(
-       xfs_inode_t     *ip,
-       xfs_trans_t     **tpp)
-{
-       xfs_trans_t     *tp;
-       int             error;
-       xfs_mount_t     *mp;
-
-       ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
-       tp = *tpp;
-       mp = ip->i_mount;
-       ASSERT(ip->i_d.di_forkoff != 0);
-       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       if (error)
-               goto error_unlock;
-
-       error = xfs_attr_inactive(ip);
-       if (error)
-               goto error_unlock;
-
-       tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
-       error = xfs_trans_reserve(tp, 0,
-                                 XFS_IFREE_LOG_RES(mp),
-                                 0, XFS_TRANS_PERM_LOG_RES,
-                                 XFS_INACTIVE_LOG_COUNT);
-       if (error)
-               goto error_cancel;
-
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, 0);
-       xfs_idestroy_fork(ip, XFS_ATTR_FORK);
-
-       ASSERT(ip->i_d.di_anextents == 0);
-
-       *tpp = tp;
-       return 0;
-
-error_cancel:
-       ASSERT(XFS_FORCED_SHUTDOWN(mp));
-       xfs_trans_cancel(tp, 0);
-error_unlock:
-       *tpp = NULL;
-       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
        return error;
 }
 
@@ -574,8 +463,7 @@ xfs_release(
                if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE))
                        return 0;
 
-               error = xfs_free_eofblocks(mp, ip,
-                                          XFS_FREE_EOF_TRYLOCK);
+               error = xfs_free_eofblocks(mp, ip, true);
                if (error)
                        return error;
 
@@ -604,7 +492,7 @@ xfs_inactive(
        xfs_trans_t     *tp;
        xfs_mount_t     *mp;
        int             error;
-       int             truncate;
+       int             truncate = 0;
 
        /*
         * If the inode is already free, then there can be nothing
@@ -616,17 +504,6 @@ xfs_inactive(
                return VN_INACTIVE_CACHE;
        }
 
-       /*
-        * Only do a truncate if it's a regular file with
-        * some actual space in it.  It's OK to look at the
-        * inode's fields without the lock because we're the
-        * only one with a reference to the inode.
-        */
-       truncate = ((ip->i_d.di_nlink == 0) &&
-           ((ip->i_d.di_size != 0) || XFS_ISIZE(ip) != 0 ||
-            (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) &&
-           S_ISREG(ip->i_d.di_mode));
-
        mp = ip->i_mount;
 
        error = 0;
@@ -643,99 +520,100 @@ xfs_inactive(
                    (!(ip->i_d.di_flags &
                                (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
                     ip->i_delayed_blks != 0))) {
-                       error = xfs_free_eofblocks(mp, ip, 0);
+                       error = xfs_free_eofblocks(mp, ip, false);
                        if (error)
                                return VN_INACTIVE_CACHE;
                }
                goto out;
        }
 
-       ASSERT(ip->i_d.di_nlink == 0);
+       if (S_ISREG(ip->i_d.di_mode) &&
+           (ip->i_d.di_size != 0 || XFS_ISIZE(ip) != 0 ||
+            ip->i_d.di_nextents > 0 || ip->i_delayed_blks > 0))
+               truncate = 1;
 
        error = xfs_qm_dqattach(ip, 0);
        if (error)
                return VN_INACTIVE_CACHE;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
-       if (truncate) {
-               xfs_ilock(ip, XFS_IOLOCK_EXCL);
-
-               error = xfs_trans_reserve(tp, 0,
-                                         XFS_ITRUNCATE_LOG_RES(mp),
-                                         0, XFS_TRANS_PERM_LOG_RES,
-                                         XFS_ITRUNCATE_LOG_COUNT);
-               if (error) {
-                       /* Don't call itruncate_cleanup */
-                       ASSERT(XFS_FORCED_SHUTDOWN(mp));
-                       xfs_trans_cancel(tp, 0);
-                       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-                       return VN_INACTIVE_CACHE;
-               }
+       error = xfs_trans_reserve(tp, 0,
+                       (truncate || S_ISLNK(ip->i_d.di_mode)) ?
+                               XFS_ITRUNCATE_LOG_RES(mp) :
+                               XFS_IFREE_LOG_RES(mp),
+                       0,
+                       XFS_TRANS_PERM_LOG_RES,
+                       XFS_ITRUNCATE_LOG_COUNT);
+       if (error) {
+               ASSERT(XFS_FORCED_SHUTDOWN(mp));
+               xfs_trans_cancel(tp, 0);
+               return VN_INACTIVE_CACHE;
+       }
 
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin(tp, ip, 0);
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, 0);
 
+       if (S_ISLNK(ip->i_d.di_mode)) {
+               /*
+                * Zero length symlinks _can_ exist.
+                */
+               if (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) {
+                       error = xfs_inactive_symlink_rmt(ip, &tp);
+                       if (error)
+                               goto out_cancel;
+               } else if (ip->i_df.if_bytes > 0) {
+                       xfs_idata_realloc(ip, -(ip->i_df.if_bytes),
+                                         XFS_DATA_FORK);
+                       ASSERT(ip->i_df.if_bytes == 0);
+               }
+       } else if (truncate) {
                ip->i_d.di_size = 0;
                xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 
                error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
-               if (error) {
-                       xfs_trans_cancel(tp,
-                               XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
-                       xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-                       return VN_INACTIVE_CACHE;
-               }
+               if (error)
+                       goto out_cancel;
 
                ASSERT(ip->i_d.di_nextents == 0);
-       } else if (S_ISLNK(ip->i_d.di_mode)) {
+       }
 
-               /*
-                * If we get an error while cleaning up a
-                * symlink we bail out.
-                */
-               error = (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) ?
-                       xfs_inactive_symlink_rmt(ip, &tp) :
-                       xfs_inactive_symlink_local(ip, &tp);
+       /*
+        * If there are attributes associated with the file then blow them away
+        * now.  The code calls a routine that recursively deconstructs the
+        * attribute fork.  We need to just commit the current transaction
+        * because we can't use it for xfs_attr_inactive().
+        */
+       if (ip->i_d.di_anextents > 0) {
+               ASSERT(ip->i_d.di_forkoff != 0);
 
-               if (error) {
-                       ASSERT(tp == NULL);
-                       return VN_INACTIVE_CACHE;
-               }
+               error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+               if (error)
+                       goto out_unlock;
 
-               xfs_trans_ijoin(tp, ip, 0);
-       } else {
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+
+               error = xfs_attr_inactive(ip);
+               if (error)
+                       goto out;
+
+               tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
                error = xfs_trans_reserve(tp, 0,
                                          XFS_IFREE_LOG_RES(mp),
                                          0, XFS_TRANS_PERM_LOG_RES,
                                          XFS_INACTIVE_LOG_COUNT);
                if (error) {
-                       ASSERT(XFS_FORCED_SHUTDOWN(mp));
                        xfs_trans_cancel(tp, 0);
-                       return VN_INACTIVE_CACHE;
+                       goto out;
                }
 
-               xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+               xfs_ilock(ip, XFS_ILOCK_EXCL);
                xfs_trans_ijoin(tp, ip, 0);
        }
 
-       /*
-        * If there are attributes associated with the file
-        * then blow them away now.  The code calls a routine
-        * that recursively deconstructs the attribute fork.
-        * We need to just commit the current transaction
-        * because we can't use it for xfs_attr_inactive().
-        */
-       if (ip->i_d.di_anextents > 0) {
-               error = xfs_inactive_attrs(ip, &tp);
-               /*
-                * If we got an error, the transaction is already
-                * cancelled, and the inode is unlocked. Just get out.
-                */
-                if (error)
-                        return VN_INACTIVE_CACHE;
-       } else if (ip->i_afp) {
+       if (ip->i_afp)
                xfs_idestroy_fork(ip, XFS_ATTR_FORK);
-       }
+
+       ASSERT(ip->i_d.di_anextents == 0);
 
        /*
         * Free the inode.
@@ -779,10 +657,13 @@ xfs_inactive(
         * Release the dquots held by inode, if any.
         */
        xfs_qm_dqdetach(ip);
-       xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-
- out:
+out_unlock:
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+out:
        return VN_INACTIVE_CACHE;
+out_cancel:
+       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
+       goto out_unlock;
 }
 
 /*
@@ -2262,10 +2143,10 @@ xfs_change_file_space(
 
        llen = bf->l_len > 0 ? bf->l_len - 1 : bf->l_len;
 
-       if (   (bf->l_start < 0)
-           || (bf->l_start > XFS_MAXIOFFSET(mp))
-           || (bf->l_start + llen < 0)
-           || (bf->l_start + llen > XFS_MAXIOFFSET(mp)))
+       if (bf->l_start < 0 ||
+           bf->l_start > mp->m_super->s_maxbytes ||
+           bf->l_start + llen < 0 ||
+           bf->l_start + llen > mp->m_super->s_maxbytes)
                return XFS_ERROR(EINVAL);
 
        bf->l_whence = 0;
index abfb2682de7f33b0dce686447849e9c49b85c0a5..2be8a2dbc868f86f84e90c0e79a755c1f51e672b 100644 (file)
@@ -29,6 +29,7 @@ dma_mark_declared_memory_occupied(struct device *dev,
 #else
 #define dma_alloc_from_coherent(dev, size, handle, ret) (0)
 #define dma_release_from_coherent(dev, order, vaddr) (0)
+#define dma_mmap_from_coherent(dev, vma, vaddr, order, ret) (0)
 #endif
 
 #endif
index 2e248d8924dc34c38fa0ed91fdaa619060c9a603..de8bf89940f8dc3a7bc27a877067d3885cf646fa 100644 (file)
@@ -176,4 +176,59 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
 #define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL)
 #define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL)
 
+extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+                          void *cpu_addr, dma_addr_t dma_addr, size_t size);
+
+/**
+ * dma_mmap_attrs - map a coherent DMA allocation into user space
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @vma: vm_area_struct describing requested user mapping
+ * @cpu_addr: kernel CPU-view address returned from dma_alloc_attrs
+ * @handle: device-view address returned from dma_alloc_attrs
+ * @size: size of memory originally requested in dma_alloc_attrs
+ * @attrs: attributes of mapping properties requested in dma_alloc_attrs
+ *
+ * Map a coherent DMA buffer previously allocated by dma_alloc_attrs
+ * into user space.  The coherent DMA buffer must not be freed by the
+ * driver until the user space mapping has been released.
+ */
+static inline int
+dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr,
+              dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
+{
+       struct dma_map_ops *ops = get_dma_ops(dev);
+       BUG_ON(!ops);
+       if (ops->mmap)
+               return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
+       return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+
+#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL)
+
+static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
+                     void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+       DEFINE_DMA_ATTRS(attrs);
+       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+       return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs);
+}
+
+int
+dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
+                      void *cpu_addr, dma_addr_t dma_addr, size_t size);
+
+static inline int
+dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr,
+                     dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
+{
+       struct dma_map_ops *ops = get_dma_ops(dev);
+       BUG_ON(!ops);
+       if (ops->get_sgtable)
+               return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size,
+                                       attrs);
+       return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size);
+}
+
+#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, NULL)
+
 #endif
index 9e5b0356e2bbd0950c6399929e69da831928d9ee..a48937d4a5ea5715fafe813baf4f586a0b747355 100644 (file)
 #define F_GETOWN_EX    16
 #endif
 
+#ifndef F_GETOWNER_UIDS
+#define F_GETOWNER_UIDS        17
+#endif
+
 #define F_OWNER_TID    0
 #define F_OWNER_PID    1
 #define F_OWNER_PGRP   2
index 68733587e700bb00b776114e4a19530425194143..c20b001815303a670347a3e1c6b2227ea0f53383 100644 (file)
@@ -107,11 +107,6 @@ struct drm_exynos_vidi_connection {
        uint64_t edid;
 };
 
-struct drm_exynos_plane_set_zpos {
-       __u32 plane_id;
-       __s32 zpos;
-};
-
 /* memory type definitions. */
 enum e_drm_exynos_gem_mem_type {
        /* Physically Continuous memory and used as default. */
@@ -164,7 +159,6 @@ struct drm_exynos_g2d_exec {
 #define DRM_EXYNOS_GEM_MMAP            0x02
 /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
 #define DRM_EXYNOS_GEM_GET             0x04
-#define DRM_EXYNOS_PLANE_SET_ZPOS      0x06
 #define DRM_EXYNOS_VIDI_CONNECTION     0x07
 
 /* G2D */
@@ -184,9 +178,6 @@ struct drm_exynos_g2d_exec {
 #define DRM_IOCTL_EXYNOS_GEM_GET       DRM_IOWR(DRM_COMMAND_BASE + \
                DRM_EXYNOS_GEM_GET,     struct drm_exynos_gem_info)
 
-#define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS        DRM_IOWR(DRM_COMMAND_BASE + \
-               DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos)
-
 #define DRM_IOCTL_EXYNOS_VIDI_CONNECTION       DRM_IOWR(DRM_COMMAND_BASE + \
                DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection)
 
index 9547daddf8130f7db081edb28dad839c7c652268..d9a7544748785d020ba77f74392fb1275fbe02fd 100644 (file)
@@ -386,6 +386,7 @@ header-y += utime.h
 header-y += utsname.h
 header-y += uuid.h
 header-y += uvcvideo.h
+header-y += v4l2-common.h
 header-y += v4l2-dv-timings.h
 header-y += v4l2-mediabus.h
 header-y += v4l2-subdev.h
index b2b4d2ad7103d9fa9d5710b21b522ff78371fd46..3ad510b25283ee1e5285929b702d739fb0afc31a 100644 (file)
@@ -190,6 +190,8 @@ extern bool wmi_has_guid(const char *guid);
 
 extern long acpi_video_get_capabilities(acpi_handle graphics_dev_handle);
 extern long acpi_is_video_device(struct acpi_device *device);
+extern void acpi_video_dmi_promote_vendor(void);
+extern void acpi_video_dmi_demote_vendor(void);
 extern int acpi_video_backlight_support(void);
 extern int acpi_video_display_switch_support(void);
 
@@ -205,6 +207,14 @@ static inline long acpi_is_video_device(struct acpi_device *device)
        return 0;
 }
 
+static inline void acpi_video_dmi_promote_vendor(void)
+{
+}
+
+static inline void acpi_video_dmi_demote_vendor(void)
+{
+}
+
 static inline int acpi_video_backlight_support(void)
 {
        return 0;
index b1a520ec8b59dd0975bc4e738ce2398ca19dc363..31ff6dba4872a96c6bbfa5a78bbe27a782affc41 100644 (file)
@@ -126,22 +126,20 @@ struct kiocb {
        struct eventfd_ctx      *ki_eventfd;
 };
 
-#define is_sync_kiocb(iocb)    ((iocb)->ki_key == KIOCB_SYNC_KEY)
-#define init_sync_kiocb(x, filp)                       \
-       do {                                            \
-               struct task_struct *tsk = current;      \
-               (x)->ki_flags = 0;                      \
-               (x)->ki_users = 1;                      \
-               (x)->ki_key = KIOCB_SYNC_KEY;           \
-               (x)->ki_filp = (filp);                  \
-               (x)->ki_ctx = NULL;                     \
-               (x)->ki_cancel = NULL;                  \
-               (x)->ki_retry = NULL;                   \
-               (x)->ki_dtor = NULL;                    \
-               (x)->ki_obj.tsk = tsk;                  \
-               (x)->ki_user_data = 0;                  \
-               (x)->private = NULL;                    \
-       } while (0)
+static inline bool is_sync_kiocb(struct kiocb *kiocb)
+{
+       return kiocb->ki_key == KIOCB_SYNC_KEY;
+}
+
+static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp)
+{
+       *kiocb = (struct kiocb) {
+                       .ki_users = 1,
+                       .ki_key = KIOCB_SYNC_KEY,
+                       .ki_filp = filp,
+                       .ki_obj.tsk = current,
+               };
+}
 
 #define AIO_RING_MAGIC                 0xa10a10a1
 #define AIO_RING_COMPAT_FEATURES       1
@@ -161,8 +159,6 @@ struct aio_ring {
        struct io_event         io_events[0];
 }; /* 128 bytes + ring size */
 
-#define aio_ring_avail(info, ring)     (((ring)->head + (info)->nr - 1 - (ring)->tail) % (info)->nr)
-
 #define AIO_RING_PAGES 8
 struct aio_ring_info {
        unsigned long           mmap_base;
@@ -177,6 +173,12 @@ struct aio_ring_info {
        struct page             *internal_pages[AIO_RING_PAGES];
 };
 
+static inline unsigned aio_ring_avail(struct aio_ring_info *info,
+                                       struct aio_ring *ring)
+{
+       return (ring->head + info->nr - 1 - ring->tail) % info->nr;
+}
+
 struct kioctx {
        atomic_t                users;
        int                     dead;
index b1038bd686acfc46caf251aad8ae765e9970ceb3..489de625cd2599c2c2abc33d4ba46e4aeddd9e51 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <linux/percpu_counter.h>
 #include <linux/log2.h>
-#include <linux/proportions.h>
+#include <linux/flex_proportions.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/sched.h>
@@ -89,7 +89,7 @@ struct backing_dev_info {
        unsigned long dirty_ratelimit;
        unsigned long balanced_dirty_ratelimit;
 
-       struct prop_local_percpu completions;
+       struct fprop_local_percpu completions;
        int dirty_exceeded;
 
        unsigned int min_ratio;
diff --git a/include/linux/ceph/ceph_features.h b/include/linux/ceph/ceph_features.h
new file mode 100644 (file)
index 0000000..dad579b
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __CEPH_FEATURES
+#define __CEPH_FEATURES
+
+/*
+ * feature bits
+ */
+#define CEPH_FEATURE_UID            (1<<0)
+#define CEPH_FEATURE_NOSRCADDR      (1<<1)
+#define CEPH_FEATURE_MONCLOCKCHECK  (1<<2)
+#define CEPH_FEATURE_FLOCK          (1<<3)
+#define CEPH_FEATURE_SUBSCRIBE2     (1<<4)
+#define CEPH_FEATURE_MONNAMES       (1<<5)
+#define CEPH_FEATURE_RECONNECT_SEQ  (1<<6)
+#define CEPH_FEATURE_DIRLAYOUTHASH  (1<<7)
+/* bits 8-17 defined by user-space; not supported yet here */
+#define CEPH_FEATURE_CRUSH_TUNABLES (1<<18)
+
+/*
+ * Features supported.
+ */
+#define CEPH_FEATURES_SUPPORTED_DEFAULT  \
+       (CEPH_FEATURE_NOSRCADDR |        \
+        CEPH_FEATURE_CRUSH_TUNABLES)
+
+#define CEPH_FEATURES_REQUIRED_DEFAULT   \
+       (CEPH_FEATURE_NOSRCADDR)
+#endif
index e81ab30d4896329e29d47bea33d92e5634da6a89..d021610efd65168bf8fc5e071416d13e6faa3d0a 100644 (file)
 /* arbitrary limit on max # of monitors (cluster of 3 is typical) */
 #define CEPH_MAX_MON   31
 
-
-/*
- * feature bits
- */
-#define CEPH_FEATURE_UID            (1<<0)
-#define CEPH_FEATURE_NOSRCADDR      (1<<1)
-#define CEPH_FEATURE_MONCLOCKCHECK  (1<<2)
-#define CEPH_FEATURE_FLOCK          (1<<3)
-#define CEPH_FEATURE_SUBSCRIBE2     (1<<4)
-#define CEPH_FEATURE_MONNAMES       (1<<5)
-#define CEPH_FEATURE_RECONNECT_SEQ  (1<<6)
-#define CEPH_FEATURE_DIRLAYOUTHASH  (1<<7)
-
-
 /*
  * ceph_file_layout - describe data layout for a file/inode
  */
index d8615dee5808d3f55c93a38c6fdb66113f09a691..4bbf2db45f461bf8be35159a3a0b91671191992e 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __CEPH_DECODE_H
 #define __CEPH_DECODE_H
 
+#include <linux/err.h>
 #include <linux/bug.h>
 #include <linux/time.h>
 #include <asm/unaligned.h>
@@ -84,6 +85,52 @@ static inline int ceph_has_room(void **p, void *end, size_t n)
                ceph_decode_copy(p, pv, n);                     \
        } while (0)
 
+/*
+ * Allocate a buffer big enough to hold the wire-encoded string, and
+ * decode the string into it.  The resulting string will always be
+ * terminated with '\0'.  If successful, *p will be advanced
+ * past the decoded data.  Also, if lenp is not a null pointer, the
+ * length (not including the terminating '\0') will be recorded in
+ * *lenp.  Note that a zero-length string is a valid return value.
+ *
+ * Returns a pointer to the newly-allocated string buffer, or a
+ * pointer-coded errno if an error occurs.  Neither *p nor *lenp
+ * will have been updated if an error is returned.
+ *
+ * There are two possible failures:
+ *   - converting the string would require accessing memory at or
+ *     beyond the "end" pointer provided (-E
+ *   - memory could not be allocated for the result
+ */
+static inline char *ceph_extract_encoded_string(void **p, void *end,
+                                               size_t *lenp, gfp_t gfp)
+{
+       u32 len;
+       void *sp = *p;
+       char *buf;
+
+       ceph_decode_32_safe(&sp, end, len, bad);
+       if (!ceph_has_room(&sp, end, len))
+               goto bad;
+
+       buf = kmalloc(len + 1, gfp);
+       if (!buf)
+               return ERR_PTR(-ENOMEM);
+
+       if (len)
+               memcpy(buf, sp, len);
+       buf[len] = '\0';
+
+       *p = (char *) *p + sizeof (u32) + len;
+       if (lenp)
+               *lenp = (size_t) len;
+
+       return buf;
+
+bad:
+       return ERR_PTR(-ERANGE);
+}
+
 /*
  * struct ceph_timespec <-> struct timespec
  */
@@ -151,7 +198,7 @@ static inline void ceph_encode_filepath(void **p, void *end,
                                        u64 ino, const char *path)
 {
        u32 len = path ? strlen(path) : 0;
-       BUG_ON(*p + sizeof(ino) + sizeof(len) + len > end);
+       BUG_ON(*p + 1 + sizeof(ino) + sizeof(len) + len > end);
        ceph_encode_8(p, 1);
        ceph_encode_64(p, ino);
        ceph_encode_32(p, len);
index e71d683982a6f651a83a22fd7ef12bf7af6f655f..42624789b06f62caf30437da5b104d92f3c3a6e3 100644 (file)
 #include "osd_client.h"
 #include "ceph_fs.h"
 
-/*
- * Supported features
- */
-#define CEPH_FEATURE_SUPPORTED_DEFAULT CEPH_FEATURE_NOSRCADDR
-#define CEPH_FEATURE_REQUIRED_DEFAULT  CEPH_FEATURE_NOSRCADDR
-
 /*
  * mount options
  */
@@ -132,7 +126,7 @@ struct ceph_client {
        u32 supported_features;
        u32 required_features;
 
-       struct ceph_messenger *msgr;   /* messenger instance */
+       struct ceph_messenger msgr;   /* messenger instance */
        struct ceph_mon_client monc;
        struct ceph_osd_client osdc;
 
@@ -160,7 +154,7 @@ struct ceph_client {
 struct ceph_snap_context {
        atomic_t nref;
        u64 seq;
-       int num_snaps;
+       u32 num_snaps;
        u64 snaps[];
 };
 
index 44c87e731e9d4c5fff13cbf851694cd41356fb04..189ae063763403a95c28e667ea094bab5c74ded8 100644 (file)
@@ -31,9 +31,6 @@ struct ceph_connection_operations {
        int (*verify_authorizer_reply) (struct ceph_connection *con, int len);
        int (*invalidate_authorizer)(struct ceph_connection *con);
 
-       /* protocol version mismatch */
-       void (*bad_proto) (struct ceph_connection *con);
-
        /* there was some error on the socket (disconnect, whatever) */
        void (*fault) (struct ceph_connection *con);
 
@@ -53,6 +50,7 @@ struct ceph_messenger {
        struct ceph_entity_inst inst;    /* my name+address */
        struct ceph_entity_addr my_enc_addr;
 
+       atomic_t stopping;
        bool nocrc;
 
        /*
@@ -80,7 +78,10 @@ struct ceph_msg {
        unsigned nr_pages;              /* size of page array */
        unsigned page_alignment;        /* io offset in first page */
        struct ceph_pagelist *pagelist; /* instead of pages */
+
+       struct ceph_connection *con;
        struct list_head list_head;
+
        struct kref kref;
        struct bio  *bio;               /* instead of pages/pagelist */
        struct bio  *bio_iter;          /* bio iterator */
@@ -105,23 +106,6 @@ struct ceph_msg_pos {
 #define BASE_DELAY_INTERVAL    (HZ/2)
 #define MAX_DELAY_INTERVAL     (5 * 60 * HZ)
 
-/*
- * ceph_connection state bit flags
- */
-#define LOSSYTX         0  /* we can close channel or drop messages on errors */
-#define CONNECTING     1
-#define NEGOTIATING    2
-#define KEEPALIVE_PENDING      3
-#define WRITE_PENDING  4  /* we have data ready to send */
-#define STANDBY                8  /* no outgoing messages, socket closed.  we keep
-                           * the ceph_connection around to maintain shared
-                           * state with the peer. */
-#define CLOSED         10 /* we've closed the connection */
-#define SOCK_CLOSED    11 /* socket state changed to closed */
-#define OPENING         13 /* open connection w/ (possibly new) peer */
-#define DEAD            14 /* dead, about to kfree */
-#define BACKOFF         15
-
 /*
  * A single connection with another host.
  *
@@ -131,18 +115,22 @@ struct ceph_msg_pos {
  */
 struct ceph_connection {
        void *private;
-       atomic_t nref;
 
        const struct ceph_connection_operations *ops;
 
        struct ceph_messenger *msgr;
+
+       atomic_t sock_state;
        struct socket *sock;
-       unsigned long state;    /* connection state (see flags above) */
+       struct ceph_entity_addr peer_addr; /* peer address */
+       struct ceph_entity_addr peer_addr_for_me;
+
+       unsigned long flags;
+       unsigned long state;
        const char *error_msg;  /* error message, if any */
 
-       struct ceph_entity_addr peer_addr; /* peer address */
        struct ceph_entity_name peer_name; /* peer name */
-       struct ceph_entity_addr peer_addr_for_me;
+
        unsigned peer_features;
        u32 connect_seq;      /* identify the most recent connection
                                 attempt for this connection, client */
@@ -207,24 +195,26 @@ extern int ceph_msgr_init(void);
 extern void ceph_msgr_exit(void);
 extern void ceph_msgr_flush(void);
 
-extern struct ceph_messenger *ceph_messenger_create(
-       struct ceph_entity_addr *myaddr,
-       u32 features, u32 required);
-extern void ceph_messenger_destroy(struct ceph_messenger *);
+extern void ceph_messenger_init(struct ceph_messenger *msgr,
+                       struct ceph_entity_addr *myaddr,
+                       u32 supported_features,
+                       u32 required_features,
+                       bool nocrc);
 
-extern void ceph_con_init(struct ceph_messenger *msgr,
-                         struct ceph_connection *con);
+extern void ceph_con_init(struct ceph_connection *con, void *private,
+                       const struct ceph_connection_operations *ops,
+                       struct ceph_messenger *msgr);
 extern void ceph_con_open(struct ceph_connection *con,
+                         __u8 entity_type, __u64 entity_num,
                          struct ceph_entity_addr *addr);
 extern bool ceph_con_opened(struct ceph_connection *con);
 extern void ceph_con_close(struct ceph_connection *con);
 extern void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg);
-extern void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg);
-extern void ceph_con_revoke_message(struct ceph_connection *con,
-                                 struct ceph_msg *msg);
+
+extern void ceph_msg_revoke(struct ceph_msg *msg);
+extern void ceph_msg_revoke_incoming(struct ceph_msg *msg);
+
 extern void ceph_con_keepalive(struct ceph_connection *con);
-extern struct ceph_connection *ceph_con_get(struct ceph_connection *con);
-extern void ceph_con_put(struct ceph_connection *con);
 
 extern struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags,
                                     bool can_fail);
index 545f85917780ab3cd65a314553f7011b655dbb50..2113e3850a4e0c7e088b22b07092baf2616654a5 100644 (file)
@@ -70,7 +70,7 @@ struct ceph_mon_client {
        bool hunting;
        int cur_mon;                       /* last monitor i contacted */
        unsigned long sub_sent, sub_renew_after;
-       struct ceph_connection *con;
+       struct ceph_connection con;
        bool have_fsid;
 
        /* pending generic requests */
index a362605f93682a8ffe213fc8a3bc7d06f4cc3187..09fa96b43436cba01cda946a30e48d17991fbae8 100644 (file)
 struct ceph_msgpool {
        const char *name;
        mempool_t *pool;
+       int type;               /* preallocated message type */
        int front_len;          /* preallocated payload size */
 };
 
-extern int ceph_msgpool_init(struct ceph_msgpool *pool,
+extern int ceph_msgpool_init(struct ceph_msgpool *pool, int type,
                             int front_len, int size, bool blocking,
                             const char *name);
 extern void ceph_msgpool_destroy(struct ceph_msgpool *pool);
index 2fd6a4234531577e128cdc1d5bfabacbed7babfb..b3ac22d0fc1fdc4be337e32e7991c5b0b45d9541 100644 (file)
@@ -84,6 +84,43 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
 
 #endif
 
+/**
+ * clk_prepare - prepare a clock source
+ * @clk: clock source
+ *
+ * This prepares the clock source for use.
+ *
+ * Must not be called from within atomic context.
+ */
+#ifdef CONFIG_HAVE_CLK_PREPARE
+int clk_prepare(struct clk *clk);
+#else
+static inline int clk_prepare(struct clk *clk)
+{
+       might_sleep();
+       return 0;
+}
+#endif
+
+/**
+ * clk_unprepare - undo preparation of a clock source
+ * @clk: clock source
+ *
+ * This undoes a previously prepared clock.  The caller must balance
+ * the number of prepare and unprepare calls.
+ *
+ * Must not be called from within atomic context.
+ */
+#ifdef CONFIG_HAVE_CLK_PREPARE
+void clk_unprepare(struct clk *clk);
+#else
+static inline void clk_unprepare(struct clk *clk)
+{
+       might_sleep();
+}
+#endif
+
+#ifdef CONFIG_HAVE_CLK
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
  * @dev: device for clock "consumer"
@@ -121,24 +158,6 @@ struct clk *clk_get(struct device *dev, const char *id);
  */
 struct clk *devm_clk_get(struct device *dev, const char *id);
 
-/**
- * clk_prepare - prepare a clock source
- * @clk: clock source
- *
- * This prepares the clock source for use.
- *
- * Must not be called from within atomic context.
- */
-#ifdef CONFIG_HAVE_CLK_PREPARE
-int clk_prepare(struct clk *clk);
-#else
-static inline int clk_prepare(struct clk *clk)
-{
-       might_sleep();
-       return 0;
-}
-#endif
-
 /**
  * clk_enable - inform the system when the clock source should be running.
  * @clk: clock source
@@ -167,47 +186,6 @@ int clk_enable(struct clk *clk);
  */
 void clk_disable(struct clk *clk);
 
-
-/**
- * clk_unprepare - undo preparation of a clock source
- * @clk: clock source
- *
- * This undoes a previously prepared clock.  The caller must balance
- * the number of prepare and unprepare calls.
- *
- * Must not be called from within atomic context.
- */
-#ifdef CONFIG_HAVE_CLK_PREPARE
-void clk_unprepare(struct clk *clk);
-#else
-static inline void clk_unprepare(struct clk *clk)
-{
-       might_sleep();
-}
-#endif
-
-/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
-static inline int clk_prepare_enable(struct clk *clk)
-{
-       int ret;
-
-       ret = clk_prepare(clk);
-       if (ret)
-               return ret;
-       ret = clk_enable(clk);
-       if (ret)
-               clk_unprepare(clk);
-
-       return ret;
-}
-
-/* clk_disable_unprepare helps cases using clk_disable in non-atomic context. */
-static inline void clk_disable_unprepare(struct clk *clk)
-{
-       clk_disable(clk);
-       clk_unprepare(clk);
-}
-
 /**
  * clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
  *               This is only valid once the clock source has been enabled.
@@ -298,6 +276,78 @@ struct clk *clk_get_parent(struct clk *clk);
  */
 struct clk *clk_get_sys(const char *dev_id, const char *con_id);
 
+#else /* !CONFIG_HAVE_CLK */
+
+static inline struct clk *clk_get(struct device *dev, const char *id)
+{
+       return NULL;
+}
+
+static inline struct clk *devm_clk_get(struct device *dev, const char *id)
+{
+       return NULL;
+}
+
+static inline void clk_put(struct clk *clk) {}
+
+static inline void devm_clk_put(struct device *dev, struct clk *clk) {}
+
+static inline int clk_enable(struct clk *clk)
+{
+       return 0;
+}
+
+static inline void clk_disable(struct clk *clk) {}
+
+static inline unsigned long clk_get_rate(struct clk *clk)
+{
+       return 0;
+}
+
+static inline int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       return 0;
+}
+
+static inline long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       return 0;
+}
+
+static inline int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       return 0;
+}
+
+static inline struct clk *clk_get_parent(struct clk *clk)
+{
+       return NULL;
+}
+
+#endif
+
+/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
+static inline int clk_prepare_enable(struct clk *clk)
+{
+       int ret;
+
+       ret = clk_prepare(clk);
+       if (ret)
+               return ret;
+       ret = clk_enable(clk);
+       if (ret)
+               clk_unprepare(clk);
+
+       return ret;
+}
+
+/* clk_disable_unprepare helps cases using clk_disable in non-atomic context. */
+static inline void clk_disable_unprepare(struct clk *clk)
+{
+       clk_disable(clk);
+       clk_unprepare(clk);
+}
+
 /**
  * clk_add_alias - add a new clock alias
  * @alias: name for clock alias
index 4e890394ef996e709c490439be23f0c6fe24292f..09b28b7369d77e1ebedfe9a03017860df4d09fc3 100644 (file)
@@ -265,9 +265,9 @@ long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
 #else
 long compat_sys_semctl(int semid, int semnum, int cmd, int arg);
 long compat_sys_msgsnd(int msqid, struct compat_msgbuf __user *msgp,
-               size_t msgsz, int msgflg);
+               compat_ssize_t msgsz, int msgflg);
 long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp,
-               size_t msgsz, long msgtyp, int msgflg);
+               compat_ssize_t msgsz, long msgtyp, int msgflg);
 long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg);
 #endif
 long compat_sys_msgctl(int first, int second, void __user *uptr);
index 7c4750811b966e7d865484c2cf7020199c628164..25baa287cff7287d8e6cc6f5b94255ef4cf86f9e 100644 (file)
@@ -154,6 +154,14 @@ struct crush_map {
        __s32 max_buckets;
        __u32 max_rules;
        __s32 max_devices;
+
+       /* choose local retries before re-descent */
+       __u32 choose_local_tries;
+       /* choose local attempts using a fallback permutation before
+        * re-descent */
+       __u32 choose_local_fallback_tries;
+       /* choose attempts before giving up */ 
+       __u32 choose_total_tries;
 };
 
 
index 98f34b886f955db4e9c7ecd63d892bafd30e6f1f..38d27a10aa5d9f922a14dd5746b9e29f34bce633 100644 (file)
@@ -66,14 +66,13 @@ typedef int (*dm_request_endio_fn) (struct dm_target *ti,
                                    struct request *clone, int error,
                                    union map_info *map_context);
 
-typedef void (*dm_flush_fn) (struct dm_target *ti);
 typedef void (*dm_presuspend_fn) (struct dm_target *ti);
 typedef void (*dm_postsuspend_fn) (struct dm_target *ti);
 typedef int (*dm_preresume_fn) (struct dm_target *ti);
 typedef void (*dm_resume_fn) (struct dm_target *ti);
 
 typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
-                            char *result, unsigned int maxlen);
+                            unsigned status_flags, char *result, unsigned maxlen);
 
 typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv);
 
@@ -139,7 +138,6 @@ struct target_type {
        dm_map_request_fn map_rq;
        dm_endio_fn end_io;
        dm_request_endio_fn rq_end_io;
-       dm_flush_fn flush;
        dm_presuspend_fn presuspend;
        dm_postsuspend_fn postsuspend;
        dm_preresume_fn preresume;
@@ -188,8 +186,8 @@ struct dm_target {
        sector_t begin;
        sector_t len;
 
-       /* Always a power of 2 */
-       sector_t split_io;
+       /* If non-zero, maximum size of I/O submitted to a target. */
+       uint32_t max_io_len;
 
        /*
         * A number of zero-length barrier requests that will be submitted
@@ -213,16 +211,28 @@ struct dm_target {
        /* Used to provide an error string from the ctr */
        char *error;
 
+       /*
+        * Set if this target needs to receive flushes regardless of
+        * whether or not its underlying devices have support.
+        */
+       bool flush_supported:1;
+
        /*
         * Set if this target needs to receive discards regardless of
         * whether or not its underlying devices have support.
         */
-       unsigned discards_supported:1;
+       bool discards_supported:1;
+
+       /*
+        * Set if the target required discard request to be split
+        * on max_io_len boundary.
+        */
+       bool split_discard_requests:1;
 
        /*
         * Set if this target does not return zeroes on discarded blocks.
         */
-       unsigned discard_zeroes_data_unsupported:1;
+       bool discard_zeroes_data_unsupported:1;
 };
 
 /* Each target can link one of these into the table */
@@ -359,6 +369,11 @@ void dm_table_add_target_callbacks(struct dm_table *t, struct dm_target_callback
  */
 int dm_table_complete(struct dm_table *t);
 
+/*
+ * Target may require that it is never sent I/O larger than len.
+ */
+int __must_check dm_set_target_max_io_len(struct dm_target *ti, sector_t len);
+
 /*
  * Table reference counting.
  */
index 75fd5573516e15f04bcc864140620977405362f6..91e3a360f61103451986008553dd91567e68fe13 100644 (file)
@@ -267,9 +267,9 @@ enum {
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       22
+#define DM_VERSION_MINOR       23
 #define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2011-10-19)"
+#define DM_VERSION_EXTRA       "-ioctl (2012-07-25)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */
@@ -307,6 +307,8 @@ enum {
 
 /*
  * Set this to suspend without flushing queued ios.
+ * Also disables flushing uncommitted changes in the thin target before
+ * generating statistics for DM_TABLE_STATUS and DM_DEV_WAIT.
  */
 #define DM_NOFLUSH_FLAG                (1 << 11) /* In */
 
index 547ab568d3ae83f940e503c6999719f37a73547e..f83f793223ff7491f59c44b3c3bd6d7440b51084 100644 (file)
@@ -15,6 +15,8 @@ enum dma_attr {
        DMA_ATTR_WEAK_ORDERING,
        DMA_ATTR_WRITE_COMBINE,
        DMA_ATTR_NON_CONSISTENT,
+       DMA_ATTR_NO_KERNEL_MAPPING,
+       DMA_ATTR_SKIP_CPU_SYNC,
        DMA_ATTR_MAX,
 };
 
index dfc099e56a66187ba9d223eea924da5650e462bf..94af418585135a6fdaabb987e284caad4a8b1e99 100644 (file)
@@ -18,6 +18,9 @@ struct dma_map_ops {
        int (*mmap)(struct device *, struct vm_area_struct *,
                          void *, dma_addr_t, size_t, struct dma_attrs *attrs);
 
+       int (*get_sgtable)(struct device *dev, struct sg_table *sgt, void *,
+                          dma_addr_t, size_t, struct dma_attrs *attrs);
+
        dma_addr_t (*map_page)(struct device *dev, struct page *page,
                               unsigned long offset, size_t size,
                               enum dma_data_direction dir,
index 91ba3bae42ee53b7dac7c891284cee2b32ecb32a..bab9f8473dc1c7673c7e900e73691d38ee35e737 100644 (file)
 #define _LINUX_EDAC_H_
 
 #include <linux/atomic.h>
+#include <linux/device.h>
 #include <linux/kobject.h>
 #include <linux/completion.h>
 #include <linux/workqueue.h>
+#include <linux/debugfs.h>
 
 struct device;
 
@@ -49,7 +51,19 @@ static inline void opstate_init(void)
 #define EDAC_MC_LABEL_LEN      31
 #define MC_PROC_NAME_MAX_LEN   7
 
-/* memory devices */
+/**
+ * enum dev_type - describe the type of memory DRAM chips used at the stick
+ * @DEV_UNKNOWN:       Can't be determined, or MC doesn't support detect it
+ * @DEV_X1:            1 bit for data
+ * @DEV_X2:            2 bits for data
+ * @DEV_X4:            4 bits for data
+ * @DEV_X8:            8 bits for data
+ * @DEV_X16:           16 bits for data
+ * @DEV_X32:           32 bits for data
+ * @DEV_X64:           64 bits for data
+ *
+ * Typical values are x4 and x8.
+ */
 enum dev_type {
        DEV_UNKNOWN = 0,
        DEV_X1,
@@ -167,18 +181,30 @@ enum mem_type {
 #define MEM_FLAG_DDR3           BIT(MEM_DDR3)
 #define MEM_FLAG_RDDR3          BIT(MEM_RDDR3)
 
-/* chipset Error Detection and Correction capabilities and mode */
+/**
+ * enum edac-type - Error Detection and Correction capabilities and mode
+ * @EDAC_UNKNOWN:      Unknown if ECC is available
+ * @EDAC_NONE:         Doesn't support ECC
+ * @EDAC_RESERVED:     Reserved ECC type
+ * @EDAC_PARITY:       Detects parity errors
+ * @EDAC_EC:           Error Checking - no correction
+ * @EDAC_SECDED:       Single bit error correction, Double detection
+ * @EDAC_S2ECD2ED:     Chipkill x2 devices - do these exist?
+ * @EDAC_S4ECD4ED:     Chipkill x4 devices
+ * @EDAC_S8ECD8ED:     Chipkill x8 devices
+ * @EDAC_S16ECD16ED:   Chipkill x16 devices
+ */
 enum edac_type {
-       EDAC_UNKNOWN = 0,       /* Unknown if ECC is available */
-       EDAC_NONE,              /* Doesn't support ECC */
-       EDAC_RESERVED,          /* Reserved ECC type */
-       EDAC_PARITY,            /* Detects parity errors */
-       EDAC_EC,                /* Error Checking - no correction */
-       EDAC_SECDED,            /* Single bit error correction, Double detection */
-       EDAC_S2ECD2ED,          /* Chipkill x2 devices - do these exist? */
-       EDAC_S4ECD4ED,          /* Chipkill x4 devices */
-       EDAC_S8ECD8ED,          /* Chipkill x8 devices */
-       EDAC_S16ECD16ED,        /* Chipkill x16 devices */
+       EDAC_UNKNOWN =  0,
+       EDAC_NONE,
+       EDAC_RESERVED,
+       EDAC_PARITY,
+       EDAC_EC,
+       EDAC_SECDED,
+       EDAC_S2ECD2ED,
+       EDAC_S4ECD4ED,
+       EDAC_S8ECD8ED,
+       EDAC_S16ECD16ED,
 };
 
 #define EDAC_FLAG_UNKNOWN      BIT(EDAC_UNKNOWN)
@@ -191,18 +217,30 @@ enum edac_type {
 #define EDAC_FLAG_S8ECD8ED     BIT(EDAC_S8ECD8ED)
 #define EDAC_FLAG_S16ECD16ED   BIT(EDAC_S16ECD16ED)
 
-/* scrubbing capabilities */
+/**
+ * enum scrub_type - scrubbing capabilities
+ * @SCRUB_UNKNOWN              Unknown if scrubber is available
+ * @SCRUB_NONE:                        No scrubber
+ * @SCRUB_SW_PROG:             SW progressive (sequential) scrubbing
+ * @SCRUB_SW_SRC:              Software scrub only errors
+ * @SCRUB_SW_PROG_SRC:         Progressive software scrub from an error
+ * @SCRUB_SW_TUNABLE:          Software scrub frequency is tunable
+ * @SCRUB_HW_PROG:             HW progressive (sequential) scrubbing
+ * @SCRUB_HW_SRC:              Hardware scrub only errors
+ * @SCRUB_HW_PROG_SRC:         Progressive hardware scrub from an error
+ * SCRUB_HW_TUNABLE:           Hardware scrub frequency is tunable
+ */
 enum scrub_type {
-       SCRUB_UNKNOWN = 0,      /* Unknown if scrubber is available */
-       SCRUB_NONE,             /* No scrubber */
-       SCRUB_SW_PROG,          /* SW progressive (sequential) scrubbing */
-       SCRUB_SW_SRC,           /* Software scrub only errors */
-       SCRUB_SW_PROG_SRC,      /* Progressive software scrub from an error */
-       SCRUB_SW_TUNABLE,       /* Software scrub frequency is tunable */
-       SCRUB_HW_PROG,          /* HW progressive (sequential) scrubbing */
-       SCRUB_HW_SRC,           /* Hardware scrub only errors */
-       SCRUB_HW_PROG_SRC,      /* Progressive hardware scrub from an error */
-       SCRUB_HW_TUNABLE        /* Hardware scrub frequency is tunable */
+       SCRUB_UNKNOWN = 0,
+       SCRUB_NONE,
+       SCRUB_SW_PROG,
+       SCRUB_SW_SRC,
+       SCRUB_SW_PROG_SRC,
+       SCRUB_SW_TUNABLE,
+       SCRUB_HW_PROG,
+       SCRUB_HW_SRC,
+       SCRUB_HW_PROG_SRC,
+       SCRUB_HW_TUNABLE
 };
 
 #define SCRUB_FLAG_SW_PROG     BIT(SCRUB_SW_PROG)
@@ -374,23 +412,21 @@ struct edac_mc_layer {
 #define EDAC_MAX_LAYERS                3
 
 /**
- * EDAC_DIMM_PTR - Macro responsible to find a pointer inside a pointer array
+ * EDAC_DIMM_OFF - Macro responsible to get a pointer offset inside a pointer array
  *                for the element given by [layer0,layer1,layer2] position
  *
  * @layers:    a struct edac_mc_layer array, describing how many elements
  *             were allocated for each layer
- * @var:       name of the var where we want to get the pointer
- *             (like mci->dimms)
  * @n_layers:  Number of layers at the @layers array
  * @layer0:    layer0 position
  * @layer1:    layer1 position. Unused if n_layers < 2
  * @layer2:    layer2 position. Unused if n_layers < 3
  *
- * For 1 layer, this macro returns &var[layer0]
+ * For 1 layer, this macro returns &var[layer0] - &var
  * For 2 layers, this macro is similar to allocate a bi-dimensional array
- *             and to return "&var[layer0][layer1]"
+ *             and to return "&var[layer0][layer1] - &var"
  * For 3 layers, this macro is similar to allocate a tri-dimensional array
- *             and to return "&var[layer0][layer1][layer2]"
+ *             and to return "&var[layer0][layer1][layer2] - &var"
  *
  * A loop could be used here to make it more generic, but, as we only have
  * 3 layers, this is a little faster.
@@ -398,23 +434,52 @@ struct edac_mc_layer {
  * a NULL is returned, causing an OOPS during the memory allocation routine,
  * with would point to the developer that he's doing something wrong.
  */
-#define EDAC_DIMM_PTR(layers, var, nlayers, layer0, layer1, layer2) ({ \
-       typeof(var) __p;                                                \
+#define EDAC_DIMM_OFF(layers, nlayers, layer0, layer1, layer2) ({              \
+       int __i;                                                        \
        if ((nlayers) == 1)                                             \
-               __p = &var[layer0];                                     \
+               __i = layer0;                                           \
        else if ((nlayers) == 2)                                        \
-               __p = &var[(layer1) + ((layers[1]).size * (layer0))];   \
+               __i = (layer1) + ((layers[1]).size * (layer0));         \
        else if ((nlayers) == 3)                                        \
-               __p = &var[(layer2) + ((layers[2]).size * ((layer1) +   \
-                           ((layers[1]).size * (layer0))))];           \
+               __i = (layer2) + ((layers[2]).size * ((layer1) +        \
+                           ((layers[1]).size * (layer0))))           \
        else                                                            \
+               __i = -EINVAL;                                          \
+       __i;                                                            \
+})
+
+/**
+ * EDAC_DIMM_PTR - Macro responsible to get a pointer inside a pointer array
+ *                for the element given by [layer0,layer1,layer2] position
+ *
+ * @layers:    a struct edac_mc_layer array, describing how many elements
+ *             were allocated for each layer
+ * @var:       name of the var where we want to get the pointer
+ *             (like mci->dimms)
+ * @n_layers:  Number of layers at the @layers array
+ * @layer0:    layer0 position
+ * @layer1:    layer1 position. Unused if n_layers < 2
+ * @layer2:    layer2 position. Unused if n_layers < 3
+ *
+ * For 1 layer, this macro returns &var[layer0]
+ * For 2 layers, this macro is similar to allocate a bi-dimensional array
+ *             and to return "&var[layer0][layer1]"
+ * For 3 layers, this macro is similar to allocate a tri-dimensional array
+ *             and to return "&var[layer0][layer1][layer2]"
+ */
+#define EDAC_DIMM_PTR(layers, var, nlayers, layer0, layer1, layer2) ({ \
+       typeof(*var) __p;                                               \
+       int ___i = EDAC_DIMM_OFF(layers, nlayers, layer0, layer1, layer2);      \
+       if (___i < 0)                                                   \
                __p = NULL;                                             \
+       else                                                            \
+               __p = (var)[___i];                                      \
        __p;                                                            \
 })
 
-
-/* FIXME: add the proper per-location error counts */
 struct dimm_info {
+       struct device dev;
+
        char label[EDAC_MC_LABEL_LEN + 1];      /* DIMM label on motherboard */
 
        /* Memory location data */
@@ -456,6 +521,8 @@ struct rank_info {
 };
 
 struct csrow_info {
+       struct device dev;
+
        /* Used only by edac_mc_find_csrow_by_page() */
        unsigned long first_page;       /* first page number in csrow */
        unsigned long last_page;        /* last page number in csrow */
@@ -469,44 +536,26 @@ struct csrow_info {
 
        struct mem_ctl_info *mci;       /* the parent */
 
-       struct kobject kobj;    /* sysfs kobject for this csrow */
-
        /* channel information for this csrow */
        u32 nr_channels;
-       struct rank_info *channels;
+       struct rank_info **channels;
 };
 
-struct mcidev_sysfs_group {
-       const char *name;                               /* group name */
-       const struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
-};
-
-struct mcidev_sysfs_group_kobj {
-       struct list_head list;          /* list for all instances within a mc */
-
-       struct kobject kobj;            /* kobj for the group */
-
-       const struct mcidev_sysfs_group *grp;   /* group description table */
-       struct mem_ctl_info *mci;       /* the parent */
-};
-
-/* mcidev_sysfs_attribute structure
- *     used for driver sysfs attributes and in mem_ctl_info
- *     sysfs top level entries
+/*
+ * struct errcount_attribute - used to store the several error counts
  */
-struct mcidev_sysfs_attribute {
-       /* It should use either attr or grp */
-       struct attribute attr;
-       const struct mcidev_sysfs_group *grp;   /* Points to a group of attributes */
-
-       /* Ops for show/store values at the attribute - not used on group */
-        ssize_t (*show)(struct mem_ctl_info *,char *);
-        ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
+struct errcount_attribute_data {
+       int n_layers;
+       int pos[EDAC_MAX_LAYERS];
+       int layer0, layer1, layer2;
 };
 
 /* MEMORY controller information structure
  */
 struct mem_ctl_info {
+       struct device                   dev;
+       struct bus_type                 bus;
+
        struct list_head link;  /* for global list of mem_ctl_info structs */
 
        struct module *owner;   /* Module owner of this control struct */
@@ -548,10 +597,18 @@ struct mem_ctl_info {
        unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci,
                                           unsigned long page);
        int mc_idx;
-       struct csrow_info *csrows;
+       struct csrow_info **csrows;
        unsigned nr_csrows, num_cschannel;
 
-       /* Memory Controller hierarchy */
+       /*
+        * Memory Controller hierarchy
+        *
+        * There are basically two types of memory controller: the ones that
+        * sees memory sticks ("dimms"), and the ones that sees memory ranks.
+        * All old memory controllers enumerate memories per rank, but most
+        * of the recent drivers enumerate memories per DIMM, instead.
+        * When the memory controller is per rank, mem_is_per_rank is true.
+        */
        unsigned n_layers;
        struct edac_mc_layer *layers;
        bool mem_is_per_rank;
@@ -560,14 +617,14 @@ struct mem_ctl_info {
         * DIMM info. Will eventually remove the entire csrows_info some day
         */
        unsigned tot_dimms;
-       struct dimm_info *dimms;
+       struct dimm_info **dimms;
 
        /*
         * FIXME - what about controllers on other busses? - IDs must be
         * unique.  dev pointer should be sufficiently unique, but
         * BUS:SLOT.FUNC numbers may not be unique.
         */
-       struct device *dev;
+       struct device *pdev;
        const char *mod_name;
        const char *mod_ver;
        const char *ctl_name;
@@ -586,12 +643,6 @@ struct mem_ctl_info {
 
        struct completion complete;
 
-       /* edac sysfs device control */
-       struct kobject edac_mci_kobj;
-
-       /* list for all grp instances within a mc */
-       struct list_head grp_kobj_list;
-
        /* Additional top controller level attributes, but specified
         * by the low level driver.
         *
@@ -609,6 +660,13 @@ struct mem_ctl_info {
 
        /* the internal state of this controller instance */
        int op_state;
+
+#ifdef CONFIG_EDAC_DEBUG
+       struct dentry *debugfs;
+       u8 fake_inject_layer[EDAC_MAX_LAYERS];
+       u32 fake_inject_ue;
+       u16 fake_inject_count;
+#endif
 };
 
 #endif
index 7edcf10317182a32c4ffeef84b5c6dd1d7ed091c..db04ec5121cb770d6c571a59234997c60527e539 100644 (file)
@@ -152,7 +152,7 @@ static inline void fw_card_put(struct fw_card *card)
 struct fw_attribute_group {
        struct attribute_group *groups[2];
        struct attribute_group group;
-       struct attribute *attrs[12];
+       struct attribute *attrs[13];
 };
 
 enum fw_device_state {
@@ -321,7 +321,7 @@ struct fw_transaction {
 
 struct fw_address_handler {
        u64 offset;
-       size_t length;
+       u64 length;
        fw_address_callback_t address_callback;
        void *callback_data;
        struct list_head link;
diff --git a/include/linux/flex_proportions.h b/include/linux/flex_proportions.h
new file mode 100644 (file)
index 0000000..4ebc49f
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Floating proportions with flexible aging period
+ *
+ *  Copyright (C) 2011, SUSE, Jan Kara <jack@suse.cz>
+ */
+
+#ifndef _LINUX_FLEX_PROPORTIONS_H
+#define _LINUX_FLEX_PROPORTIONS_H
+
+#include <linux/percpu_counter.h>
+#include <linux/spinlock.h>
+#include <linux/seqlock.h>
+
+/*
+ * When maximum proportion of some event type is specified, this is the
+ * precision with which we allow limitting. Note that this creates an upper
+ * bound on the number of events per period like
+ *   ULLONG_MAX >> FPROP_FRAC_SHIFT.
+ */
+#define FPROP_FRAC_SHIFT 10
+#define FPROP_FRAC_BASE (1UL << FPROP_FRAC_SHIFT)
+
+/*
+ * ---- Global proportion definitions ----
+ */
+struct fprop_global {
+       /* Number of events in the current period */
+       struct percpu_counter events;
+       /* Current period */
+       unsigned int period;
+       /* Synchronization with period transitions */
+       seqcount_t sequence;
+};
+
+int fprop_global_init(struct fprop_global *p);
+void fprop_global_destroy(struct fprop_global *p);
+bool fprop_new_period(struct fprop_global *p, int periods);
+
+/*
+ *  ---- SINGLE ----
+ */
+struct fprop_local_single {
+       /* the local events counter */
+       unsigned long events;
+       /* Period in which we last updated events */
+       unsigned int period;
+       raw_spinlock_t lock;    /* Protect period and numerator */
+};
+
+#define INIT_FPROP_LOCAL_SINGLE(name)                  \
+{      .lock = __RAW_SPIN_LOCK_UNLOCKED(name.lock),    \
+}
+
+int fprop_local_init_single(struct fprop_local_single *pl);
+void fprop_local_destroy_single(struct fprop_local_single *pl);
+void __fprop_inc_single(struct fprop_global *p, struct fprop_local_single *pl);
+void fprop_fraction_single(struct fprop_global *p,
+       struct fprop_local_single *pl, unsigned long *numerator,
+       unsigned long *denominator);
+
+static inline
+void fprop_inc_single(struct fprop_global *p, struct fprop_local_single *pl)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __fprop_inc_single(p, pl);
+       local_irq_restore(flags);
+}
+
+/*
+ * ---- PERCPU ----
+ */
+struct fprop_local_percpu {
+       /* the local events counter */
+       struct percpu_counter events;
+       /* Period in which we last updated events */
+       unsigned int period;
+       raw_spinlock_t lock;    /* Protect period and numerator */
+};
+
+int fprop_local_init_percpu(struct fprop_local_percpu *pl);
+void fprop_local_destroy_percpu(struct fprop_local_percpu *pl);
+void __fprop_inc_percpu(struct fprop_global *p, struct fprop_local_percpu *pl);
+void __fprop_inc_percpu_max(struct fprop_global *p, struct fprop_local_percpu *pl,
+                           int max_frac);
+void fprop_fraction_percpu(struct fprop_global *p,
+       struct fprop_local_percpu *pl, unsigned long *numerator,
+       unsigned long *denominator);
+
+static inline
+void fprop_inc_percpu(struct fprop_global *p, struct fprop_local_percpu *pl)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __fprop_inc_percpu(p, pl);
+       local_irq_restore(flags);
+}
+
+#endif
index 8fabb037a48db40e8a490fc74c15ce907ad9059a..b178f9e91e23c473e39881c33ee3a36544cefa90 100644 (file)
@@ -1163,9 +1163,10 @@ struct lock_manager {
        struct list_head list;
 };
 
-void locks_start_grace(struct lock_manager *);
+struct net;
+void locks_start_grace(struct net *, struct lock_manager *);
 void locks_end_grace(struct lock_manager *);
-int locks_in_grace(void);
+int locks_in_grace(struct net *);
 
 /* that will die - we need it for nfs_lock_info */
 #include <linux/nfs_fs_i.h>
index 4d5e57ff66144f48fce709bcf5d151b96f8f1530..1c06b5c7c308468204e53883398c11d29d12539a 100644 (file)
@@ -12,7 +12,8 @@
 #define _LINUX_I2C_OCORES_H
 
 struct ocores_i2c_platform_data {
-       u32 regstep;   /* distance between registers */
+       u32 reg_shift; /* register offset shift value */
+       u32 reg_io_width; /* register io read/write width */
        u32 clock_khz; /* input clock in kHz */
        u8 num_devices; /* number of devices in the devices list */
        struct i2c_board_info const *devices; /* devices connected to the bus */
index 1d0fe4877b1fa0fdd4c9e2c36a4f154874de8cc1..5970266930a26f0517208b03336646232067dc1a 100644 (file)
@@ -68,6 +68,9 @@ extern int i2c_master_recv(const struct i2c_client *client, char *buf,
  */
 extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
                        int num);
+/* Unlocked flavor */
+extern int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+                         int num);
 
 /* This is the very generalized SMBus access routine. You probably do not
    want to use this, though; one of the functions below may be much easier,
index 555382660bc40e00eb4876eae585f3f9a5e6eea6..7ea898c55a601e04d11231a9425d9b29460089b0 100644 (file)
@@ -555,6 +555,8 @@ struct twl4030_clock_init_data {
 struct twl4030_bci_platform_data {
        int *battery_tmp_tbl;
        unsigned int tblsize;
+       int     bb_uvolt;       /* voltage to charge backup battery */
+       int     bb_uamp;        /* current for backup battery charging */
 };
 
 /* TWL4030_GPIO_MAX (18) GPIOs, with interrupts */
diff --git a/include/linux/input/edt-ft5x06.h b/include/linux/input/edt-ft5x06.h
new file mode 100644 (file)
index 0000000..8a1e0d1
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _EDT_FT5X06_H
+#define _EDT_FT5X06_H
+
+/*
+ * Copyright (c) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+struct edt_ft5x06_platform_data {
+       int irq_pin;
+       int reset_pin;
+
+       /* startup defaults for operational parameters */
+       bool use_parameters;
+       u8 gain;
+       u8 threshold;
+       u8 offset;
+       u8 report_rate;
+};
+
+#endif /* _EDT_FT5X06_H */
diff --git a/include/linux/kern_levels.h b/include/linux/kern_levels.h
new file mode 100644 (file)
index 0000000..866caaa
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __KERN_LEVELS_H__
+#define __KERN_LEVELS_H__
+
+#define KERN_SOH       "\001"          /* ASCII Start Of Header */
+#define KERN_SOH_ASCII '\001'
+
+#define KERN_EMERG     KERN_SOH "0"    /* system is unusable */
+#define KERN_ALERT     KERN_SOH "1"    /* action must be taken immediately */
+#define KERN_CRIT      KERN_SOH "2"    /* critical conditions */
+#define KERN_ERR       KERN_SOH "3"    /* error conditions */
+#define KERN_WARNING   KERN_SOH "4"    /* warning conditions */
+#define KERN_NOTICE    KERN_SOH "5"    /* normal but significant condition */
+#define KERN_INFO      KERN_SOH "6"    /* informational */
+#define KERN_DEBUG     KERN_SOH "7"    /* debug-level messages */
+
+#define KERN_DEFAULT   KERN_SOH "d"    /* the default kernel loglevel */
+
+/*
+ * Annotation for a "continued" line of log printout (only done after a
+ * line that had no enclosing \n). Only to be used by core/arch code
+ * during early bootup (a continued line is not SMP-safe otherwise).
+ */
+#define KERN_CONT      ""
+
+#endif
index 39e3c082c49d489a32ab781e080b28236661877f..f0c651cda7b0b7a367b41160ed88ea487838a72b 100644 (file)
@@ -13,6 +13,7 @@
 #define _LINUX_KEY_TYPE_H
 
 #include <linux/key.h>
+#include <linux/errno.h>
 
 #ifdef CONFIG_KEYS
 
diff --git a/include/linux/libfdt.h b/include/linux/libfdt.h
new file mode 100644 (file)
index 0000000..4c0306c
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _INCLUDE_LIBFDT_H_
+#define _INCLUDE_LIBFDT_H_
+
+#include <linux/libfdt_env.h>
+#include "../../scripts/dtc/libfdt/fdt.h"
+#include "../../scripts/dtc/libfdt/libfdt.h"
+
+#endif /* _INCLUDE_LIBFDT_H_ */
diff --git a/include/linux/libfdt_env.h b/include/linux/libfdt_env.h
new file mode 100644 (file)
index 0000000..01508c7
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#include <linux/string.h>
+
+#include <asm/byteorder.h>
+
+#define fdt32_to_cpu(x) be32_to_cpu(x)
+#define cpu_to_fdt32(x) cpu_to_be32(x)
+#define fdt64_to_cpu(x) be64_to_cpu(x)
+#define cpu_to_fdt64(x) cpu_to_be64(x)
+
+#endif /* _LIBFDT_ENV_H */
index f04ce6ac6d04fd84f65c533cb34b5748d2d6665f..f5a051a79273c7f3fcdb1a18f4c9e2522e68cc85 100644 (file)
@@ -262,11 +262,11 @@ typedef int         (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref);
 __be32           nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
                              struct nlm_host *, struct nlm_lock *, int,
                              struct nlm_cookie *, int);
-__be32           nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
+__be32           nlmsvc_unlock(struct net *net, struct nlm_file *, struct nlm_lock *);
 __be32           nlmsvc_testlock(struct svc_rqst *, struct nlm_file *,
                        struct nlm_host *, struct nlm_lock *,
                        struct nlm_lock *, struct nlm_cookie *);
-__be32           nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
+__be32           nlmsvc_cancel_blocked(struct net *net, struct nlm_file *, struct nlm_lock *);
 unsigned long    nlmsvc_retry_blocked(void);
 void             nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
                                        nlm_host_match_fn_t match);
@@ -279,7 +279,7 @@ void                  nlmsvc_release_call(struct nlm_rqst *);
 __be32           nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
                                        struct nfs_fh *);
 void             nlm_release_file(struct nlm_file *);
-void             nlmsvc_mark_resources(void);
+void             nlmsvc_mark_resources(struct net *);
 void             nlmsvc_free_host_resources(struct nlm_host *);
 void             nlmsvc_invalidate_all(void);
 
index 4aa42732e47f34ca29392180fbee0fc73a086cd2..95b738c7abff9ac1e45a5e78e1daf1437b2283fd 100644 (file)
@@ -215,7 +215,7 @@ extern struct zonelist *huge_zonelist(struct vm_area_struct *vma,
 extern bool init_nodemask_of_mempolicy(nodemask_t *mask);
 extern bool mempolicy_nodemask_intersects(struct task_struct *tsk,
                                const nodemask_t *mask);
-extern unsigned slab_node(struct mempolicy *policy);
+extern unsigned slab_node(void);
 
 extern enum zone_type policy_zone;
 
diff --git a/include/linux/mfd/88pm80x.h b/include/linux/mfd/88pm80x.h
new file mode 100644 (file)
index 0000000..a0ca0dc
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * Marvell 88PM80x Interface
+ *
+ * Copyright (C) 2012 Marvell International Ltd.
+ * Qiao Zhou <zhouqiao@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MFD_88PM80X_H
+#define __LINUX_MFD_88PM80X_H
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/atomic.h>
+
+#define PM80X_VERSION_MASK             (0xFF)  /* 80X chip ID mask */
+enum {
+       CHIP_INVALID = 0,
+       CHIP_PM800,
+       CHIP_PM805,
+       CHIP_MAX,
+};
+
+enum {
+       PM800_ID_BUCK1 = 0,
+       PM800_ID_BUCK2,
+       PM800_ID_BUCK3,
+       PM800_ID_BUCK4,
+       PM800_ID_BUCK5,
+
+       PM800_ID_LDO1,
+       PM800_ID_LDO2,
+       PM800_ID_LDO3,
+       PM800_ID_LDO4,
+       PM800_ID_LDO5,
+       PM800_ID_LDO6,
+       PM800_ID_LDO7,
+       PM800_ID_LDO8,
+       PM800_ID_LDO9,
+       PM800_ID_LDO10,
+       PM800_ID_LDO11,
+       PM800_ID_LDO12,
+       PM800_ID_LDO13,
+       PM800_ID_LDO14,
+       PM800_ID_LDO15,
+       PM800_ID_LDO16,
+       PM800_ID_LDO17,
+       PM800_ID_LDO18,
+       PM800_ID_LDO19,
+
+       PM800_ID_RG_MAX,
+};
+#define PM800_MAX_REGULATOR    PM800_ID_RG_MAX /* 5 Bucks, 19 LDOs */
+#define PM800_NUM_BUCK (5)     /*5 Bucks */
+#define PM800_NUM_LDO (19)     /*19 Bucks */
+
+/* page 0 basic: slave adder 0x60 */
+
+#define PM800_STATUS_1                 (0x01)
+#define PM800_ONKEY_STS1               (1 << 0)
+#define PM800_EXTON_STS1               (1 << 1)
+#define PM800_CHG_STS1                 (1 << 2)
+#define PM800_BAT_STS1                 (1 << 3)
+#define PM800_VBUS_STS1                        (1 << 4)
+#define PM800_LDO_PGOOD_STS1   (1 << 5)
+#define PM800_BUCK_PGOOD_STS1  (1 << 6)
+
+#define PM800_STATUS_2                 (0x02)
+#define PM800_RTC_ALARM_STS2   (1 << 0)
+
+/* Wakeup Registers */
+#define PM800_WAKEUP1          (0x0D)
+
+#define PM800_WAKEUP2          (0x0E)
+#define PM800_WAKEUP2_INV_INT          (1 << 0)
+#define PM800_WAKEUP2_INT_CLEAR                (1 << 1)
+#define PM800_WAKEUP2_INT_MASK         (1 << 2)
+
+#define PM800_POWER_UP_LOG     (0x10)
+
+/* Referance and low power registers */
+#define PM800_LOW_POWER1               (0x20)
+#define PM800_LOW_POWER2               (0x21)
+#define PM800_LOW_POWER_CONFIG3        (0x22)
+#define PM800_LOW_POWER_CONFIG4        (0x23)
+
+/* GPIO register */
+#define PM800_GPIO_0_1_CNTRL           (0x30)
+#define PM800_GPIO0_VAL                                (1 << 0)
+#define PM800_GPIO0_GPIO_MODE(x)       (x << 1)
+#define PM800_GPIO1_VAL                                (1 << 4)
+#define PM800_GPIO1_GPIO_MODE(x)       (x << 5)
+
+#define PM800_GPIO_2_3_CNTRL           (0x31)
+#define PM800_GPIO2_VAL                                (1 << 0)
+#define PM800_GPIO2_GPIO_MODE(x)       (x << 1)
+#define PM800_GPIO3_VAL                                (1 << 4)
+#define PM800_GPIO3_GPIO_MODE(x)       (x << 5)
+#define PM800_GPIO3_MODE_MASK          0x1F
+#define PM800_GPIO3_HEADSET_MODE       PM800_GPIO3_GPIO_MODE(6)
+
+#define PM800_GPIO_4_CNTRL                     (0x32)
+#define PM800_GPIO4_VAL                                (1 << 0)
+#define PM800_GPIO4_GPIO_MODE(x)       (x << 1)
+
+#define PM800_HEADSET_CNTRL            (0x38)
+#define PM800_HEADSET_DET_EN           (1 << 7)
+#define PM800_HSDET_SLP                        (1 << 1)
+/* PWM register */
+#define PM800_PWM1             (0x40)
+#define PM800_PWM2             (0x41)
+#define PM800_PWM3             (0x42)
+#define PM800_PWM4             (0x43)
+
+/* RTC Registers */
+#define PM800_RTC_CONTROL              (0xD0)
+#define PM800_RTC_MISC1                        (0xE1)
+#define PM800_RTC_MISC2                        (0xE2)
+#define PM800_RTC_MISC3                        (0xE3)
+#define PM800_RTC_MISC4                        (0xE4)
+#define PM800_RTC_MISC5                        (0xE7)
+/* bit definitions of RTC Register 1 (0xD0) */
+#define PM800_ALARM1_EN                        (1 << 0)
+#define PM800_ALARM_WAKEUP             (1 << 4)
+#define PM800_ALARM                    (1 << 5)
+#define PM800_RTC1_USE_XO              (1 << 7)
+
+/* Regulator Control Registers: BUCK1,BUCK5,LDO1 have DVC */
+
+/* buck registers */
+#define PM800_SLEEP_BUCK1      (0x30)
+
+/* BUCK Sleep Mode Register 1: BUCK[1..4] */
+#define PM800_BUCK_SLP1                (0x5A)
+#define PM800_BUCK1_SLP1_SHIFT 0
+#define PM800_BUCK1_SLP1_MASK  (0x3 << PM800_BUCK1_SLP1_SHIFT)
+
+/* page 2 GPADC: slave adder 0x02 */
+#define PM800_GPADC_MEAS_EN1           (0x01)
+#define PM800_MEAS_EN1_VBAT         (1 << 2)
+#define PM800_GPADC_MEAS_EN2           (0x02)
+#define PM800_MEAS_EN2_RFTMP        (1 << 0)
+#define PM800_MEAS_GP0_EN                      (1 << 2)
+#define PM800_MEAS_GP1_EN                      (1 << 3)
+#define PM800_MEAS_GP2_EN                      (1 << 4)
+#define PM800_MEAS_GP3_EN                      (1 << 5)
+#define PM800_MEAS_GP4_EN                      (1 << 6)
+
+#define PM800_GPADC_MISC_CONFIG1       (0x05)
+#define PM800_GPADC_MISC_CONFIG2       (0x06)
+#define PM800_GPADC_MISC_GPFSM_EN      (1 << 0)
+#define PM800_GPADC_SLOW_MODE(x)       (x << 3)
+
+#define PM800_GPADC_MISC_CONFIG3               (0x09)
+#define PM800_GPADC_MISC_CONFIG4               (0x0A)
+
+#define PM800_GPADC_PREBIAS1                   (0x0F)
+#define PM800_GPADC0_GP_PREBIAS_TIME(x)        (x << 0)
+#define PM800_GPADC_PREBIAS2                   (0x10)
+
+#define PM800_GP_BIAS_ENA1                             (0x14)
+#define PM800_GPADC_GP_BIAS_EN0                        (1 << 0)
+#define PM800_GPADC_GP_BIAS_EN1                        (1 << 1)
+#define PM800_GPADC_GP_BIAS_EN2                        (1 << 2)
+#define PM800_GPADC_GP_BIAS_EN3                        (1 << 3)
+
+#define PM800_GP_BIAS_OUT1             (0x15)
+#define PM800_BIAS_OUT_GP0             (1 << 0)
+#define PM800_BIAS_OUT_GP1             (1 << 1)
+#define PM800_BIAS_OUT_GP2             (1 << 2)
+#define PM800_BIAS_OUT_GP3             (1 << 3)
+
+#define PM800_GPADC0_LOW_TH            0x20
+#define PM800_GPADC1_LOW_TH            0x21
+#define PM800_GPADC2_LOW_TH            0x22
+#define PM800_GPADC3_LOW_TH            0x23
+#define PM800_GPADC4_LOW_TH            0x24
+
+#define PM800_GPADC0_UPP_TH            0x30
+#define PM800_GPADC1_UPP_TH            0x31
+#define PM800_GPADC2_UPP_TH            0x32
+#define PM800_GPADC3_UPP_TH            0x33
+#define PM800_GPADC4_UPP_TH            0x34
+
+#define PM800_VBBAT_MEAS1              0x40
+#define PM800_VBBAT_MEAS2              0x41
+#define PM800_VBAT_MEAS1               0x42
+#define PM800_VBAT_MEAS2               0x43
+#define PM800_VSYS_MEAS1               0x44
+#define PM800_VSYS_MEAS2               0x45
+#define PM800_VCHG_MEAS1               0x46
+#define PM800_VCHG_MEAS2               0x47
+#define PM800_TINT_MEAS1               0x50
+#define PM800_TINT_MEAS2               0x51
+#define PM800_PMOD_MEAS1               0x52
+#define PM800_PMOD_MEAS2               0x53
+
+#define PM800_GPADC0_MEAS1             0x54
+#define PM800_GPADC0_MEAS2             0x55
+#define PM800_GPADC1_MEAS1             0x56
+#define PM800_GPADC1_MEAS2             0x57
+#define PM800_GPADC2_MEAS1             0x58
+#define PM800_GPADC2_MEAS2             0x59
+#define PM800_GPADC3_MEAS1             0x5A
+#define PM800_GPADC3_MEAS2             0x5B
+#define PM800_GPADC4_MEAS1             0x5C
+#define PM800_GPADC4_MEAS2             0x5D
+
+#define PM800_GPADC4_AVG1              0xA8
+#define PM800_GPADC4_AVG2              0xA9
+
+/* 88PM805 Registers */
+#define PM805_MAIN_POWERUP             (0x01)
+#define PM805_INT_STATUS0              (0x02)  /* for ena/dis all interrupts */
+
+#define PM805_STATUS0_INT_CLEAR                (1 << 0)
+#define PM805_STATUS0_INV_INT          (1 << 1)
+#define PM800_STATUS0_INT_MASK         (1 << 2)
+
+#define PM805_INT_STATUS1              (0x03)
+
+#define PM805_INT1_HP1_SHRT            (1 << 0)
+#define PM805_INT1_HP2_SHRT            (1 << 1)
+#define PM805_INT1_MIC_CONFLICT                (1 << 2)
+#define PM805_INT1_CLIP_FAULT          (1 << 3)
+#define PM805_INT1_LDO_OFF                     (1 << 4)
+#define PM805_INT1_SRC_DPLL_LOCK       (1 << 5)
+
+#define PM805_INT_STATUS2              (0x04)
+
+#define PM805_INT2_MIC_DET                     (1 << 0)
+#define PM805_INT2_SHRT_BTN_DET                (1 << 1)
+#define PM805_INT2_VOLM_BTN_DET                (1 << 2)
+#define PM805_INT2_VOLP_BTN_DET                (1 << 3)
+#define PM805_INT2_RAW_PLL_FAULT       (1 << 4)
+#define PM805_INT2_FINE_PLL_FAULT      (1 << 5)
+
+#define PM805_INT_MASK1                        (0x05)
+#define PM805_INT_MASK2                        (0x06)
+#define PM805_SHRT_BTN_DET             (1 << 1)
+
+/* number of status and int reg in a row */
+#define PM805_INT_REG_NUM              (2)
+
+#define PM805_MIC_DET1                 (0x07)
+#define PM805_MIC_DET_EN_MIC_DET (1 << 0)
+#define PM805_MIC_DET2                 (0x08)
+#define PM805_MIC_DET_STATUS1  (0x09)
+
+#define PM805_MIC_DET_STATUS3  (0x0A)
+#define PM805_AUTO_SEQ_STATUS1 (0x0B)
+#define PM805_AUTO_SEQ_STATUS2 (0x0C)
+
+#define PM805_ADC_SETTING1             (0x10)
+#define PM805_ADC_SETTING2             (0x11)
+#define PM805_ADC_SETTING3             (0x11)
+#define PM805_ADC_GAIN1                        (0x12)
+#define PM805_ADC_GAIN2                        (0x13)
+#define PM805_DMIC_SETTING             (0x15)
+#define PM805_DWS_SETTING              (0x16)
+#define PM805_MIC_CONFLICT_STS (0x17)
+
+#define PM805_PDM_SETTING1             (0x20)
+#define PM805_PDM_SETTING2             (0x21)
+#define PM805_PDM_SETTING3             (0x22)
+#define PM805_PDM_CONTROL1             (0x23)
+#define PM805_PDM_CONTROL2             (0x24)
+#define PM805_PDM_CONTROL3             (0x25)
+
+#define PM805_HEADPHONE_SETTING                        (0x26)
+#define PM805_HEADPHONE_GAIN_A2A               (0x27)
+#define PM805_HEADPHONE_SHORT_STATE            (0x28)
+#define PM805_EARPHONE_SETTING                 (0x29)
+#define PM805_AUTO_SEQ_SETTING                 (0x2A)
+
+struct pm80x_rtc_pdata {
+       int             vrtc;
+       int             rtc_wakeup;
+};
+
+struct pm80x_subchip {
+       struct i2c_client *power_page;  /* chip client for power page */
+       struct i2c_client *gpadc_page;  /* chip client for gpadc page */
+       struct regmap *regmap_power;
+       struct regmap *regmap_gpadc;
+       unsigned short power_page_addr; /* power page I2C address */
+       unsigned short gpadc_page_addr; /* gpadc page I2C address */
+};
+
+struct pm80x_chip {
+       struct pm80x_subchip *subchip;
+       struct device *dev;
+       struct i2c_client *client;
+       struct i2c_client *companion;
+       struct regmap *regmap;
+       struct regmap_irq_chip *regmap_irq_chip;
+       struct regmap_irq_chip_data *irq_data;
+       unsigned char version;
+       int id;
+       int irq;
+       int irq_mode;
+       unsigned long wu_flag;
+       spinlock_t lock;
+};
+
+struct pm80x_platform_data {
+       struct pm80x_rtc_pdata *rtc;
+       unsigned short power_page_addr; /* power page I2C address */
+       unsigned short gpadc_page_addr; /* gpadc page I2C address */
+       int irq_mode;           /* Clear interrupt by read/write(0/1) */
+       int batt_det;           /* enable/disable */
+       int (*plat_config)(struct pm80x_chip *chip,
+                               struct pm80x_platform_data *pdata);
+};
+
+extern const struct dev_pm_ops pm80x_pm_ops;
+extern const struct regmap_config pm80x_regmap_config;
+
+static inline int pm80x_request_irq(struct pm80x_chip *pm80x, int irq,
+                                    irq_handler_t handler, unsigned long flags,
+                                    const char *name, void *data)
+{
+       if (!pm80x->irq_data)
+               return -EINVAL;
+       return request_threaded_irq(regmap_irq_get_virq(pm80x->irq_data, irq),
+                                   NULL, handler, flags, name, data);
+}
+
+static inline void pm80x_free_irq(struct pm80x_chip *pm80x, int irq, void *data)
+{
+       if (!pm80x->irq_data)
+               return;
+       free_irq(regmap_irq_get_virq(pm80x->irq_data, irq), data);
+}
+
+#ifdef CONFIG_PM
+static inline int pm80x_dev_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       int irq = platform_get_irq(pdev, 0);
+
+       if (device_may_wakeup(dev))
+               set_bit((1 << irq), &chip->wu_flag);
+
+       return 0;
+}
+
+static inline int pm80x_dev_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       int irq = platform_get_irq(pdev, 0);
+
+       if (device_may_wakeup(dev))
+               clear_bit((1 << irq), &chip->wu_flag);
+
+       return 0;
+}
+#endif
+
+extern int pm80x_init(struct i2c_client *client,
+                            const struct i2c_device_id *id) __devinit;
+extern int pm80x_deinit(struct i2c_client *client);
+#endif /* __LINUX_MFD_88PM80X_H */
index 84d071ade1d89df5dd9faf6e6de1c7f3a0f88bcf..7b24943779fa7258904f2b93dbd484856b8fe74d 100644 (file)
@@ -136,6 +136,7 @@ enum {
        PM8607_ID_LDO13,
        PM8607_ID_LDO14,
        PM8607_ID_LDO15,
+       PM8606_ID_PREG,
 
        PM8607_ID_RG_MAX,
 };
index bc9b84b60ec6e53a35b0c6b7e7fe103f5c4e8986..3764cb6759e31e05a39c8eb99034f48d323462b4 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/atomic.h>
 #include <linux/mutex.h>
+#include <linux/irqdomain.h>
 
 struct device;
 
@@ -227,6 +228,7 @@ enum ab8500_version {
  * @irq_lock: genirq bus lock
  * @transfer_ongoing: 0 if no transfer ongoing
  * @irq: irq line
+ * @irq_domain: irq domain
  * @version: chip version id (e.g. ab8500 or ab9540)
  * @chip_id: chip revision id
  * @write: register write
@@ -247,6 +249,7 @@ struct ab8500 {
        atomic_t        transfer_ongoing;
        int             irq_base;
        int             irq;
+       struct irq_domain  *domain;
        enum ab8500_version version;
        u8              chip_id;
 
@@ -338,4 +341,6 @@ static inline int is_ab8500_2p0(struct ab8500 *ab)
        return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
 }
 
+int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq);
+
 #endif /* MFD_AB8500_H */
diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h
new file mode 100644 (file)
index 0000000..dd231ac
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Arizona MFD internals
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM_ARIZONA_CORE_H
+#define _WM_ARIZONA_CORE_H
+
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/arizona/pdata.h>
+
+#define ARIZONA_MAX_CORE_SUPPLIES 3
+
+enum arizona_type {
+       WM5102 = 1,
+       WM5110 = 2,
+};
+
+#define ARIZONA_IRQ_GP1                    0
+#define ARIZONA_IRQ_GP2                    1
+#define ARIZONA_IRQ_GP3                    2
+#define ARIZONA_IRQ_GP4                    3
+#define ARIZONA_IRQ_GP5_FALL               4
+#define ARIZONA_IRQ_GP5_RISE               5
+#define ARIZONA_IRQ_JD_FALL                6
+#define ARIZONA_IRQ_JD_RISE                7
+#define ARIZONA_IRQ_DSP1_RAM_RDY           8
+#define ARIZONA_IRQ_DSP2_RAM_RDY           9
+#define ARIZONA_IRQ_DSP3_RAM_RDY          10
+#define ARIZONA_IRQ_DSP4_RAM_RDY          11
+#define ARIZONA_IRQ_DSP_IRQ1              12
+#define ARIZONA_IRQ_DSP_IRQ2              13
+#define ARIZONA_IRQ_DSP_IRQ3              14
+#define ARIZONA_IRQ_DSP_IRQ4              15
+#define ARIZONA_IRQ_DSP_IRQ5              16
+#define ARIZONA_IRQ_DSP_IRQ6              17
+#define ARIZONA_IRQ_DSP_IRQ7              18
+#define ARIZONA_IRQ_DSP_IRQ8              19
+#define ARIZONA_IRQ_SPK_SHUTDOWN_WARN     20
+#define ARIZONA_IRQ_SPK_SHUTDOWN          21
+#define ARIZONA_IRQ_MICDET                22
+#define ARIZONA_IRQ_HPDET                 23
+#define ARIZONA_IRQ_WSEQ_DONE             24
+#define ARIZONA_IRQ_DRC2_SIG_DET          25
+#define ARIZONA_IRQ_DRC1_SIG_DET          26
+#define ARIZONA_IRQ_ASRC2_LOCK            27
+#define ARIZONA_IRQ_ASRC1_LOCK            28
+#define ARIZONA_IRQ_UNDERCLOCKED          29
+#define ARIZONA_IRQ_OVERCLOCKED           30
+#define ARIZONA_IRQ_FLL2_LOCK             31
+#define ARIZONA_IRQ_FLL1_LOCK             32
+#define ARIZONA_IRQ_CLKGEN_ERR            33
+#define ARIZONA_IRQ_CLKGEN_ERR_ASYNC      34
+#define ARIZONA_IRQ_ASRC_CFG_ERR          35
+#define ARIZONA_IRQ_AIF3_ERR              36
+#define ARIZONA_IRQ_AIF2_ERR              37
+#define ARIZONA_IRQ_AIF1_ERR              38
+#define ARIZONA_IRQ_CTRLIF_ERR            39
+#define ARIZONA_IRQ_MIXER_DROPPED_SAMPLES 40
+#define ARIZONA_IRQ_ASYNC_CLK_ENA_LOW     41
+#define ARIZONA_IRQ_SYSCLK_ENA_LOW        42
+#define ARIZONA_IRQ_ISRC1_CFG_ERR         43
+#define ARIZONA_IRQ_ISRC2_CFG_ERR         44
+#define ARIZONA_IRQ_BOOT_DONE             45
+#define ARIZONA_IRQ_DCS_DAC_DONE          46
+#define ARIZONA_IRQ_DCS_HP_DONE           47
+#define ARIZONA_IRQ_FLL2_CLOCK_OK         48
+#define ARIZONA_IRQ_FLL1_CLOCK_OK         49
+
+#define ARIZONA_NUM_IRQ                   50
+
+struct arizona {
+       struct regmap *regmap;
+       struct device *dev;
+
+       enum arizona_type type;
+       unsigned int rev;
+
+       int num_core_supplies;
+       struct regulator_bulk_data core_supplies[ARIZONA_MAX_CORE_SUPPLIES];
+       struct regulator *dcvdd;
+
+       struct arizona_pdata pdata;
+
+       int irq;
+       struct irq_domain *virq;
+       struct regmap_irq_chip_data *aod_irq_chip;
+       struct regmap_irq_chip_data *irq_chip;
+
+       struct mutex clk_lock;
+       int clk32k_ref;
+};
+
+int arizona_clk32k_enable(struct arizona *arizona);
+int arizona_clk32k_disable(struct arizona *arizona);
+
+int arizona_request_irq(struct arizona *arizona, int irq, char *name,
+                       irq_handler_t handler, void *data);
+void arizona_free_irq(struct arizona *arizona, int irq, void *data);
+int arizona_set_irq_wake(struct arizona *arizona, int irq, int on);
+
+int wm5102_patch(struct arizona *arizona);
+int wm5110_patch(struct arizona *arizona);
+
+#endif
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h
new file mode 100644 (file)
index 0000000..7ab4429
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Platform data for Arizona devices
+ *
+ * Copyright 2012 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 _ARIZONA_PDATA_H
+#define _ARIZONA_PDATA_H
+
+#define ARIZONA_GPN_DIR                          0x8000  /* GPN_DIR */
+#define ARIZONA_GPN_DIR_MASK                     0x8000  /* GPN_DIR */
+#define ARIZONA_GPN_DIR_SHIFT                        15  /* GPN_DIR */
+#define ARIZONA_GPN_DIR_WIDTH                         1  /* GPN_DIR */
+#define ARIZONA_GPN_PU                           0x4000  /* GPN_PU */
+#define ARIZONA_GPN_PU_MASK                      0x4000  /* GPN_PU */
+#define ARIZONA_GPN_PU_SHIFT                         14  /* GPN_PU */
+#define ARIZONA_GPN_PU_WIDTH                          1  /* GPN_PU */
+#define ARIZONA_GPN_PD                           0x2000  /* GPN_PD */
+#define ARIZONA_GPN_PD_MASK                      0x2000  /* GPN_PD */
+#define ARIZONA_GPN_PD_SHIFT                         13  /* GPN_PD */
+#define ARIZONA_GPN_PD_WIDTH                          1  /* GPN_PD */
+#define ARIZONA_GPN_LVL                          0x0800  /* GPN_LVL */
+#define ARIZONA_GPN_LVL_MASK                     0x0800  /* GPN_LVL */
+#define ARIZONA_GPN_LVL_SHIFT                        11  /* GPN_LVL */
+#define ARIZONA_GPN_LVL_WIDTH                         1  /* GPN_LVL */
+#define ARIZONA_GPN_POL                          0x0400  /* GPN_POL */
+#define ARIZONA_GPN_POL_MASK                     0x0400  /* GPN_POL */
+#define ARIZONA_GPN_POL_SHIFT                        10  /* GPN_POL */
+#define ARIZONA_GPN_POL_WIDTH                         1  /* GPN_POL */
+#define ARIZONA_GPN_OP_CFG                       0x0200  /* GPN_OP_CFG */
+#define ARIZONA_GPN_OP_CFG_MASK                  0x0200  /* GPN_OP_CFG */
+#define ARIZONA_GPN_OP_CFG_SHIFT                      9  /* GPN_OP_CFG */
+#define ARIZONA_GPN_OP_CFG_WIDTH                      1  /* GPN_OP_CFG */
+#define ARIZONA_GPN_DB                           0x0100  /* GPN_DB */
+#define ARIZONA_GPN_DB_MASK                      0x0100  /* GPN_DB */
+#define ARIZONA_GPN_DB_SHIFT                          8  /* GPN_DB */
+#define ARIZONA_GPN_DB_WIDTH                          1  /* GPN_DB */
+#define ARIZONA_GPN_FN_MASK                      0x007F  /* GPN_FN - [6:0] */
+#define ARIZONA_GPN_FN_SHIFT                          0  /* GPN_FN - [6:0] */
+#define ARIZONA_GPN_FN_WIDTH                          7  /* GPN_FN - [6:0] */
+
+#define ARIZONA_MAX_GPIO 5
+
+#define ARIZONA_32KZ_MCLK1 1
+#define ARIZONA_32KZ_MCLK2 2
+#define ARIZONA_32KZ_NONE  3
+
+#define ARIZONA_MAX_INPUT 4
+
+#define ARIZONA_DMIC_MICVDD   0
+#define ARIZONA_DMIC_MICBIAS1 1
+#define ARIZONA_DMIC_MICBIAS2 2
+#define ARIZONA_DMIC_MICBIAS3 3
+
+#define ARIZONA_INMODE_DIFF 0
+#define ARIZONA_INMODE_SE   1
+#define ARIZONA_INMODE_DMIC 2
+
+#define ARIZONA_MAX_OUTPUT 6
+
+#define ARIZONA_MAX_PDM_SPK 2
+
+struct regulator_init_data;
+
+struct arizona_micd_config {
+       unsigned int src;
+       unsigned int bias;
+       bool gpio;
+};
+
+struct arizona_pdata {
+       int reset;      /** GPIO controlling /RESET, if any */
+       int ldoena;     /** GPIO controlling LODENA, if any */
+
+       /** Regulator configuration for MICVDD */
+       struct regulator_init_data *micvdd;
+
+       /** Regulator configuration for LDO1 */
+       struct regulator_init_data *ldo1;
+
+       /** If a direct 32kHz clock is provided on an MCLK specify it here */
+       int clk32k_src;
+
+       bool irq_active_high; /** IRQ polarity */
+
+       /* Base GPIO */
+       int gpio_base;
+
+       /** Pin state for GPIO pins */
+       int gpio_defaults[ARIZONA_MAX_GPIO];
+
+       /** GPIO for mic detection polarity */
+       int micd_pol_gpio;
+
+       /** Headset polarity configurations */
+       struct arizona_micd_config *micd_configs;
+       int num_micd_configs;
+
+       /** Reference voltage for DMIC inputs */
+       int dmic_ref[ARIZONA_MAX_INPUT];
+
+       /** Mode of input structures */
+       int inmode[ARIZONA_MAX_INPUT];
+
+       /** Mode for outputs */
+       bool out_mono[ARIZONA_MAX_OUTPUT];
+
+       /** PDM speaker mute setting */
+       unsigned int spk_mute[ARIZONA_MAX_PDM_SPK];
+
+       /** PDM speaker format */
+       unsigned int spk_fmt[ARIZONA_MAX_PDM_SPK];
+};
+
+#endif
diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h
new file mode 100644 (file)
index 0000000..7671a28
--- /dev/null
@@ -0,0 +1,6594 @@
+/*
+ * ARIZONA register definitions
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ARIZONA_REGISTERS_H
+#define _ARIZONA_REGISTERS_H
+
+/*
+ * Register values.
+ */
+#define ARIZONA_SOFTWARE_RESET                   0x00
+#define ARIZONA_DEVICE_REVISION                  0x01
+#define ARIZONA_CTRL_IF_SPI_CFG_1                0x08
+#define ARIZONA_CTRL_IF_I2C1_CFG_1               0x09
+#define ARIZONA_CTRL_IF_I2C2_CFG_1               0x0A
+#define ARIZONA_CTRL_IF_I2C1_CFG_2               0x0B
+#define ARIZONA_CTRL_IF_I2C2_CFG_2               0x0C
+#define ARIZONA_CTRL_IF_STATUS_1                 0x0D
+#define ARIZONA_WRITE_SEQUENCER_CTRL_0           0x16
+#define ARIZONA_WRITE_SEQUENCER_CTRL_1           0x17
+#define ARIZONA_WRITE_SEQUENCER_CTRL_2           0x18
+#define ARIZONA_WRITE_SEQUENCER_PROM             0x1A
+#define ARIZONA_TONE_GENERATOR_1                 0x20
+#define ARIZONA_TONE_GENERATOR_2                 0x21
+#define ARIZONA_TONE_GENERATOR_3                 0x22
+#define ARIZONA_TONE_GENERATOR_4                 0x23
+#define ARIZONA_TONE_GENERATOR_5                 0x24
+#define ARIZONA_PWM_DRIVE_1                      0x30
+#define ARIZONA_PWM_DRIVE_2                      0x31
+#define ARIZONA_PWM_DRIVE_3                      0x32
+#define ARIZONA_WAKE_CONTROL                     0x40
+#define ARIZONA_SEQUENCE_CONTROL                 0x41
+#define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1    0x61
+#define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2    0x62
+#define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3    0x63
+#define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4    0x64
+#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1 0x68
+#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2 0x69
+#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3 0x6A
+#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4 0x6B
+#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5 0x6C
+#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6 0x6D
+#define ARIZONA_COMFORT_NOISE_GENERATOR          0x70
+#define ARIZONA_HAPTICS_CONTROL_1                0x90
+#define ARIZONA_HAPTICS_CONTROL_2                0x91
+#define ARIZONA_HAPTICS_PHASE_1_INTENSITY        0x92
+#define ARIZONA_HAPTICS_PHASE_1_DURATION         0x93
+#define ARIZONA_HAPTICS_PHASE_2_INTENSITY        0x94
+#define ARIZONA_HAPTICS_PHASE_2_DURATION         0x95
+#define ARIZONA_HAPTICS_PHASE_3_INTENSITY        0x96
+#define ARIZONA_HAPTICS_PHASE_3_DURATION         0x97
+#define ARIZONA_HAPTICS_STATUS                   0x98
+#define ARIZONA_CLOCK_32K_1                      0x100
+#define ARIZONA_SYSTEM_CLOCK_1                   0x101
+#define ARIZONA_SAMPLE_RATE_1                    0x102
+#define ARIZONA_SAMPLE_RATE_2                    0x103
+#define ARIZONA_SAMPLE_RATE_3                    0x104
+#define ARIZONA_SAMPLE_RATE_1_STATUS             0x10A
+#define ARIZONA_SAMPLE_RATE_2_STATUS             0x10B
+#define ARIZONA_SAMPLE_RATE_3_STATUS             0x10C
+#define ARIZONA_ASYNC_CLOCK_1                    0x112
+#define ARIZONA_ASYNC_SAMPLE_RATE_1              0x113
+#define ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS       0x11B
+#define ARIZONA_OUTPUT_SYSTEM_CLOCK              0x149
+#define ARIZONA_OUTPUT_ASYNC_CLOCK               0x14A
+#define ARIZONA_RATE_ESTIMATOR_1                 0x152
+#define ARIZONA_RATE_ESTIMATOR_2                 0x153
+#define ARIZONA_RATE_ESTIMATOR_3                 0x154
+#define ARIZONA_RATE_ESTIMATOR_4                 0x155
+#define ARIZONA_RATE_ESTIMATOR_5                 0x156
+#define ARIZONA_FLL1_CONTROL_1                   0x171
+#define ARIZONA_FLL1_CONTROL_2                   0x172
+#define ARIZONA_FLL1_CONTROL_3                   0x173
+#define ARIZONA_FLL1_CONTROL_4                   0x174
+#define ARIZONA_FLL1_CONTROL_5                   0x175
+#define ARIZONA_FLL1_CONTROL_6                   0x176
+#define ARIZONA_FLL1_LOOP_FILTER_TEST_1          0x177
+#define ARIZONA_FLL1_NCO_TEST_0                  0x178
+#define ARIZONA_FLL1_SYNCHRONISER_1              0x181
+#define ARIZONA_FLL1_SYNCHRONISER_2              0x182
+#define ARIZONA_FLL1_SYNCHRONISER_3              0x183
+#define ARIZONA_FLL1_SYNCHRONISER_4              0x184
+#define ARIZONA_FLL1_SYNCHRONISER_5              0x185
+#define ARIZONA_FLL1_SYNCHRONISER_6              0x186
+#define ARIZONA_FLL1_SPREAD_SPECTRUM             0x189
+#define ARIZONA_FLL1_GPIO_CLOCK                  0x18A
+#define ARIZONA_FLL2_CONTROL_1                   0x191
+#define ARIZONA_FLL2_CONTROL_2                   0x192
+#define ARIZONA_FLL2_CONTROL_3                   0x193
+#define ARIZONA_FLL2_CONTROL_4                   0x194
+#define ARIZONA_FLL2_CONTROL_5                   0x195
+#define ARIZONA_FLL2_CONTROL_6                   0x196
+#define ARIZONA_FLL2_LOOP_FILTER_TEST_1          0x197
+#define ARIZONA_FLL2_NCO_TEST_0                  0x198
+#define ARIZONA_FLL2_SYNCHRONISER_1              0x1A1
+#define ARIZONA_FLL2_SYNCHRONISER_2              0x1A2
+#define ARIZONA_FLL2_SYNCHRONISER_3              0x1A3
+#define ARIZONA_FLL2_SYNCHRONISER_4              0x1A4
+#define ARIZONA_FLL2_SYNCHRONISER_5              0x1A5
+#define ARIZONA_FLL2_SYNCHRONISER_6              0x1A6
+#define ARIZONA_FLL2_SPREAD_SPECTRUM             0x1A9
+#define ARIZONA_FLL2_GPIO_CLOCK                  0x1AA
+#define ARIZONA_MIC_CHARGE_PUMP_1                0x200
+#define ARIZONA_LDO1_CONTROL_1                   0x210
+#define ARIZONA_LDO2_CONTROL_1                   0x213
+#define ARIZONA_MIC_BIAS_CTRL_1                  0x218
+#define ARIZONA_MIC_BIAS_CTRL_2                  0x219
+#define ARIZONA_MIC_BIAS_CTRL_3                  0x21A
+#define ARIZONA_ACCESSORY_DETECT_MODE_1          0x293
+#define ARIZONA_HEADPHONE_DETECT_1               0x29B
+#define ARIZONA_HEADPHONE_DETECT_2               0x29C
+#define ARIZONA_MIC_DETECT_1                     0x2A3
+#define ARIZONA_MIC_DETECT_2                     0x2A4
+#define ARIZONA_MIC_DETECT_3                     0x2A5
+#define ARIZONA_MIC_NOISE_MIX_CONTROL_1          0x2C3
+#define ARIZONA_ISOLATION_CONTROL                0x2CB
+#define ARIZONA_JACK_DETECT_ANALOGUE             0x2D3
+#define ARIZONA_INPUT_ENABLES                    0x300
+#define ARIZONA_INPUT_ENABLES_STATUS             0x301
+#define ARIZONA_INPUT_RATE                       0x308
+#define ARIZONA_INPUT_VOLUME_RAMP                0x309
+#define ARIZONA_IN1L_CONTROL                     0x310
+#define ARIZONA_ADC_DIGITAL_VOLUME_1L            0x311
+#define ARIZONA_DMIC1L_CONTROL                   0x312
+#define ARIZONA_IN1R_CONTROL                     0x314
+#define ARIZONA_ADC_DIGITAL_VOLUME_1R            0x315
+#define ARIZONA_DMIC1R_CONTROL                   0x316
+#define ARIZONA_IN2L_CONTROL                     0x318
+#define ARIZONA_ADC_DIGITAL_VOLUME_2L            0x319
+#define ARIZONA_DMIC2L_CONTROL                   0x31A
+#define ARIZONA_IN2R_CONTROL                     0x31C
+#define ARIZONA_ADC_DIGITAL_VOLUME_2R            0x31D
+#define ARIZONA_DMIC2R_CONTROL                   0x31E
+#define ARIZONA_IN3L_CONTROL                     0x320
+#define ARIZONA_ADC_DIGITAL_VOLUME_3L            0x321
+#define ARIZONA_DMIC3L_CONTROL                   0x322
+#define ARIZONA_IN3R_CONTROL                     0x324
+#define ARIZONA_ADC_DIGITAL_VOLUME_3R            0x325
+#define ARIZONA_DMIC3R_CONTROL                   0x326
+#define ARIZONA_IN4L_CONTROL                     0x328
+#define ARIZONA_ADC_DIGITAL_VOLUME_4L            0x329
+#define ARIZONA_DMIC4L_CONTROL                   0x32A
+#define ARIZONA_ADC_DIGITAL_VOLUME_4R            0x32D
+#define ARIZONA_DMIC4R_CONTROL                   0x32E
+#define ARIZONA_OUTPUT_ENABLES_1                 0x400
+#define ARIZONA_OUTPUT_STATUS_1                  0x401
+#define ARIZONA_RAW_OUTPUT_STATUS_1              0x406
+#define ARIZONA_OUTPUT_RATE_1                    0x408
+#define ARIZONA_OUTPUT_VOLUME_RAMP               0x409
+#define ARIZONA_OUTPUT_PATH_CONFIG_1L            0x410
+#define ARIZONA_DAC_DIGITAL_VOLUME_1L            0x411
+#define ARIZONA_DAC_VOLUME_LIMIT_1L              0x412
+#define ARIZONA_NOISE_GATE_SELECT_1L             0x413
+#define ARIZONA_OUTPUT_PATH_CONFIG_1R            0x414
+#define ARIZONA_DAC_DIGITAL_VOLUME_1R            0x415
+#define ARIZONA_DAC_VOLUME_LIMIT_1R              0x416
+#define ARIZONA_NOISE_GATE_SELECT_1R             0x417
+#define ARIZONA_OUTPUT_PATH_CONFIG_2L            0x418
+#define ARIZONA_DAC_DIGITAL_VOLUME_2L            0x419
+#define ARIZONA_DAC_VOLUME_LIMIT_2L              0x41A
+#define ARIZONA_NOISE_GATE_SELECT_2L             0x41B
+#define ARIZONA_OUTPUT_PATH_CONFIG_2R            0x41C
+#define ARIZONA_DAC_DIGITAL_VOLUME_2R            0x41D
+#define ARIZONA_DAC_VOLUME_LIMIT_2R              0x41E
+#define ARIZONA_NOISE_GATE_SELECT_2R             0x41F
+#define ARIZONA_OUTPUT_PATH_CONFIG_3L            0x420
+#define ARIZONA_DAC_DIGITAL_VOLUME_3L            0x421
+#define ARIZONA_DAC_VOLUME_LIMIT_3L              0x422
+#define ARIZONA_NOISE_GATE_SELECT_3L             0x423
+#define ARIZONA_OUTPUT_PATH_CONFIG_3R            0x424
+#define ARIZONA_DAC_DIGITAL_VOLUME_3R            0x425
+#define ARIZONA_DAC_VOLUME_LIMIT_3R              0x426
+#define ARIZONA_NOISE_GATE_SELECT_3R             0x427
+#define ARIZONA_OUTPUT_PATH_CONFIG_4L            0x428
+#define ARIZONA_DAC_DIGITAL_VOLUME_4L            0x429
+#define ARIZONA_OUT_VOLUME_4L                    0x42A
+#define ARIZONA_NOISE_GATE_SELECT_4L             0x42B
+#define ARIZONA_OUTPUT_PATH_CONFIG_4R            0x42C
+#define ARIZONA_DAC_DIGITAL_VOLUME_4R            0x42D
+#define ARIZONA_OUT_VOLUME_4R                    0x42E
+#define ARIZONA_NOISE_GATE_SELECT_4R             0x42F
+#define ARIZONA_OUTPUT_PATH_CONFIG_5L            0x430
+#define ARIZONA_DAC_DIGITAL_VOLUME_5L            0x431
+#define ARIZONA_DAC_VOLUME_LIMIT_5L              0x432
+#define ARIZONA_NOISE_GATE_SELECT_5L             0x433
+#define ARIZONA_OUTPUT_PATH_CONFIG_5R            0x434
+#define ARIZONA_DAC_DIGITAL_VOLUME_5R            0x435
+#define ARIZONA_DAC_VOLUME_LIMIT_5R              0x436
+#define ARIZONA_NOISE_GATE_SELECT_5R             0x437
+#define ARIZONA_OUTPUT_PATH_CONFIG_6L            0x438
+#define ARIZONA_DAC_DIGITAL_VOLUME_6L            0x439
+#define ARIZONA_DAC_VOLUME_LIMIT_6L              0x43A
+#define ARIZONA_NOISE_GATE_SELECT_6L             0x43B
+#define ARIZONA_OUTPUT_PATH_CONFIG_6R            0x43C
+#define ARIZONA_DAC_DIGITAL_VOLUME_6R            0x43D
+#define ARIZONA_DAC_VOLUME_LIMIT_6R              0x43E
+#define ARIZONA_NOISE_GATE_SELECT_6R             0x43F
+#define ARIZONA_DAC_AEC_CONTROL_1                0x450
+#define ARIZONA_NOISE_GATE_CONTROL               0x458
+#define ARIZONA_PDM_SPK1_CTRL_1                  0x490
+#define ARIZONA_PDM_SPK1_CTRL_2                  0x491
+#define ARIZONA_PDM_SPK2_CTRL_1                  0x492
+#define ARIZONA_PDM_SPK2_CTRL_2                  0x493
+#define ARIZONA_DAC_COMP_1                       0x4DC
+#define ARIZONA_DAC_COMP_2                       0x4DD
+#define ARIZONA_DAC_COMP_3                       0x4DE
+#define ARIZONA_DAC_COMP_4                       0x4DF
+#define ARIZONA_AIF1_BCLK_CTRL                   0x500
+#define ARIZONA_AIF1_TX_PIN_CTRL                 0x501
+#define ARIZONA_AIF1_RX_PIN_CTRL                 0x502
+#define ARIZONA_AIF1_RATE_CTRL                   0x503
+#define ARIZONA_AIF1_FORMAT                      0x504
+#define ARIZONA_AIF1_TX_BCLK_RATE                0x505
+#define ARIZONA_AIF1_RX_BCLK_RATE                0x506
+#define ARIZONA_AIF1_FRAME_CTRL_1                0x507
+#define ARIZONA_AIF1_FRAME_CTRL_2                0x508
+#define ARIZONA_AIF1_FRAME_CTRL_3                0x509
+#define ARIZONA_AIF1_FRAME_CTRL_4                0x50A
+#define ARIZONA_AIF1_FRAME_CTRL_5                0x50B
+#define ARIZONA_AIF1_FRAME_CTRL_6                0x50C
+#define ARIZONA_AIF1_FRAME_CTRL_7                0x50D
+#define ARIZONA_AIF1_FRAME_CTRL_8                0x50E
+#define ARIZONA_AIF1_FRAME_CTRL_9                0x50F
+#define ARIZONA_AIF1_FRAME_CTRL_10               0x510
+#define ARIZONA_AIF1_FRAME_CTRL_11               0x511
+#define ARIZONA_AIF1_FRAME_CTRL_12               0x512
+#define ARIZONA_AIF1_FRAME_CTRL_13               0x513
+#define ARIZONA_AIF1_FRAME_CTRL_14               0x514
+#define ARIZONA_AIF1_FRAME_CTRL_15               0x515
+#define ARIZONA_AIF1_FRAME_CTRL_16               0x516
+#define ARIZONA_AIF1_FRAME_CTRL_17               0x517
+#define ARIZONA_AIF1_FRAME_CTRL_18               0x518
+#define ARIZONA_AIF1_TX_ENABLES                  0x519
+#define ARIZONA_AIF1_RX_ENABLES                  0x51A
+#define ARIZONA_AIF1_FORCE_WRITE                 0x51B
+#define ARIZONA_AIF2_BCLK_CTRL                   0x540
+#define ARIZONA_AIF2_TX_PIN_CTRL                 0x541
+#define ARIZONA_AIF2_RX_PIN_CTRL                 0x542
+#define ARIZONA_AIF2_RATE_CTRL                   0x543
+#define ARIZONA_AIF2_FORMAT                      0x544
+#define ARIZONA_AIF2_TX_BCLK_RATE                0x545
+#define ARIZONA_AIF2_RX_BCLK_RATE                0x546
+#define ARIZONA_AIF2_FRAME_CTRL_1                0x547
+#define ARIZONA_AIF2_FRAME_CTRL_2                0x548
+#define ARIZONA_AIF2_FRAME_CTRL_3                0x549
+#define ARIZONA_AIF2_FRAME_CTRL_4                0x54A
+#define ARIZONA_AIF2_FRAME_CTRL_11               0x551
+#define ARIZONA_AIF2_FRAME_CTRL_12               0x552
+#define ARIZONA_AIF2_TX_ENABLES                  0x559
+#define ARIZONA_AIF2_RX_ENABLES                  0x55A
+#define ARIZONA_AIF2_FORCE_WRITE                 0x55B
+#define ARIZONA_AIF3_BCLK_CTRL                   0x580
+#define ARIZONA_AIF3_TX_PIN_CTRL                 0x581
+#define ARIZONA_AIF3_RX_PIN_CTRL                 0x582
+#define ARIZONA_AIF3_RATE_CTRL                   0x583
+#define ARIZONA_AIF3_FORMAT                      0x584
+#define ARIZONA_AIF3_TX_BCLK_RATE                0x585
+#define ARIZONA_AIF3_RX_BCLK_RATE                0x586
+#define ARIZONA_AIF3_FRAME_CTRL_1                0x587
+#define ARIZONA_AIF3_FRAME_CTRL_2                0x588
+#define ARIZONA_AIF3_FRAME_CTRL_3                0x589
+#define ARIZONA_AIF3_FRAME_CTRL_4                0x58A
+#define ARIZONA_AIF3_FRAME_CTRL_11               0x591
+#define ARIZONA_AIF3_FRAME_CTRL_12               0x592
+#define ARIZONA_AIF3_TX_ENABLES                  0x599
+#define ARIZONA_AIF3_RX_ENABLES                  0x59A
+#define ARIZONA_AIF3_FORCE_WRITE                 0x59B
+#define ARIZONA_SLIMBUS_FRAMER_REF_GEAR          0x5E3
+#define ARIZONA_SLIMBUS_RATES_1                  0x5E5
+#define ARIZONA_SLIMBUS_RATES_2                  0x5E6
+#define ARIZONA_SLIMBUS_RATES_3                  0x5E7
+#define ARIZONA_SLIMBUS_RATES_4                  0x5E8
+#define ARIZONA_SLIMBUS_RATES_5                  0x5E9
+#define ARIZONA_SLIMBUS_RATES_6                  0x5EA
+#define ARIZONA_SLIMBUS_RATES_7                  0x5EB
+#define ARIZONA_SLIMBUS_RATES_8                  0x5EC
+#define ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE        0x5F5
+#define ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE        0x5F6
+#define ARIZONA_SLIMBUS_RX_PORT_STATUS           0x5F7
+#define ARIZONA_SLIMBUS_TX_PORT_STATUS           0x5F8
+#define ARIZONA_PWM1MIX_INPUT_1_SOURCE           0x640
+#define ARIZONA_PWM1MIX_INPUT_1_VOLUME           0x641
+#define ARIZONA_PWM1MIX_INPUT_2_SOURCE           0x642
+#define ARIZONA_PWM1MIX_INPUT_2_VOLUME           0x643
+#define ARIZONA_PWM1MIX_INPUT_3_SOURCE           0x644
+#define ARIZONA_PWM1MIX_INPUT_3_VOLUME           0x645
+#define ARIZONA_PWM1MIX_INPUT_4_SOURCE           0x646
+#define ARIZONA_PWM1MIX_INPUT_4_VOLUME           0x647
+#define ARIZONA_PWM2MIX_INPUT_1_SOURCE           0x648
+#define ARIZONA_PWM2MIX_INPUT_1_VOLUME           0x649
+#define ARIZONA_PWM2MIX_INPUT_2_SOURCE           0x64A
+#define ARIZONA_PWM2MIX_INPUT_2_VOLUME           0x64B
+#define ARIZONA_PWM2MIX_INPUT_3_SOURCE           0x64C
+#define ARIZONA_PWM2MIX_INPUT_3_VOLUME           0x64D
+#define ARIZONA_PWM2MIX_INPUT_4_SOURCE           0x64E
+#define ARIZONA_PWM2MIX_INPUT_4_VOLUME           0x64F
+#define ARIZONA_MICMIX_INPUT_1_SOURCE            0x660
+#define ARIZONA_MICMIX_INPUT_1_VOLUME            0x661
+#define ARIZONA_MICMIX_INPUT_2_SOURCE            0x662
+#define ARIZONA_MICMIX_INPUT_2_VOLUME            0x663
+#define ARIZONA_MICMIX_INPUT_3_SOURCE            0x664
+#define ARIZONA_MICMIX_INPUT_3_VOLUME            0x665
+#define ARIZONA_MICMIX_INPUT_4_SOURCE            0x666
+#define ARIZONA_MICMIX_INPUT_4_VOLUME            0x667
+#define ARIZONA_NOISEMIX_INPUT_1_SOURCE          0x668
+#define ARIZONA_NOISEMIX_INPUT_1_VOLUME          0x669
+#define ARIZONA_NOISEMIX_INPUT_2_SOURCE          0x66A
+#define ARIZONA_NOISEMIX_INPUT_2_VOLUME          0x66B
+#define ARIZONA_NOISEMIX_INPUT_3_SOURCE          0x66C
+#define ARIZONA_NOISEMIX_INPUT_3_VOLUME          0x66D
+#define ARIZONA_NOISEMIX_INPUT_4_SOURCE          0x66E
+#define ARIZONA_NOISEMIX_INPUT_4_VOLUME          0x66F
+#define ARIZONA_OUT1LMIX_INPUT_1_SOURCE          0x680
+#define ARIZONA_OUT1LMIX_INPUT_1_VOLUME          0x681
+#define ARIZONA_OUT1LMIX_INPUT_2_SOURCE          0x682
+#define ARIZONA_OUT1LMIX_INPUT_2_VOLUME          0x683
+#define ARIZONA_OUT1LMIX_INPUT_3_SOURCE          0x684
+#define ARIZONA_OUT1LMIX_INPUT_3_VOLUME          0x685
+#define ARIZONA_OUT1LMIX_INPUT_4_SOURCE          0x686
+#define ARIZONA_OUT1LMIX_INPUT_4_VOLUME          0x687
+#define ARIZONA_OUT1RMIX_INPUT_1_SOURCE          0x688
+#define ARIZONA_OUT1RMIX_INPUT_1_VOLUME          0x689
+#define ARIZONA_OUT1RMIX_INPUT_2_SOURCE          0x68A
+#define ARIZONA_OUT1RMIX_INPUT_2_VOLUME          0x68B
+#define ARIZONA_OUT1RMIX_INPUT_3_SOURCE          0x68C
+#define ARIZONA_OUT1RMIX_INPUT_3_VOLUME          0x68D
+#define ARIZONA_OUT1RMIX_INPUT_4_SOURCE          0x68E
+#define ARIZONA_OUT1RMIX_INPUT_4_VOLUME          0x68F
+#define ARIZONA_OUT2LMIX_INPUT_1_SOURCE          0x690
+#define ARIZONA_OUT2LMIX_INPUT_1_VOLUME          0x691
+#define ARIZONA_OUT2LMIX_INPUT_2_SOURCE          0x692
+#define ARIZONA_OUT2LMIX_INPUT_2_VOLUME          0x693
+#define ARIZONA_OUT2LMIX_INPUT_3_SOURCE          0x694
+#define ARIZONA_OUT2LMIX_INPUT_3_VOLUME          0x695
+#define ARIZONA_OUT2LMIX_INPUT_4_SOURCE          0x696
+#define ARIZONA_OUT2LMIX_INPUT_4_VOLUME          0x697
+#define ARIZONA_OUT2RMIX_INPUT_1_SOURCE          0x698
+#define ARIZONA_OUT2RMIX_INPUT_1_VOLUME          0x699
+#define ARIZONA_OUT2RMIX_INPUT_2_SOURCE          0x69A
+#define ARIZONA_OUT2RMIX_INPUT_2_VOLUME          0x69B
+#define ARIZONA_OUT2RMIX_INPUT_3_SOURCE          0x69C
+#define ARIZONA_OUT2RMIX_INPUT_3_VOLUME          0x69D
+#define ARIZONA_OUT2RMIX_INPUT_4_SOURCE          0x69E
+#define ARIZONA_OUT2RMIX_INPUT_4_VOLUME          0x69F
+#define ARIZONA_OUT3LMIX_INPUT_1_SOURCE          0x6A0
+#define ARIZONA_OUT3LMIX_INPUT_1_VOLUME          0x6A1
+#define ARIZONA_OUT3LMIX_INPUT_2_SOURCE          0x6A2
+#define ARIZONA_OUT3LMIX_INPUT_2_VOLUME          0x6A3
+#define ARIZONA_OUT3LMIX_INPUT_3_SOURCE          0x6A4
+#define ARIZONA_OUT3LMIX_INPUT_3_VOLUME          0x6A5
+#define ARIZONA_OUT3LMIX_INPUT_4_SOURCE          0x6A6
+#define ARIZONA_OUT3LMIX_INPUT_4_VOLUME          0x6A7
+#define ARIZONA_OUT3RMIX_INPUT_1_SOURCE          0x6A8
+#define ARIZONA_OUT3RMIX_INPUT_1_VOLUME          0x6A9
+#define ARIZONA_OUT3RMIX_INPUT_2_SOURCE          0x6AA
+#define ARIZONA_OUT3RMIX_INPUT_2_VOLUME          0x6AB
+#define ARIZONA_OUT3RMIX_INPUT_3_SOURCE          0x6AC
+#define ARIZONA_OUT3RMIX_INPUT_3_VOLUME          0x6AD
+#define ARIZONA_OUT3RMIX_INPUT_4_SOURCE          0x6AE
+#define ARIZONA_OUT3RMIX_INPUT_4_VOLUME          0x6AF
+#define ARIZONA_OUT4LMIX_INPUT_1_SOURCE          0x6B0
+#define ARIZONA_OUT4LMIX_INPUT_1_VOLUME          0x6B1
+#define ARIZONA_OUT4LMIX_INPUT_2_SOURCE          0x6B2
+#define ARIZONA_OUT4LMIX_INPUT_2_VOLUME          0x6B3
+#define ARIZONA_OUT4LMIX_INPUT_3_SOURCE          0x6B4
+#define ARIZONA_OUT4LMIX_INPUT_3_VOLUME          0x6B5
+#define ARIZONA_OUT4LMIX_INPUT_4_SOURCE          0x6B6
+#define ARIZONA_OUT4LMIX_INPUT_4_VOLUME          0x6B7
+#define ARIZONA_OUT4RMIX_INPUT_1_SOURCE          0x6B8
+#define ARIZONA_OUT4RMIX_INPUT_1_VOLUME          0x6B9
+#define ARIZONA_OUT4RMIX_INPUT_2_SOURCE          0x6BA
+#define ARIZONA_OUT4RMIX_INPUT_2_VOLUME          0x6BB
+#define ARIZONA_OUT4RMIX_INPUT_3_SOURCE          0x6BC
+#define ARIZONA_OUT4RMIX_INPUT_3_VOLUME          0x6BD
+#define ARIZONA_OUT4RMIX_INPUT_4_SOURCE          0x6BE
+#define ARIZONA_OUT4RMIX_INPUT_4_VOLUME          0x6BF
+#define ARIZONA_OUT5LMIX_INPUT_1_SOURCE          0x6C0
+#define ARIZONA_OUT5LMIX_INPUT_1_VOLUME          0x6C1
+#define ARIZONA_OUT5LMIX_INPUT_2_SOURCE          0x6C2
+#define ARIZONA_OUT5LMIX_INPUT_2_VOLUME          0x6C3
+#define ARIZONA_OUT5LMIX_INPUT_3_SOURCE          0x6C4
+#define ARIZONA_OUT5LMIX_INPUT_3_VOLUME          0x6C5
+#define ARIZONA_OUT5LMIX_INPUT_4_SOURCE          0x6C6
+#define ARIZONA_OUT5LMIX_INPUT_4_VOLUME          0x6C7
+#define ARIZONA_OUT5RMIX_INPUT_1_SOURCE          0x6C8
+#define ARIZONA_OUT5RMIX_INPUT_1_VOLUME          0x6C9
+#define ARIZONA_OUT5RMIX_INPUT_2_SOURCE          0x6CA
+#define ARIZONA_OUT5RMIX_INPUT_2_VOLUME          0x6CB
+#define ARIZONA_OUT5RMIX_INPUT_3_SOURCE          0x6CC
+#define ARIZONA_OUT5RMIX_INPUT_3_VOLUME          0x6CD
+#define ARIZONA_OUT5RMIX_INPUT_4_SOURCE          0x6CE
+#define ARIZONA_OUT5RMIX_INPUT_4_VOLUME          0x6CF
+#define ARIZONA_OUT6LMIX_INPUT_1_SOURCE          0x6D0
+#define ARIZONA_OUT6LMIX_INPUT_1_VOLUME          0x6D1
+#define ARIZONA_OUT6LMIX_INPUT_2_SOURCE          0x6D2
+#define ARIZONA_OUT6LMIX_INPUT_2_VOLUME          0x6D3
+#define ARIZONA_OUT6LMIX_INPUT_3_SOURCE          0x6D4
+#define ARIZONA_OUT6LMIX_INPUT_3_VOLUME          0x6D5
+#define ARIZONA_OUT6LMIX_INPUT_4_SOURCE          0x6D6
+#define ARIZONA_OUT6LMIX_INPUT_4_VOLUME          0x6D7
+#define ARIZONA_OUT6RMIX_INPUT_1_SOURCE          0x6D8
+#define ARIZONA_OUT6RMIX_INPUT_1_VOLUME          0x6D9
+#define ARIZONA_OUT6RMIX_INPUT_2_SOURCE          0x6DA
+#define ARIZONA_OUT6RMIX_INPUT_2_VOLUME          0x6DB
+#define ARIZONA_OUT6RMIX_INPUT_3_SOURCE          0x6DC
+#define ARIZONA_OUT6RMIX_INPUT_3_VOLUME          0x6DD
+#define ARIZONA_OUT6RMIX_INPUT_4_SOURCE          0x6DE
+#define ARIZONA_OUT6RMIX_INPUT_4_VOLUME          0x6DF
+#define ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE        0x700
+#define ARIZONA_AIF1TX1MIX_INPUT_1_VOLUME        0x701
+#define ARIZONA_AIF1TX1MIX_INPUT_2_SOURCE        0x702
+#define ARIZONA_AIF1TX1MIX_INPUT_2_VOLUME        0x703
+#define ARIZONA_AIF1TX1MIX_INPUT_3_SOURCE        0x704
+#define ARIZONA_AIF1TX1MIX_INPUT_3_VOLUME        0x705
+#define ARIZONA_AIF1TX1MIX_INPUT_4_SOURCE        0x706
+#define ARIZONA_AIF1TX1MIX_INPUT_4_VOLUME        0x707
+#define ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE        0x708
+#define ARIZONA_AIF1TX2MIX_INPUT_1_VOLUME        0x709
+#define ARIZONA_AIF1TX2MIX_INPUT_2_SOURCE        0x70A
+#define ARIZONA_AIF1TX2MIX_INPUT_2_VOLUME        0x70B
+#define ARIZONA_AIF1TX2MIX_INPUT_3_SOURCE        0x70C
+#define ARIZONA_AIF1TX2MIX_INPUT_3_VOLUME        0x70D
+#define ARIZONA_AIF1TX2MIX_INPUT_4_SOURCE        0x70E
+#define ARIZONA_AIF1TX2MIX_INPUT_4_VOLUME        0x70F
+#define ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE        0x710
+#define ARIZONA_AIF1TX3MIX_INPUT_1_VOLUME        0x711
+#define ARIZONA_AIF1TX3MIX_INPUT_2_SOURCE        0x712
+#define ARIZONA_AIF1TX3MIX_INPUT_2_VOLUME        0x713
+#define ARIZONA_AIF1TX3MIX_INPUT_3_SOURCE        0x714
+#define ARIZONA_AIF1TX3MIX_INPUT_3_VOLUME        0x715
+#define ARIZONA_AIF1TX3MIX_INPUT_4_SOURCE        0x716
+#define ARIZONA_AIF1TX3MIX_INPUT_4_VOLUME        0x717
+#define ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE        0x718
+#define ARIZONA_AIF1TX4MIX_INPUT_1_VOLUME        0x719
+#define ARIZONA_AIF1TX4MIX_INPUT_2_SOURCE        0x71A
+#define ARIZONA_AIF1TX4MIX_INPUT_2_VOLUME        0x71B
+#define ARIZONA_AIF1TX4MIX_INPUT_3_SOURCE        0x71C
+#define ARIZONA_AIF1TX4MIX_INPUT_3_VOLUME        0x71D
+#define ARIZONA_AIF1TX4MIX_INPUT_4_SOURCE        0x71E
+#define ARIZONA_AIF1TX4MIX_INPUT_4_VOLUME        0x71F
+#define ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE        0x720
+#define ARIZONA_AIF1TX5MIX_INPUT_1_VOLUME        0x721
+#define ARIZONA_AIF1TX5MIX_INPUT_2_SOURCE        0x722
+#define ARIZONA_AIF1TX5MIX_INPUT_2_VOLUME        0x723
+#define ARIZONA_AIF1TX5MIX_INPUT_3_SOURCE        0x724
+#define ARIZONA_AIF1TX5MIX_INPUT_3_VOLUME        0x725
+#define ARIZONA_AIF1TX5MIX_INPUT_4_SOURCE        0x726
+#define ARIZONA_AIF1TX5MIX_INPUT_4_VOLUME        0x727
+#define ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE        0x728
+#define ARIZONA_AIF1TX6MIX_INPUT_1_VOLUME        0x729
+#define ARIZONA_AIF1TX6MIX_INPUT_2_SOURCE        0x72A
+#define ARIZONA_AIF1TX6MIX_INPUT_2_VOLUME        0x72B
+#define ARIZONA_AIF1TX6MIX_INPUT_3_SOURCE        0x72C
+#define ARIZONA_AIF1TX6MIX_INPUT_3_VOLUME        0x72D
+#define ARIZONA_AIF1TX6MIX_INPUT_4_SOURCE        0x72E
+#define ARIZONA_AIF1TX6MIX_INPUT_4_VOLUME        0x72F
+#define ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE        0x730
+#define ARIZONA_AIF1TX7MIX_INPUT_1_VOLUME        0x731
+#define ARIZONA_AIF1TX7MIX_INPUT_2_SOURCE        0x732
+#define ARIZONA_AIF1TX7MIX_INPUT_2_VOLUME        0x733
+#define ARIZONA_AIF1TX7MIX_INPUT_3_SOURCE        0x734
+#define ARIZONA_AIF1TX7MIX_INPUT_3_VOLUME        0x735
+#define ARIZONA_AIF1TX7MIX_INPUT_4_SOURCE        0x736
+#define ARIZONA_AIF1TX7MIX_INPUT_4_VOLUME        0x737
+#define ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE        0x738
+#define ARIZONA_AIF1TX8MIX_INPUT_1_VOLUME        0x739
+#define ARIZONA_AIF1TX8MIX_INPUT_2_SOURCE        0x73A
+#define ARIZONA_AIF1TX8MIX_INPUT_2_VOLUME        0x73B
+#define ARIZONA_AIF1TX8MIX_INPUT_3_SOURCE        0x73C
+#define ARIZONA_AIF1TX8MIX_INPUT_3_VOLUME        0x73D
+#define ARIZONA_AIF1TX8MIX_INPUT_4_SOURCE        0x73E
+#define ARIZONA_AIF1TX8MIX_INPUT_4_VOLUME        0x73F
+#define ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE        0x740
+#define ARIZONA_AIF2TX1MIX_INPUT_1_VOLUME        0x741
+#define ARIZONA_AIF2TX1MIX_INPUT_2_SOURCE        0x742
+#define ARIZONA_AIF2TX1MIX_INPUT_2_VOLUME        0x743
+#define ARIZONA_AIF2TX1MIX_INPUT_3_SOURCE        0x744
+#define ARIZONA_AIF2TX1MIX_INPUT_3_VOLUME        0x745
+#define ARIZONA_AIF2TX1MIX_INPUT_4_SOURCE        0x746
+#define ARIZONA_AIF2TX1MIX_INPUT_4_VOLUME        0x747
+#define ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE        0x748
+#define ARIZONA_AIF2TX2MIX_INPUT_1_VOLUME        0x749
+#define ARIZONA_AIF2TX2MIX_INPUT_2_SOURCE        0x74A
+#define ARIZONA_AIF2TX2MIX_INPUT_2_VOLUME        0x74B
+#define ARIZONA_AIF2TX2MIX_INPUT_3_SOURCE        0x74C
+#define ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME        0x74D
+#define ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE        0x74E
+#define ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME        0x74F
+#define ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE        0x780
+#define ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME        0x781
+#define ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE        0x782
+#define ARIZONA_AIF3TX1MIX_INPUT_2_VOLUME        0x783
+#define ARIZONA_AIF3TX1MIX_INPUT_3_SOURCE        0x784
+#define ARIZONA_AIF3TX1MIX_INPUT_3_VOLUME        0x785
+#define ARIZONA_AIF3TX1MIX_INPUT_4_SOURCE        0x786
+#define ARIZONA_AIF3TX1MIX_INPUT_4_VOLUME        0x787
+#define ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE        0x788
+#define ARIZONA_AIF3TX2MIX_INPUT_1_VOLUME        0x789
+#define ARIZONA_AIF3TX2MIX_INPUT_2_SOURCE        0x78A
+#define ARIZONA_AIF3TX2MIX_INPUT_2_VOLUME        0x78B
+#define ARIZONA_AIF3TX2MIX_INPUT_3_SOURCE        0x78C
+#define ARIZONA_AIF3TX2MIX_INPUT_3_VOLUME        0x78D
+#define ARIZONA_AIF3TX2MIX_INPUT_4_SOURCE        0x78E
+#define ARIZONA_AIF3TX2MIX_INPUT_4_VOLUME        0x78F
+#define ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE        0x7C0
+#define ARIZONA_SLIMTX1MIX_INPUT_1_VOLUME        0x7C1
+#define ARIZONA_SLIMTX1MIX_INPUT_2_SOURCE        0x7C2
+#define ARIZONA_SLIMTX1MIX_INPUT_2_VOLUME        0x7C3
+#define ARIZONA_SLIMTX1MIX_INPUT_3_SOURCE        0x7C4
+#define ARIZONA_SLIMTX1MIX_INPUT_3_VOLUME        0x7C5
+#define ARIZONA_SLIMTX1MIX_INPUT_4_SOURCE        0x7C6
+#define ARIZONA_SLIMTX1MIX_INPUT_4_VOLUME        0x7C7
+#define ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE        0x7C8
+#define ARIZONA_SLIMTX2MIX_INPUT_1_VOLUME        0x7C9
+#define ARIZONA_SLIMTX2MIX_INPUT_2_SOURCE        0x7CA
+#define ARIZONA_SLIMTX2MIX_INPUT_2_VOLUME        0x7CB
+#define ARIZONA_SLIMTX2MIX_INPUT_3_SOURCE        0x7CC
+#define ARIZONA_SLIMTX2MIX_INPUT_3_VOLUME        0x7CD
+#define ARIZONA_SLIMTX2MIX_INPUT_4_SOURCE        0x7CE
+#define ARIZONA_SLIMTX2MIX_INPUT_4_VOLUME        0x7CF
+#define ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE        0x7D0
+#define ARIZONA_SLIMTX3MIX_INPUT_1_VOLUME        0x7D1
+#define ARIZONA_SLIMTX3MIX_INPUT_2_SOURCE        0x7D2
+#define ARIZONA_SLIMTX3MIX_INPUT_2_VOLUME        0x7D3
+#define ARIZONA_SLIMTX3MIX_INPUT_3_SOURCE        0x7D4
+#define ARIZONA_SLIMTX3MIX_INPUT_3_VOLUME        0x7D5
+#define ARIZONA_SLIMTX3MIX_INPUT_4_SOURCE        0x7D6
+#define ARIZONA_SLIMTX3MIX_INPUT_4_VOLUME        0x7D7
+#define ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE        0x7D8
+#define ARIZONA_SLIMTX4MIX_INPUT_1_VOLUME        0x7D9
+#define ARIZONA_SLIMTX4MIX_INPUT_2_SOURCE        0x7DA
+#define ARIZONA_SLIMTX4MIX_INPUT_2_VOLUME        0x7DB
+#define ARIZONA_SLIMTX4MIX_INPUT_3_SOURCE        0x7DC
+#define ARIZONA_SLIMTX4MIX_INPUT_3_VOLUME        0x7DD
+#define ARIZONA_SLIMTX4MIX_INPUT_4_SOURCE        0x7DE
+#define ARIZONA_SLIMTX4MIX_INPUT_4_VOLUME        0x7DF
+#define ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE        0x7E0
+#define ARIZONA_SLIMTX5MIX_INPUT_1_VOLUME        0x7E1
+#define ARIZONA_SLIMTX5MIX_INPUT_2_SOURCE        0x7E2
+#define ARIZONA_SLIMTX5MIX_INPUT_2_VOLUME        0x7E3
+#define ARIZONA_SLIMTX5MIX_INPUT_3_SOURCE        0x7E4
+#define ARIZONA_SLIMTX5MIX_INPUT_3_VOLUME        0x7E5
+#define ARIZONA_SLIMTX5MIX_INPUT_4_SOURCE        0x7E6
+#define ARIZONA_SLIMTX5MIX_INPUT_4_VOLUME        0x7E7
+#define ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE        0x7E8
+#define ARIZONA_SLIMTX6MIX_INPUT_1_VOLUME        0x7E9
+#define ARIZONA_SLIMTX6MIX_INPUT_2_SOURCE        0x7EA
+#define ARIZONA_SLIMTX6MIX_INPUT_2_VOLUME        0x7EB
+#define ARIZONA_SLIMTX6MIX_INPUT_3_SOURCE        0x7EC
+#define ARIZONA_SLIMTX6MIX_INPUT_3_VOLUME        0x7ED
+#define ARIZONA_SLIMTX6MIX_INPUT_4_SOURCE        0x7EE
+#define ARIZONA_SLIMTX6MIX_INPUT_4_VOLUME        0x7EF
+#define ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE        0x7F0
+#define ARIZONA_SLIMTX7MIX_INPUT_1_VOLUME        0x7F1
+#define ARIZONA_SLIMTX7MIX_INPUT_2_SOURCE        0x7F2
+#define ARIZONA_SLIMTX7MIX_INPUT_2_VOLUME        0x7F3
+#define ARIZONA_SLIMTX7MIX_INPUT_3_SOURCE        0x7F4
+#define ARIZONA_SLIMTX7MIX_INPUT_3_VOLUME        0x7F5
+#define ARIZONA_SLIMTX7MIX_INPUT_4_SOURCE        0x7F6
+#define ARIZONA_SLIMTX7MIX_INPUT_4_VOLUME        0x7F7
+#define ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE        0x7F8
+#define ARIZONA_SLIMTX8MIX_INPUT_1_VOLUME        0x7F9
+#define ARIZONA_SLIMTX8MIX_INPUT_2_SOURCE        0x7FA
+#define ARIZONA_SLIMTX8MIX_INPUT_2_VOLUME        0x7FB
+#define ARIZONA_SLIMTX8MIX_INPUT_3_SOURCE        0x7FC
+#define ARIZONA_SLIMTX8MIX_INPUT_3_VOLUME        0x7FD
+#define ARIZONA_SLIMTX8MIX_INPUT_4_SOURCE        0x7FE
+#define ARIZONA_SLIMTX8MIX_INPUT_4_VOLUME        0x7FF
+#define ARIZONA_EQ1MIX_INPUT_1_SOURCE            0x880
+#define ARIZONA_EQ1MIX_INPUT_1_VOLUME            0x881
+#define ARIZONA_EQ1MIX_INPUT_2_SOURCE            0x882
+#define ARIZONA_EQ1MIX_INPUT_2_VOLUME            0x883
+#define ARIZONA_EQ1MIX_INPUT_3_SOURCE            0x884
+#define ARIZONA_EQ1MIX_INPUT_3_VOLUME            0x885
+#define ARIZONA_EQ1MIX_INPUT_4_SOURCE            0x886
+#define ARIZONA_EQ1MIX_INPUT_4_VOLUME            0x887
+#define ARIZONA_EQ2MIX_INPUT_1_SOURCE            0x888
+#define ARIZONA_EQ2MIX_INPUT_1_VOLUME            0x889
+#define ARIZONA_EQ2MIX_INPUT_2_SOURCE            0x88A
+#define ARIZONA_EQ2MIX_INPUT_2_VOLUME            0x88B
+#define ARIZONA_EQ2MIX_INPUT_3_SOURCE            0x88C
+#define ARIZONA_EQ2MIX_INPUT_3_VOLUME            0x88D
+#define ARIZONA_EQ2MIX_INPUT_4_SOURCE            0x88E
+#define ARIZONA_EQ2MIX_INPUT_4_VOLUME            0x88F
+#define ARIZONA_EQ3MIX_INPUT_1_SOURCE            0x890
+#define ARIZONA_EQ3MIX_INPUT_1_VOLUME            0x891
+#define ARIZONA_EQ3MIX_INPUT_2_SOURCE            0x892
+#define ARIZONA_EQ3MIX_INPUT_2_VOLUME            0x893
+#define ARIZONA_EQ3MIX_INPUT_3_SOURCE            0x894
+#define ARIZONA_EQ3MIX_INPUT_3_VOLUME            0x895
+#define ARIZONA_EQ3MIX_INPUT_4_SOURCE            0x896
+#define ARIZONA_EQ3MIX_INPUT_4_VOLUME            0x897
+#define ARIZONA_EQ4MIX_INPUT_1_SOURCE            0x898
+#define ARIZONA_EQ4MIX_INPUT_1_VOLUME            0x899
+#define ARIZONA_EQ4MIX_INPUT_2_SOURCE            0x89A
+#define ARIZONA_EQ4MIX_INPUT_2_VOLUME            0x89B
+#define ARIZONA_EQ4MIX_INPUT_3_SOURCE            0x89C
+#define ARIZONA_EQ4MIX_INPUT_3_VOLUME            0x89D
+#define ARIZONA_EQ4MIX_INPUT_4_SOURCE            0x89E
+#define ARIZONA_EQ4MIX_INPUT_4_VOLUME            0x89F
+#define ARIZONA_DRC1LMIX_INPUT_1_SOURCE          0x8C0
+#define ARIZONA_DRC1LMIX_INPUT_1_VOLUME          0x8C1
+#define ARIZONA_DRC1LMIX_INPUT_2_SOURCE          0x8C2
+#define ARIZONA_DRC1LMIX_INPUT_2_VOLUME          0x8C3
+#define ARIZONA_DRC1LMIX_INPUT_3_SOURCE          0x8C4
+#define ARIZONA_DRC1LMIX_INPUT_3_VOLUME          0x8C5
+#define ARIZONA_DRC1LMIX_INPUT_4_SOURCE          0x8C6
+#define ARIZONA_DRC1LMIX_INPUT_4_VOLUME          0x8C7
+#define ARIZONA_DRC1RMIX_INPUT_1_SOURCE          0x8C8
+#define ARIZONA_DRC1RMIX_INPUT_1_VOLUME          0x8C9
+#define ARIZONA_DRC1RMIX_INPUT_2_SOURCE          0x8CA
+#define ARIZONA_DRC1RMIX_INPUT_2_VOLUME          0x8CB
+#define ARIZONA_DRC1RMIX_INPUT_3_SOURCE          0x8CC
+#define ARIZONA_DRC1RMIX_INPUT_3_VOLUME          0x8CD
+#define ARIZONA_DRC1RMIX_INPUT_4_SOURCE          0x8CE
+#define ARIZONA_DRC1RMIX_INPUT_4_VOLUME          0x8CF
+#define ARIZONA_DRC2LMIX_INPUT_1_SOURCE          0x8D0
+#define ARIZONA_DRC2LMIX_INPUT_1_VOLUME          0x8D1
+#define ARIZONA_DRC2LMIX_INPUT_2_SOURCE          0x8D2
+#define ARIZONA_DRC2LMIX_INPUT_2_VOLUME          0x8D3
+#define ARIZONA_DRC2LMIX_INPUT_3_SOURCE          0x8D4
+#define ARIZONA_DRC2LMIX_INPUT_3_VOLUME          0x8D5
+#define ARIZONA_DRC2LMIX_INPUT_4_SOURCE          0x8D6
+#define ARIZONA_DRC2LMIX_INPUT_4_VOLUME          0x8D7
+#define ARIZONA_DRC2RMIX_INPUT_1_SOURCE          0x8D8
+#define ARIZONA_DRC2RMIX_INPUT_1_VOLUME          0x8D9
+#define ARIZONA_DRC2RMIX_INPUT_2_SOURCE          0x8DA
+#define ARIZONA_DRC2RMIX_INPUT_2_VOLUME          0x8DB
+#define ARIZONA_DRC2RMIX_INPUT_3_SOURCE          0x8DC
+#define ARIZONA_DRC2RMIX_INPUT_3_VOLUME          0x8DD
+#define ARIZONA_DRC2RMIX_INPUT_4_SOURCE          0x8DE
+#define ARIZONA_DRC2RMIX_INPUT_4_VOLUME          0x8DF
+#define ARIZONA_HPLP1MIX_INPUT_1_SOURCE          0x900
+#define ARIZONA_HPLP1MIX_INPUT_1_VOLUME          0x901
+#define ARIZONA_HPLP1MIX_INPUT_2_SOURCE          0x902
+#define ARIZONA_HPLP1MIX_INPUT_2_VOLUME          0x903
+#define ARIZONA_HPLP1MIX_INPUT_3_SOURCE          0x904
+#define ARIZONA_HPLP1MIX_INPUT_3_VOLUME          0x905
+#define ARIZONA_HPLP1MIX_INPUT_4_SOURCE          0x906
+#define ARIZONA_HPLP1MIX_INPUT_4_VOLUME          0x907
+#define ARIZONA_HPLP2MIX_INPUT_1_SOURCE          0x908
+#define ARIZONA_HPLP2MIX_INPUT_1_VOLUME          0x909
+#define ARIZONA_HPLP2MIX_INPUT_2_SOURCE          0x90A
+#define ARIZONA_HPLP2MIX_INPUT_2_VOLUME          0x90B
+#define ARIZONA_HPLP2MIX_INPUT_3_SOURCE          0x90C
+#define ARIZONA_HPLP2MIX_INPUT_3_VOLUME          0x90D
+#define ARIZONA_HPLP2MIX_INPUT_4_SOURCE          0x90E
+#define ARIZONA_HPLP2MIX_INPUT_4_VOLUME          0x90F
+#define ARIZONA_HPLP3MIX_INPUT_1_SOURCE          0x910
+#define ARIZONA_HPLP3MIX_INPUT_1_VOLUME          0x911
+#define ARIZONA_HPLP3MIX_INPUT_2_SOURCE          0x912
+#define ARIZONA_HPLP3MIX_INPUT_2_VOLUME          0x913
+#define ARIZONA_HPLP3MIX_INPUT_3_SOURCE          0x914
+#define ARIZONA_HPLP3MIX_INPUT_3_VOLUME          0x915
+#define ARIZONA_HPLP3MIX_INPUT_4_SOURCE          0x916
+#define ARIZONA_HPLP3MIX_INPUT_4_VOLUME          0x917
+#define ARIZONA_HPLP4MIX_INPUT_1_SOURCE          0x918
+#define ARIZONA_HPLP4MIX_INPUT_1_VOLUME          0x919
+#define ARIZONA_HPLP4MIX_INPUT_2_SOURCE          0x91A
+#define ARIZONA_HPLP4MIX_INPUT_2_VOLUME          0x91B
+#define ARIZONA_HPLP4MIX_INPUT_3_SOURCE          0x91C
+#define ARIZONA_HPLP4MIX_INPUT_3_VOLUME          0x91D
+#define ARIZONA_HPLP4MIX_INPUT_4_SOURCE          0x91E
+#define ARIZONA_HPLP4MIX_INPUT_4_VOLUME          0x91F
+#define ARIZONA_DSP1LMIX_INPUT_1_SOURCE          0x940
+#define ARIZONA_DSP1LMIX_INPUT_1_VOLUME          0x941
+#define ARIZONA_DSP1LMIX_INPUT_2_SOURCE          0x942
+#define ARIZONA_DSP1LMIX_INPUT_2_VOLUME          0x943
+#define ARIZONA_DSP1LMIX_INPUT_3_SOURCE          0x944
+#define ARIZONA_DSP1LMIX_INPUT_3_VOLUME          0x945
+#define ARIZONA_DSP1LMIX_INPUT_4_SOURCE          0x946
+#define ARIZONA_DSP1LMIX_INPUT_4_VOLUME          0x947
+#define ARIZONA_DSP1RMIX_INPUT_1_SOURCE          0x948
+#define ARIZONA_DSP1RMIX_INPUT_1_VOLUME          0x949
+#define ARIZONA_DSP1RMIX_INPUT_2_SOURCE          0x94A
+#define ARIZONA_DSP1RMIX_INPUT_2_VOLUME          0x94B
+#define ARIZONA_DSP1RMIX_INPUT_3_SOURCE          0x94C
+#define ARIZONA_DSP1RMIX_INPUT_3_VOLUME          0x94D
+#define ARIZONA_DSP1RMIX_INPUT_4_SOURCE          0x94E
+#define ARIZONA_DSP1RMIX_INPUT_4_VOLUME          0x94F
+#define ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE       0x950
+#define ARIZONA_DSP1AUX2MIX_INPUT_1_SOURCE       0x958
+#define ARIZONA_DSP1AUX3MIX_INPUT_1_SOURCE       0x960
+#define ARIZONA_DSP1AUX4MIX_INPUT_1_SOURCE       0x968
+#define ARIZONA_DSP1AUX5MIX_INPUT_1_SOURCE       0x970
+#define ARIZONA_DSP1AUX6MIX_INPUT_1_SOURCE       0x978
+#define ARIZONA_DSP2LMIX_INPUT_1_SOURCE          0x980
+#define ARIZONA_DSP2LMIX_INPUT_1_VOLUME          0x981
+#define ARIZONA_DSP2LMIX_INPUT_2_SOURCE          0x982
+#define ARIZONA_DSP2LMIX_INPUT_2_VOLUME          0x983
+#define ARIZONA_DSP2LMIX_INPUT_3_SOURCE          0x984
+#define ARIZONA_DSP2LMIX_INPUT_3_VOLUME          0x985
+#define ARIZONA_DSP2LMIX_INPUT_4_SOURCE          0x986
+#define ARIZONA_DSP2LMIX_INPUT_4_VOLUME          0x987
+#define ARIZONA_DSP2RMIX_INPUT_1_SOURCE          0x988
+#define ARIZONA_DSP2RMIX_INPUT_1_VOLUME          0x989
+#define ARIZONA_DSP2RMIX_INPUT_2_SOURCE          0x98A
+#define ARIZONA_DSP2RMIX_INPUT_2_VOLUME          0x98B
+#define ARIZONA_DSP2RMIX_INPUT_3_SOURCE          0x98C
+#define ARIZONA_DSP2RMIX_INPUT_3_VOLUME          0x98D
+#define ARIZONA_DSP2RMIX_INPUT_4_SOURCE          0x98E
+#define ARIZONA_DSP2RMIX_INPUT_4_VOLUME          0x98F
+#define ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE       0x990
+#define ARIZONA_DSP2AUX2MIX_INPUT_1_SOURCE       0x998
+#define ARIZONA_DSP2AUX3MIX_INPUT_1_SOURCE       0x9A0
+#define ARIZONA_DSP2AUX4MIX_INPUT_1_SOURCE       0x9A8
+#define ARIZONA_DSP2AUX5MIX_INPUT_1_SOURCE       0x9B0
+#define ARIZONA_DSP2AUX6MIX_INPUT_1_SOURCE       0x9B8
+#define ARIZONA_DSP3LMIX_INPUT_1_SOURCE          0x9C0
+#define ARIZONA_DSP3LMIX_INPUT_1_VOLUME          0x9C1
+#define ARIZONA_DSP3LMIX_INPUT_2_SOURCE          0x9C2
+#define ARIZONA_DSP3LMIX_INPUT_2_VOLUME          0x9C3
+#define ARIZONA_DSP3LMIX_INPUT_3_SOURCE          0x9C4
+#define ARIZONA_DSP3LMIX_INPUT_3_VOLUME          0x9C5
+#define ARIZONA_DSP3LMIX_INPUT_4_SOURCE          0x9C6
+#define ARIZONA_DSP3LMIX_INPUT_4_VOLUME          0x9C7
+#define ARIZONA_DSP3RMIX_INPUT_1_SOURCE          0x9C8
+#define ARIZONA_DSP3RMIX_INPUT_1_VOLUME          0x9C9
+#define ARIZONA_DSP3RMIX_INPUT_2_SOURCE          0x9CA
+#define ARIZONA_DSP3RMIX_INPUT_2_VOLUME          0x9CB
+#define ARIZONA_DSP3RMIX_INPUT_3_SOURCE          0x9CC
+#define ARIZONA_DSP3RMIX_INPUT_3_VOLUME          0x9CD
+#define ARIZONA_DSP3RMIX_INPUT_4_SOURCE          0x9CE
+#define ARIZONA_DSP3RMIX_INPUT_4_VOLUME          0x9CF
+#define ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE       0x9D0
+#define ARIZONA_DSP3AUX2MIX_INPUT_1_SOURCE       0x9D8
+#define ARIZONA_DSP3AUX3MIX_INPUT_1_SOURCE       0x9E0
+#define ARIZONA_DSP3AUX4MIX_INPUT_1_SOURCE       0x9E8
+#define ARIZONA_DSP3AUX5MIX_INPUT_1_SOURCE       0x9F0
+#define ARIZONA_DSP3AUX6MIX_INPUT_1_SOURCE       0x9F8
+#define ARIZONA_DSP4LMIX_INPUT_1_SOURCE          0xA00
+#define ARIZONA_DSP4LMIX_INPUT_1_VOLUME          0xA01
+#define ARIZONA_DSP4LMIX_INPUT_2_SOURCE          0xA02
+#define ARIZONA_DSP4LMIX_INPUT_2_VOLUME          0xA03
+#define ARIZONA_DSP4LMIX_INPUT_3_SOURCE          0xA04
+#define ARIZONA_DSP4LMIX_INPUT_3_VOLUME          0xA05
+#define ARIZONA_DSP4LMIX_INPUT_4_SOURCE          0xA06
+#define ARIZONA_DSP4LMIX_INPUT_4_VOLUME          0xA07
+#define ARIZONA_DSP4RMIX_INPUT_1_SOURCE          0xA08
+#define ARIZONA_DSP4RMIX_INPUT_1_VOLUME          0xA09
+#define ARIZONA_DSP4RMIX_INPUT_2_SOURCE          0xA0A
+#define ARIZONA_DSP4RMIX_INPUT_2_VOLUME          0xA0B
+#define ARIZONA_DSP4RMIX_INPUT_3_SOURCE          0xA0C
+#define ARIZONA_DSP4RMIX_INPUT_3_VOLUME          0xA0D
+#define ARIZONA_DSP4RMIX_INPUT_4_SOURCE          0xA0E
+#define ARIZONA_DSP4RMIX_INPUT_4_VOLUME          0xA0F
+#define ARIZONA_DSP4AUX1MIX_INPUT_1_SOURCE       0xA10
+#define ARIZONA_DSP4AUX2MIX_INPUT_1_SOURCE       0xA18
+#define ARIZONA_DSP4AUX3MIX_INPUT_1_SOURCE       0xA20
+#define ARIZONA_DSP4AUX4MIX_INPUT_1_SOURCE       0xA28
+#define ARIZONA_DSP4AUX5MIX_INPUT_1_SOURCE       0xA30
+#define ARIZONA_DSP4AUX6MIX_INPUT_1_SOURCE       0xA38
+#define ARIZONA_ASRC1LMIX_INPUT_1_SOURCE         0xA80
+#define ARIZONA_ASRC1RMIX_INPUT_1_SOURCE         0xA88
+#define ARIZONA_ASRC2LMIX_INPUT_1_SOURCE         0xA90
+#define ARIZONA_ASRC2RMIX_INPUT_1_SOURCE         0xA98
+#define ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE      0xB00
+#define ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE      0xB08
+#define ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE      0xB10
+#define ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE      0xB18
+#define ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE      0xB20
+#define ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE      0xB28
+#define ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE      0xB30
+#define ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE      0xB38
+#define ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE      0xB40
+#define ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE      0xB48
+#define ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE      0xB60
+#define ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE      0xB68
+#define ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE      0xB30
+#define ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE      0xB38
+#define ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE      0xB40
+#define ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE      0xB48
+#define ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE      0xB50
+#define ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE      0xB58
+#define ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE      0xB60
+#define ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE      0xB68
+#define ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE      0xB70
+#define ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE      0xB78
+#define ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE      0xB80
+#define ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE      0xB88
+#define ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE      0xB90
+#define ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE      0xB98
+#define ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE      0xBA0
+#define ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE      0xBA8
+#define ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE      0xBB0
+#define ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE      0xBB8
+#define ARIZONA_GPIO1_CTRL                       0xC00
+#define ARIZONA_GPIO2_CTRL                       0xC01
+#define ARIZONA_GPIO3_CTRL                       0xC02
+#define ARIZONA_GPIO4_CTRL                       0xC03
+#define ARIZONA_GPIO5_CTRL                       0xC04
+#define ARIZONA_IRQ_CTRL_1                       0xC0F
+#define ARIZONA_GPIO_DEBOUNCE_CONFIG             0xC10
+#define ARIZONA_MISC_PAD_CTRL_1                  0xC20
+#define ARIZONA_MISC_PAD_CTRL_2                  0xC21
+#define ARIZONA_MISC_PAD_CTRL_3                  0xC22
+#define ARIZONA_MISC_PAD_CTRL_4                  0xC23
+#define ARIZONA_MISC_PAD_CTRL_5                  0xC24
+#define ARIZONA_MISC_PAD_CTRL_6                  0xC25
+#define ARIZONA_MISC_PAD_CTRL_7                  0xC30
+#define ARIZONA_MISC_PAD_CTRL_8                  0xC31
+#define ARIZONA_MISC_PAD_CTRL_9                  0xC32
+#define ARIZONA_MISC_PAD_CTRL_10                 0xC33
+#define ARIZONA_MISC_PAD_CTRL_11                 0xC34
+#define ARIZONA_MISC_PAD_CTRL_12                 0xC35
+#define ARIZONA_MISC_PAD_CTRL_13                 0xC36
+#define ARIZONA_MISC_PAD_CTRL_14                 0xC37
+#define ARIZONA_MISC_PAD_CTRL_15                 0xC38
+#define ARIZONA_MISC_PAD_CTRL_16                 0xC39
+#define ARIZONA_MISC_PAD_CTRL_17                 0xC3A
+#define ARIZONA_MISC_PAD_CTRL_18                 0xC3B
+#define ARIZONA_INTERRUPT_STATUS_1               0xD00
+#define ARIZONA_INTERRUPT_STATUS_2               0xD01
+#define ARIZONA_INTERRUPT_STATUS_3               0xD02
+#define ARIZONA_INTERRUPT_STATUS_4               0xD03
+#define ARIZONA_INTERRUPT_STATUS_5               0xD04
+#define ARIZONA_INTERRUPT_STATUS_1_MASK          0xD08
+#define ARIZONA_INTERRUPT_STATUS_2_MASK          0xD09
+#define ARIZONA_INTERRUPT_STATUS_3_MASK          0xD0A
+#define ARIZONA_INTERRUPT_STATUS_4_MASK          0xD0B
+#define ARIZONA_INTERRUPT_STATUS_5_MASK          0xD0C
+#define ARIZONA_INTERRUPT_CONTROL                0xD0F
+#define ARIZONA_IRQ2_STATUS_1                    0xD10
+#define ARIZONA_IRQ2_STATUS_2                    0xD11
+#define ARIZONA_IRQ2_STATUS_3                    0xD12
+#define ARIZONA_IRQ2_STATUS_4                    0xD13
+#define ARIZONA_IRQ2_STATUS_5                    0xD14
+#define ARIZONA_IRQ2_STATUS_1_MASK               0xD18
+#define ARIZONA_IRQ2_STATUS_2_MASK               0xD19
+#define ARIZONA_IRQ2_STATUS_3_MASK               0xD1A
+#define ARIZONA_IRQ2_STATUS_4_MASK               0xD1B
+#define ARIZONA_IRQ2_STATUS_5_MASK               0xD1C
+#define ARIZONA_IRQ2_CONTROL                     0xD1F
+#define ARIZONA_INTERRUPT_RAW_STATUS_2           0xD20
+#define ARIZONA_INTERRUPT_RAW_STATUS_3           0xD21
+#define ARIZONA_INTERRUPT_RAW_STATUS_4           0xD22
+#define ARIZONA_INTERRUPT_RAW_STATUS_5           0xD23
+#define ARIZONA_INTERRUPT_RAW_STATUS_6           0xD24
+#define ARIZONA_INTERRUPT_RAW_STATUS_7           0xD25
+#define ARIZONA_INTERRUPT_RAW_STATUS_8           0xD26
+#define ARIZONA_IRQ_PIN_STATUS                   0xD40
+#define ARIZONA_ADSP2_IRQ0                       0xD41
+#define ARIZONA_AOD_WKUP_AND_TRIG                0xD50
+#define ARIZONA_AOD_IRQ1                         0xD51
+#define ARIZONA_AOD_IRQ2                         0xD52
+#define ARIZONA_AOD_IRQ_MASK_IRQ1                0xD53
+#define ARIZONA_AOD_IRQ_MASK_IRQ2                0xD54
+#define ARIZONA_AOD_IRQ_RAW_STATUS               0xD55
+#define ARIZONA_JACK_DETECT_DEBOUNCE             0xD56
+#define ARIZONA_FX_CTRL1                         0xE00
+#define ARIZONA_FX_CTRL2                         0xE01
+#define ARIZONA_EQ1_1                            0xE10
+#define ARIZONA_EQ1_2                            0xE11
+#define ARIZONA_EQ1_3                            0xE12
+#define ARIZONA_EQ1_4                            0xE13
+#define ARIZONA_EQ1_5                            0xE14
+#define ARIZONA_EQ1_6                            0xE15
+#define ARIZONA_EQ1_7                            0xE16
+#define ARIZONA_EQ1_8                            0xE17
+#define ARIZONA_EQ1_9                            0xE18
+#define ARIZONA_EQ1_10                           0xE19
+#define ARIZONA_EQ1_11                           0xE1A
+#define ARIZONA_EQ1_12                           0xE1B
+#define ARIZONA_EQ1_13                           0xE1C
+#define ARIZONA_EQ1_14                           0xE1D
+#define ARIZONA_EQ1_15                           0xE1E
+#define ARIZONA_EQ1_16                           0xE1F
+#define ARIZONA_EQ1_17                           0xE20
+#define ARIZONA_EQ1_18                           0xE21
+#define ARIZONA_EQ1_19                           0xE22
+#define ARIZONA_EQ1_20                           0xE23
+#define ARIZONA_EQ1_21                           0xE24
+#define ARIZONA_EQ2_1                            0xE26
+#define ARIZONA_EQ2_2                            0xE27
+#define ARIZONA_EQ2_3                            0xE28
+#define ARIZONA_EQ2_4                            0xE29
+#define ARIZONA_EQ2_5                            0xE2A
+#define ARIZONA_EQ2_6                            0xE2B
+#define ARIZONA_EQ2_7                            0xE2C
+#define ARIZONA_EQ2_8                            0xE2D
+#define ARIZONA_EQ2_9                            0xE2E
+#define ARIZONA_EQ2_10                           0xE2F
+#define ARIZONA_EQ2_11                           0xE30
+#define ARIZONA_EQ2_12                           0xE31
+#define ARIZONA_EQ2_13                           0xE32
+#define ARIZONA_EQ2_14                           0xE33
+#define ARIZONA_EQ2_15                           0xE34
+#define ARIZONA_EQ2_16                           0xE35
+#define ARIZONA_EQ2_17                           0xE36
+#define ARIZONA_EQ2_18                           0xE37
+#define ARIZONA_EQ2_19                           0xE38
+#define ARIZONA_EQ2_20                           0xE39
+#define ARIZONA_EQ2_21                           0xE3A
+#define ARIZONA_EQ3_1                            0xE3C
+#define ARIZONA_EQ3_2                            0xE3D
+#define ARIZONA_EQ3_3                            0xE3E
+#define ARIZONA_EQ3_4                            0xE3F
+#define ARIZONA_EQ3_5                            0xE40
+#define ARIZONA_EQ3_6                            0xE41
+#define ARIZONA_EQ3_7                            0xE42
+#define ARIZONA_EQ3_8                            0xE43
+#define ARIZONA_EQ3_9                            0xE44
+#define ARIZONA_EQ3_10                           0xE45
+#define ARIZONA_EQ3_11                           0xE46
+#define ARIZONA_EQ3_12                           0xE47
+#define ARIZONA_EQ3_13                           0xE48
+#define ARIZONA_EQ3_14                           0xE49
+#define ARIZONA_EQ3_15                           0xE4A
+#define ARIZONA_EQ3_16                           0xE4B
+#define ARIZONA_EQ3_17                           0xE4C
+#define ARIZONA_EQ3_18                           0xE4D
+#define ARIZONA_EQ3_19                           0xE4E
+#define ARIZONA_EQ3_20                           0xE4F
+#define ARIZONA_EQ3_21                           0xE50
+#define ARIZONA_EQ4_1                            0xE52
+#define ARIZONA_EQ4_2                            0xE53
+#define ARIZONA_EQ4_3                            0xE54
+#define ARIZONA_EQ4_4                            0xE55
+#define ARIZONA_EQ4_5                            0xE56
+#define ARIZONA_EQ4_6                            0xE57
+#define ARIZONA_EQ4_7                            0xE58
+#define ARIZONA_EQ4_8                            0xE59
+#define ARIZONA_EQ4_9                            0xE5A
+#define ARIZONA_EQ4_10                           0xE5B
+#define ARIZONA_EQ4_11                           0xE5C
+#define ARIZONA_EQ4_12                           0xE5D
+#define ARIZONA_EQ4_13                           0xE5E
+#define ARIZONA_EQ4_14                           0xE5F
+#define ARIZONA_EQ4_15                           0xE60
+#define ARIZONA_EQ4_16                           0xE61
+#define ARIZONA_EQ4_17                           0xE62
+#define ARIZONA_EQ4_18                           0xE63
+#define ARIZONA_EQ4_19                           0xE64
+#define ARIZONA_EQ4_20                           0xE65
+#define ARIZONA_EQ4_21                           0xE66
+#define ARIZONA_DRC1_CTRL1                       0xE80
+#define ARIZONA_DRC1_CTRL2                       0xE81
+#define ARIZONA_DRC1_CTRL3                       0xE82
+#define ARIZONA_DRC1_CTRL4                       0xE83
+#define ARIZONA_DRC1_CTRL5                       0xE84
+#define ARIZONA_DRC2_CTRL1                       0xE89
+#define ARIZONA_DRC2_CTRL2                       0xE8A
+#define ARIZONA_DRC2_CTRL3                       0xE8B
+#define ARIZONA_DRC2_CTRL4                       0xE8C
+#define ARIZONA_DRC2_CTRL5                       0xE8D
+#define ARIZONA_HPLPF1_1                         0xEC0
+#define ARIZONA_HPLPF1_2                         0xEC1
+#define ARIZONA_HPLPF2_1                         0xEC4
+#define ARIZONA_HPLPF2_2                         0xEC5
+#define ARIZONA_HPLPF3_1                         0xEC8
+#define ARIZONA_HPLPF3_2                         0xEC9
+#define ARIZONA_HPLPF4_1                         0xECC
+#define ARIZONA_HPLPF4_2                         0xECD
+#define ARIZONA_ASRC_ENABLE                      0xEE0
+#define ARIZONA_ASRC_STATUS                      0xEE1
+#define ARIZONA_ASRC_RATE1                       0xEE2
+#define ARIZONA_ASRC_RATE2                       0xEE3
+#define ARIZONA_ISRC_1_CTRL_1                    0xEF0
+#define ARIZONA_ISRC_1_CTRL_2                    0xEF1
+#define ARIZONA_ISRC_1_CTRL_3                    0xEF2
+#define ARIZONA_ISRC_2_CTRL_1                    0xEF3
+#define ARIZONA_ISRC_2_CTRL_2                    0xEF4
+#define ARIZONA_ISRC_2_CTRL_3                    0xEF5
+#define ARIZONA_ISRC_3_CTRL_1                    0xEF6
+#define ARIZONA_ISRC_3_CTRL_2                    0xEF7
+#define ARIZONA_ISRC_3_CTRL_3                    0xEF8
+#define ARIZONA_CLOCK_CONTROL                    0xF00
+#define ARIZONA_ANC_SRC                          0xF01
+#define ARIZONA_DSP_STATUS                       0xF02
+#define ARIZONA_DSP1_CONTROL_1                   0x1100
+#define ARIZONA_DSP1_CLOCKING_1                  0x1101
+#define ARIZONA_DSP1_STATUS_1                    0x1104
+#define ARIZONA_DSP1_STATUS_2                    0x1105
+#define ARIZONA_DSP2_CONTROL_1                   0x1200
+#define ARIZONA_DSP2_CLOCKING_1                  0x1201
+#define ARIZONA_DSP2_STATUS_1                    0x1204
+#define ARIZONA_DSP2_STATUS_2                    0x1205
+#define ARIZONA_DSP3_CONTROL_1                   0x1300
+#define ARIZONA_DSP3_CLOCKING_1                  0x1301
+#define ARIZONA_DSP3_STATUS_1                    0x1304
+#define ARIZONA_DSP3_STATUS_2                    0x1305
+#define ARIZONA_DSP4_CONTROL_1                   0x1400
+#define ARIZONA_DSP4_CLOCKING_1                  0x1401
+#define ARIZONA_DSP4_STATUS_1                    0x1404
+#define ARIZONA_DSP4_STATUS_2                    0x1405
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - software reset
+ */
+#define ARIZONA_SW_RST_DEV_ID1_MASK              0xFFFF  /* SW_RST_DEV_ID1 - [15:0] */
+#define ARIZONA_SW_RST_DEV_ID1_SHIFT                  0  /* SW_RST_DEV_ID1 - [15:0] */
+#define ARIZONA_SW_RST_DEV_ID1_WIDTH                 16  /* SW_RST_DEV_ID1 - [15:0] */
+
+/*
+ * R1 (0x01) - Device Revision
+ */
+#define ARIZONA_DEVICE_REVISION_MASK             0x00FF  /* DEVICE_REVISION - [7:0] */
+#define ARIZONA_DEVICE_REVISION_SHIFT                 0  /* DEVICE_REVISION - [7:0] */
+#define ARIZONA_DEVICE_REVISION_WIDTH                 8  /* DEVICE_REVISION - [7:0] */
+
+/*
+ * R8 (0x08) - Ctrl IF SPI CFG 1
+ */
+#define ARIZONA_SPI_CFG                          0x0010  /* SPI_CFG */
+#define ARIZONA_SPI_CFG_MASK                     0x0010  /* SPI_CFG */
+#define ARIZONA_SPI_CFG_SHIFT                         4  /* SPI_CFG */
+#define ARIZONA_SPI_CFG_WIDTH                         1  /* SPI_CFG */
+#define ARIZONA_SPI_4WIRE                        0x0008  /* SPI_4WIRE */
+#define ARIZONA_SPI_4WIRE_MASK                   0x0008  /* SPI_4WIRE */
+#define ARIZONA_SPI_4WIRE_SHIFT                       3  /* SPI_4WIRE */
+#define ARIZONA_SPI_4WIRE_WIDTH                       1  /* SPI_4WIRE */
+#define ARIZONA_SPI_AUTO_INC_MASK                0x0003  /* SPI_AUTO_INC - [1:0] */
+#define ARIZONA_SPI_AUTO_INC_SHIFT                    0  /* SPI_AUTO_INC - [1:0] */
+#define ARIZONA_SPI_AUTO_INC_WIDTH                    2  /* SPI_AUTO_INC - [1:0] */
+
+/*
+ * R9 (0x09) - Ctrl IF I2C1 CFG 1
+ */
+#define ARIZONA_I2C1_AUTO_INC_MASK               0x0003  /* I2C1_AUTO_INC - [1:0] */
+#define ARIZONA_I2C1_AUTO_INC_SHIFT                   0  /* I2C1_AUTO_INC - [1:0] */
+#define ARIZONA_I2C1_AUTO_INC_WIDTH                   2  /* I2C1_AUTO_INC - [1:0] */
+
+/*
+ * R13 (0x0D) - Ctrl IF Status 1
+ */
+#define ARIZONA_I2C1_BUSY                        0x0020  /* I2C1_BUSY */
+#define ARIZONA_I2C1_BUSY_MASK                   0x0020  /* I2C1_BUSY */
+#define ARIZONA_I2C1_BUSY_SHIFT                       5  /* I2C1_BUSY */
+#define ARIZONA_I2C1_BUSY_WIDTH                       1  /* I2C1_BUSY */
+#define ARIZONA_SPI_BUSY                         0x0010  /* SPI_BUSY */
+#define ARIZONA_SPI_BUSY_MASK                    0x0010  /* SPI_BUSY */
+#define ARIZONA_SPI_BUSY_SHIFT                        4  /* SPI_BUSY */
+#define ARIZONA_SPI_BUSY_WIDTH                        1  /* SPI_BUSY */
+
+/*
+ * R22 (0x16) - Write Sequencer Ctrl 0
+ */
+#define ARIZONA_WSEQ_ABORT                       0x0800  /* WSEQ_ABORT */
+#define ARIZONA_WSEQ_ABORT_MASK                  0x0800  /* WSEQ_ABORT */
+#define ARIZONA_WSEQ_ABORT_SHIFT                     11  /* WSEQ_ABORT */
+#define ARIZONA_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define ARIZONA_WSEQ_START                       0x0400  /* WSEQ_START */
+#define ARIZONA_WSEQ_START_MASK                  0x0400  /* WSEQ_START */
+#define ARIZONA_WSEQ_START_SHIFT                     10  /* WSEQ_START */
+#define ARIZONA_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define ARIZONA_WSEQ_ENA                         0x0200  /* WSEQ_ENA */
+#define ARIZONA_WSEQ_ENA_MASK                    0x0200  /* WSEQ_ENA */
+#define ARIZONA_WSEQ_ENA_SHIFT                        9  /* WSEQ_ENA */
+#define ARIZONA_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define ARIZONA_WSEQ_START_INDEX_MASK            0x01FF  /* WSEQ_START_INDEX - [8:0] */
+#define ARIZONA_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [8:0] */
+#define ARIZONA_WSEQ_START_INDEX_WIDTH                9  /* WSEQ_START_INDEX - [8:0] */
+
+/*
+ * R23 (0x17) - Write Sequencer Ctrl 1
+ */
+#define ARIZONA_WSEQ_BUSY                        0x0200  /* WSEQ_BUSY */
+#define ARIZONA_WSEQ_BUSY_MASK                   0x0200  /* WSEQ_BUSY */
+#define ARIZONA_WSEQ_BUSY_SHIFT                       9  /* WSEQ_BUSY */
+#define ARIZONA_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+#define ARIZONA_WSEQ_CURRENT_INDEX_MASK          0x01FF  /* WSEQ_CURRENT_INDEX - [8:0] */
+#define ARIZONA_WSEQ_CURRENT_INDEX_SHIFT              0  /* WSEQ_CURRENT_INDEX - [8:0] */
+#define ARIZONA_WSEQ_CURRENT_INDEX_WIDTH              9  /* WSEQ_CURRENT_INDEX - [8:0] */
+
+/*
+ * R24 (0x18) - Write Sequencer Ctrl 2
+ */
+#define ARIZONA_LOAD_DEFAULTS                    0x0002  /* LOAD_DEFAULTS */
+#define ARIZONA_LOAD_DEFAULTS_MASK               0x0002  /* LOAD_DEFAULTS */
+#define ARIZONA_LOAD_DEFAULTS_SHIFT                   1  /* LOAD_DEFAULTS */
+#define ARIZONA_LOAD_DEFAULTS_WIDTH                   1  /* LOAD_DEFAULTS */
+#define ARIZONA_WSEQ_LOAD_MEM                    0x0001  /* WSEQ_LOAD_MEM */
+#define ARIZONA_WSEQ_LOAD_MEM_MASK               0x0001  /* WSEQ_LOAD_MEM */
+#define ARIZONA_WSEQ_LOAD_MEM_SHIFT                   0  /* WSEQ_LOAD_MEM */
+#define ARIZONA_WSEQ_LOAD_MEM_WIDTH                   1  /* WSEQ_LOAD_MEM */
+
+/*
+ * R26 (0x1A) - Write Sequencer PROM
+ */
+#define ARIZONA_WSEQ_OTP_WRITE                   0x0001  /* WSEQ_OTP_WRITE */
+#define ARIZONA_WSEQ_OTP_WRITE_MASK              0x0001  /* WSEQ_OTP_WRITE */
+#define ARIZONA_WSEQ_OTP_WRITE_SHIFT                  0  /* WSEQ_OTP_WRITE */
+#define ARIZONA_WSEQ_OTP_WRITE_WIDTH                  1  /* WSEQ_OTP_WRITE */
+
+/*
+ * R32 (0x20) - Tone Generator 1
+ */
+#define ARIZONA_TONE_RATE_MASK                   0x7800  /* TONE_RATE - [14:11] */
+#define ARIZONA_TONE_RATE_SHIFT                      11  /* TONE_RATE - [14:11] */
+#define ARIZONA_TONE_RATE_WIDTH                       4  /* TONE_RATE - [14:11] */
+#define ARIZONA_TONE_OFFSET_MASK                 0x0300  /* TONE_OFFSET - [9:8] */
+#define ARIZONA_TONE_OFFSET_SHIFT                     8  /* TONE_OFFSET - [9:8] */
+#define ARIZONA_TONE_OFFSET_WIDTH                     2  /* TONE_OFFSET - [9:8] */
+#define ARIZONA_TONE2_OVD                        0x0020  /* TONE2_OVD */
+#define ARIZONA_TONE2_OVD_MASK                   0x0020  /* TONE2_OVD */
+#define ARIZONA_TONE2_OVD_SHIFT                       5  /* TONE2_OVD */
+#define ARIZONA_TONE2_OVD_WIDTH                       1  /* TONE2_OVD */
+#define ARIZONA_TONE1_OVD                        0x0010  /* TONE1_OVD */
+#define ARIZONA_TONE1_OVD_MASK                   0x0010  /* TONE1_OVD */
+#define ARIZONA_TONE1_OVD_SHIFT                       4  /* TONE1_OVD */
+#define ARIZONA_TONE1_OVD_WIDTH                       1  /* TONE1_OVD */
+#define ARIZONA_TONE2_ENA                        0x0002  /* TONE2_ENA */
+#define ARIZONA_TONE2_ENA_MASK                   0x0002  /* TONE2_ENA */
+#define ARIZONA_TONE2_ENA_SHIFT                       1  /* TONE2_ENA */
+#define ARIZONA_TONE2_ENA_WIDTH                       1  /* TONE2_ENA */
+#define ARIZONA_TONE1_ENA                        0x0001  /* TONE1_ENA */
+#define ARIZONA_TONE1_ENA_MASK                   0x0001  /* TONE1_ENA */
+#define ARIZONA_TONE1_ENA_SHIFT                       0  /* TONE1_ENA */
+#define ARIZONA_TONE1_ENA_WIDTH                       1  /* TONE1_ENA */
+
+/*
+ * R33 (0x21) - Tone Generator 2
+ */
+#define ARIZONA_TONE1_LVL_0_MASK                 0xFFFF  /* TONE1_LVL - [15:0] */
+#define ARIZONA_TONE1_LVL_0_SHIFT                     0  /* TONE1_LVL - [15:0] */
+#define ARIZONA_TONE1_LVL_0_WIDTH                    16  /* TONE1_LVL - [15:0] */
+
+/*
+ * R34 (0x22) - Tone Generator 3
+ */
+#define ARIZONA_TONE1_LVL_MASK                   0x00FF  /* TONE1_LVL - [7:0] */
+#define ARIZONA_TONE1_LVL_SHIFT                       0  /* TONE1_LVL - [7:0] */
+#define ARIZONA_TONE1_LVL_WIDTH                       8  /* TONE1_LVL - [7:0] */
+
+/*
+ * R35 (0x23) - Tone Generator 4
+ */
+#define ARIZONA_TONE2_LVL_0_MASK                 0xFFFF  /* TONE2_LVL - [15:0] */
+#define ARIZONA_TONE2_LVL_0_SHIFT                     0  /* TONE2_LVL - [15:0] */
+#define ARIZONA_TONE2_LVL_0_WIDTH                    16  /* TONE2_LVL - [15:0] */
+
+/*
+ * R36 (0x24) - Tone Generator 5
+ */
+#define ARIZONA_TONE2_LVL_MASK                   0x00FF  /* TONE2_LVL - [7:0] */
+#define ARIZONA_TONE2_LVL_SHIFT                       0  /* TONE2_LVL - [7:0] */
+#define ARIZONA_TONE2_LVL_WIDTH                       8  /* TONE2_LVL - [7:0] */
+
+/*
+ * R48 (0x30) - PWM Drive 1
+ */
+#define ARIZONA_PWM_RATE_MASK                    0x7800  /* PWM_RATE - [14:11] */
+#define ARIZONA_PWM_RATE_SHIFT                       11  /* PWM_RATE - [14:11] */
+#define ARIZONA_PWM_RATE_WIDTH                        4  /* PWM_RATE - [14:11] */
+#define ARIZONA_PWM_CLK_SEL_MASK                 0x0700  /* PWM_CLK_SEL - [10:8] */
+#define ARIZONA_PWM_CLK_SEL_SHIFT                     8  /* PWM_CLK_SEL - [10:8] */
+#define ARIZONA_PWM_CLK_SEL_WIDTH                     3  /* PWM_CLK_SEL - [10:8] */
+#define ARIZONA_PWM2_OVD                         0x0020  /* PWM2_OVD */
+#define ARIZONA_PWM2_OVD_MASK                    0x0020  /* PWM2_OVD */
+#define ARIZONA_PWM2_OVD_SHIFT                        5  /* PWM2_OVD */
+#define ARIZONA_PWM2_OVD_WIDTH                        1  /* PWM2_OVD */
+#define ARIZONA_PWM1_OVD                         0x0010  /* PWM1_OVD */
+#define ARIZONA_PWM1_OVD_MASK                    0x0010  /* PWM1_OVD */
+#define ARIZONA_PWM1_OVD_SHIFT                        4  /* PWM1_OVD */
+#define ARIZONA_PWM1_OVD_WIDTH                        1  /* PWM1_OVD */
+#define ARIZONA_PWM2_ENA                         0x0002  /* PWM2_ENA */
+#define ARIZONA_PWM2_ENA_MASK                    0x0002  /* PWM2_ENA */
+#define ARIZONA_PWM2_ENA_SHIFT                        1  /* PWM2_ENA */
+#define ARIZONA_PWM2_ENA_WIDTH                        1  /* PWM2_ENA */
+#define ARIZONA_PWM1_ENA                         0x0001  /* PWM1_ENA */
+#define ARIZONA_PWM1_ENA_MASK                    0x0001  /* PWM1_ENA */
+#define ARIZONA_PWM1_ENA_SHIFT                        0  /* PWM1_ENA */
+#define ARIZONA_PWM1_ENA_WIDTH                        1  /* PWM1_ENA */
+
+/*
+ * R49 (0x31) - PWM Drive 2
+ */
+#define ARIZONA_PWM1_LVL_MASK                    0x03FF  /* PWM1_LVL - [9:0] */
+#define ARIZONA_PWM1_LVL_SHIFT                        0  /* PWM1_LVL - [9:0] */
+#define ARIZONA_PWM1_LVL_WIDTH                       10  /* PWM1_LVL - [9:0] */
+
+/*
+ * R50 (0x32) - PWM Drive 3
+ */
+#define ARIZONA_PWM2_LVL_MASK                    0x03FF  /* PWM2_LVL - [9:0] */
+#define ARIZONA_PWM2_LVL_SHIFT                        0  /* PWM2_LVL - [9:0] */
+#define ARIZONA_PWM2_LVL_WIDTH                       10  /* PWM2_LVL - [9:0] */
+
+/*
+ * R64 (0x40) - Wake control
+ */
+#define ARIZONA_WKUP_GP5_FALL                    0x0020  /* WKUP_GP5_FALL */
+#define ARIZONA_WKUP_GP5_FALL_MASK               0x0020  /* WKUP_GP5_FALL */
+#define ARIZONA_WKUP_GP5_FALL_SHIFT                   5  /* WKUP_GP5_FALL */
+#define ARIZONA_WKUP_GP5_FALL_WIDTH                   1  /* WKUP_GP5_FALL */
+#define ARIZONA_WKUP_GP5_RISE                    0x0010  /* WKUP_GP5_RISE */
+#define ARIZONA_WKUP_GP5_RISE_MASK               0x0010  /* WKUP_GP5_RISE */
+#define ARIZONA_WKUP_GP5_RISE_SHIFT                   4  /* WKUP_GP5_RISE */
+#define ARIZONA_WKUP_GP5_RISE_WIDTH                   1  /* WKUP_GP5_RISE */
+#define ARIZONA_WKUP_JD1_FALL                    0x0008  /* WKUP_JD1_FALL */
+#define ARIZONA_WKUP_JD1_FALL_MASK               0x0008  /* WKUP_JD1_FALL */
+#define ARIZONA_WKUP_JD1_FALL_SHIFT                   3  /* WKUP_JD1_FALL */
+#define ARIZONA_WKUP_JD1_FALL_WIDTH                   1  /* WKUP_JD1_FALL */
+#define ARIZONA_WKUP_JD1_RISE                    0x0004  /* WKUP_JD1_RISE */
+#define ARIZONA_WKUP_JD1_RISE_MASK               0x0004  /* WKUP_JD1_RISE */
+#define ARIZONA_WKUP_JD1_RISE_SHIFT                   2  /* WKUP_JD1_RISE */
+#define ARIZONA_WKUP_JD1_RISE_WIDTH                   1  /* WKUP_JD1_RISE */
+#define ARIZONA_WKUP_JD2_FALL                    0x0002  /* WKUP_JD2_FALL */
+#define ARIZONA_WKUP_JD2_FALL_MASK               0x0002  /* WKUP_JD2_FALL */
+#define ARIZONA_WKUP_JD2_FALL_SHIFT                   1  /* WKUP_JD2_FALL */
+#define ARIZONA_WKUP_JD2_FALL_WIDTH                   1  /* WKUP_JD2_FALL */
+#define ARIZONA_WKUP_JD2_RISE                    0x0001  /* WKUP_JD2_RISE */
+#define ARIZONA_WKUP_JD2_RISE_MASK               0x0001  /* WKUP_JD2_RISE */
+#define ARIZONA_WKUP_JD2_RISE_SHIFT                   0  /* WKUP_JD2_RISE */
+#define ARIZONA_WKUP_JD2_RISE_WIDTH                   1  /* WKUP_JD2_RISE */
+
+/*
+ * R65 (0x41) - Sequence control
+ */
+#define ARIZONA_WSEQ_ENA_GP5_FALL                0x0020  /* WSEQ_ENA_GP5_FALL */
+#define ARIZONA_WSEQ_ENA_GP5_FALL_MASK           0x0020  /* WSEQ_ENA_GP5_FALL */
+#define ARIZONA_WSEQ_ENA_GP5_FALL_SHIFT               5  /* WSEQ_ENA_GP5_FALL */
+#define ARIZONA_WSEQ_ENA_GP5_FALL_WIDTH               1  /* WSEQ_ENA_GP5_FALL */
+#define ARIZONA_WSEQ_ENA_GP5_RISE                0x0010  /* WSEQ_ENA_GP5_RISE */
+#define ARIZONA_WSEQ_ENA_GP5_RISE_MASK           0x0010  /* WSEQ_ENA_GP5_RISE */
+#define ARIZONA_WSEQ_ENA_GP5_RISE_SHIFT               4  /* WSEQ_ENA_GP5_RISE */
+#define ARIZONA_WSEQ_ENA_GP5_RISE_WIDTH               1  /* WSEQ_ENA_GP5_RISE */
+#define ARIZONA_WSEQ_ENA_JD1_FALL                0x0008  /* WSEQ_ENA_JD1_FALL */
+#define ARIZONA_WSEQ_ENA_JD1_FALL_MASK           0x0008  /* WSEQ_ENA_JD1_FALL */
+#define ARIZONA_WSEQ_ENA_JD1_FALL_SHIFT               3  /* WSEQ_ENA_JD1_FALL */
+#define ARIZONA_WSEQ_ENA_JD1_FALL_WIDTH               1  /* WSEQ_ENA_JD1_FALL */
+#define ARIZONA_WSEQ_ENA_JD1_RISE                0x0004  /* WSEQ_ENA_JD1_RISE */
+#define ARIZONA_WSEQ_ENA_JD1_RISE_MASK           0x0004  /* WSEQ_ENA_JD1_RISE */
+#define ARIZONA_WSEQ_ENA_JD1_RISE_SHIFT               2  /* WSEQ_ENA_JD1_RISE */
+#define ARIZONA_WSEQ_ENA_JD1_RISE_WIDTH               1  /* WSEQ_ENA_JD1_RISE */
+#define ARIZONA_WSEQ_ENA_JD2_FALL                0x0002  /* WSEQ_ENA_JD2_FALL */
+#define ARIZONA_WSEQ_ENA_JD2_FALL_MASK           0x0002  /* WSEQ_ENA_JD2_FALL */
+#define ARIZONA_WSEQ_ENA_JD2_FALL_SHIFT               1  /* WSEQ_ENA_JD2_FALL */
+#define ARIZONA_WSEQ_ENA_JD2_FALL_WIDTH               1  /* WSEQ_ENA_JD2_FALL */
+#define ARIZONA_WSEQ_ENA_JD2_RISE                0x0001  /* WSEQ_ENA_JD2_RISE */
+#define ARIZONA_WSEQ_ENA_JD2_RISE_MASK           0x0001  /* WSEQ_ENA_JD2_RISE */
+#define ARIZONA_WSEQ_ENA_JD2_RISE_SHIFT               0  /* WSEQ_ENA_JD2_RISE */
+#define ARIZONA_WSEQ_ENA_JD2_RISE_WIDTH               1  /* WSEQ_ENA_JD2_RISE */
+
+/*
+ * R97 (0x61) - Sample Rate Sequence Select 1
+ */
+#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_A_SEQ_ADDR_MASK 0x01FF  /* WSEQ_SAMPLE_RATE_DETECT_A_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_A_SEQ_ADDR_SHIFT      0  /* WSEQ_SAMPLE_RATE_DETECT_A_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_A_SEQ_ADDR_WIDTH      9  /* WSEQ_SAMPLE_RATE_DETECT_A_SEQ_ADDR - [8:0] */
+
+/*
+ * R98 (0x62) - Sample Rate Sequence Select 2
+ */
+#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_B_SEQ_ADDR_MASK 0x01FF  /* WSEQ_SAMPLE_RATE_DETECT_B_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_B_SEQ_ADDR_SHIFT      0  /* WSEQ_SAMPLE_RATE_DETECT_B_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_B_SEQ_ADDR_WIDTH      9  /* WSEQ_SAMPLE_RATE_DETECT_B_SEQ_ADDR - [8:0] */
+
+/*
+ * R99 (0x63) - Sample Rate Sequence Select 3
+ */
+#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_C_SEQ_ADDR_MASK 0x01FF  /* WSEQ_SAMPLE_RATE_DETECT_C_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_C_SEQ_ADDR_SHIFT      0  /* WSEQ_SAMPLE_RATE_DETECT_C_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_C_SEQ_ADDR_WIDTH      9  /* WSEQ_SAMPLE_RATE_DETECT_C_SEQ_ADDR - [8:0] */
+
+/*
+ * R100 (0x64) - Sample Rate Sequence Select 4
+ */
+#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_D_SEQ_ADDR_MASK 0x01FF  /* WSEQ_SAMPLE_RATE_DETECT_D_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_D_SEQ_ADDR_SHIFT      0  /* WSEQ_SAMPLE_RATE_DETECT_D_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_SAMPLE_RATE_DETECT_D_SEQ_ADDR_WIDTH      9  /* WSEQ_SAMPLE_RATE_DETECT_D_SEQ_ADDR - [8:0] */
+
+/*
+ * R104 (0x68) - Always On Triggers Sequence Select 1
+ */
+#define ARIZONA_WSEQ_GP5_RISE_SEQ_ADDR_MASK      0x01FF  /* WSEQ_GP5_RISE_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_GP5_RISE_SEQ_ADDR_SHIFT          0  /* WSEQ_GP5_RISE_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_GP5_RISE_SEQ_ADDR_WIDTH          9  /* WSEQ_GP5_RISE_SEQ_ADDR - [8:0] */
+
+/*
+ * R105 (0x69) - Always On Triggers Sequence Select 2
+ */
+#define ARIZONA_WSEQ_GP5_FALL_SEQ_ADDR_MASK      0x01FF  /* WSEQ_GP5_FALL_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_GP5_FALL_SEQ_ADDR_SHIFT          0  /* WSEQ_GP5_FALL_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_GP5_FALL_SEQ_ADDR_WIDTH          9  /* WSEQ_GP5_FALL_SEQ_ADDR - [8:0] */
+
+/*
+ * R106 (0x6A) - Always On Triggers Sequence Select 3
+ */
+#define ARIZONA_WSEQ_JD1_RISE_SEQ_ADDR_MASK      0x01FF  /* WSEQ_JD1_RISE_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_JD1_RISE_SEQ_ADDR_SHIFT          0  /* WSEQ_JD1_RISE_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_JD1_RISE_SEQ_ADDR_WIDTH          9  /* WSEQ_JD1_RISE_SEQ_ADDR - [8:0] */
+
+/*
+ * R107 (0x6B) - Always On Triggers Sequence Select 4
+ */
+#define ARIZONA_WSEQ_JD1_FALL_SEQ_ADDR_MASK      0x01FF  /* WSEQ_JD1_FALL_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_JD1_FALL_SEQ_ADDR_SHIFT          0  /* WSEQ_JD1_FALL_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_JD1_FALL_SEQ_ADDR_WIDTH          9  /* WSEQ_JD1_FALL_SEQ_ADDR - [8:0] */
+
+/*
+ * R108 (0x6C) - Always On Triggers Sequence Select 5
+ */
+#define ARIZONA_WSEQ_JD2_RISE_SEQ_ADDR_MASK      0x01FF  /* WSEQ_JD2_RISE_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_JD2_RISE_SEQ_ADDR_SHIFT          0  /* WSEQ_JD2_RISE_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_JD2_RISE_SEQ_ADDR_WIDTH          9  /* WSEQ_JD2_RISE_SEQ_ADDR - [8:0] */
+
+/*
+ * R109 (0x6D) - Always On Triggers Sequence Select 6
+ */
+#define ARIZONA_WSEQ_JD2_FALL_SEQ_ADDR_MASK      0x01FF  /* WSEQ_JD2_FALL_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_JD2_FALL_SEQ_ADDR_SHIFT          0  /* WSEQ_JD2_FALL_SEQ_ADDR - [8:0] */
+#define ARIZONA_WSEQ_JD2_FALL_SEQ_ADDR_WIDTH          9  /* WSEQ_JD2_FALL_SEQ_ADDR - [8:0] */
+
+/*
+ * R112 (0x70) - Comfort Noise Generator
+ */
+#define ARIZONA_NOISE_GEN_RATE_MASK              0x7800  /* NOISE_GEN_RATE - [14:11] */
+#define ARIZONA_NOISE_GEN_RATE_SHIFT                 11  /* NOISE_GEN_RATE - [14:11] */
+#define ARIZONA_NOISE_GEN_RATE_WIDTH                  4  /* NOISE_GEN_RATE - [14:11] */
+#define ARIZONA_NOISE_GEN_ENA                    0x0020  /* NOISE_GEN_ENA */
+#define ARIZONA_NOISE_GEN_ENA_MASK               0x0020  /* NOISE_GEN_ENA */
+#define ARIZONA_NOISE_GEN_ENA_SHIFT                   5  /* NOISE_GEN_ENA */
+#define ARIZONA_NOISE_GEN_ENA_WIDTH                   1  /* NOISE_GEN_ENA */
+#define ARIZONA_NOISE_GEN_GAIN_MASK              0x001F  /* NOISE_GEN_GAIN - [4:0] */
+#define ARIZONA_NOISE_GEN_GAIN_SHIFT                  0  /* NOISE_GEN_GAIN - [4:0] */
+#define ARIZONA_NOISE_GEN_GAIN_WIDTH                  5  /* NOISE_GEN_GAIN - [4:0] */
+
+/*
+ * R144 (0x90) - Haptics Control 1
+ */
+#define ARIZONA_HAP_RATE_MASK                    0x7800  /* HAP_RATE - [14:11] */
+#define ARIZONA_HAP_RATE_SHIFT                       11  /* HAP_RATE - [14:11] */
+#define ARIZONA_HAP_RATE_WIDTH                        4  /* HAP_RATE - [14:11] */
+#define ARIZONA_ONESHOT_TRIG                     0x0010  /* ONESHOT_TRIG */
+#define ARIZONA_ONESHOT_TRIG_MASK                0x0010  /* ONESHOT_TRIG */
+#define ARIZONA_ONESHOT_TRIG_SHIFT                    4  /* ONESHOT_TRIG */
+#define ARIZONA_ONESHOT_TRIG_WIDTH                    1  /* ONESHOT_TRIG */
+#define ARIZONA_HAP_CTRL_MASK                    0x000C  /* HAP_CTRL - [3:2] */
+#define ARIZONA_HAP_CTRL_SHIFT                        2  /* HAP_CTRL - [3:2] */
+#define ARIZONA_HAP_CTRL_WIDTH                        2  /* HAP_CTRL - [3:2] */
+#define ARIZONA_HAP_ACT                          0x0002  /* HAP_ACT */
+#define ARIZONA_HAP_ACT_MASK                     0x0002  /* HAP_ACT */
+#define ARIZONA_HAP_ACT_SHIFT                         1  /* HAP_ACT */
+#define ARIZONA_HAP_ACT_WIDTH                         1  /* HAP_ACT */
+
+/*
+ * R145 (0x91) - Haptics Control 2
+ */
+#define ARIZONA_LRA_FREQ_MASK                    0x7FFF  /* LRA_FREQ - [14:0] */
+#define ARIZONA_LRA_FREQ_SHIFT                        0  /* LRA_FREQ - [14:0] */
+#define ARIZONA_LRA_FREQ_WIDTH                       15  /* LRA_FREQ - [14:0] */
+
+/*
+ * R146 (0x92) - Haptics phase 1 intensity
+ */
+#define ARIZONA_PHASE1_INTENSITY_MASK            0x00FF  /* PHASE1_INTENSITY - [7:0] */
+#define ARIZONA_PHASE1_INTENSITY_SHIFT                0  /* PHASE1_INTENSITY - [7:0] */
+#define ARIZONA_PHASE1_INTENSITY_WIDTH                8  /* PHASE1_INTENSITY - [7:0] */
+
+/*
+ * R147 (0x93) - Haptics phase 1 duration
+ */
+#define ARIZONA_PHASE1_DURATION_MASK             0x01FF  /* PHASE1_DURATION - [8:0] */
+#define ARIZONA_PHASE1_DURATION_SHIFT                 0  /* PHASE1_DURATION - [8:0] */
+#define ARIZONA_PHASE1_DURATION_WIDTH                 9  /* PHASE1_DURATION - [8:0] */
+
+/*
+ * R148 (0x94) - Haptics phase 2 intensity
+ */
+#define ARIZONA_PHASE2_INTENSITY_MASK            0x00FF  /* PHASE2_INTENSITY - [7:0] */
+#define ARIZONA_PHASE2_INTENSITY_SHIFT                0  /* PHASE2_INTENSITY - [7:0] */
+#define ARIZONA_PHASE2_INTENSITY_WIDTH                8  /* PHASE2_INTENSITY - [7:0] */
+
+/*
+ * R149 (0x95) - Haptics phase 2 duration
+ */
+#define ARIZONA_PHASE2_DURATION_MASK             0x07FF  /* PHASE2_DURATION - [10:0] */
+#define ARIZONA_PHASE2_DURATION_SHIFT                 0  /* PHASE2_DURATION - [10:0] */
+#define ARIZONA_PHASE2_DURATION_WIDTH                11  /* PHASE2_DURATION - [10:0] */
+
+/*
+ * R150 (0x96) - Haptics phase 3 intensity
+ */
+#define ARIZONA_PHASE3_INTENSITY_MASK            0x00FF  /* PHASE3_INTENSITY - [7:0] */
+#define ARIZONA_PHASE3_INTENSITY_SHIFT                0  /* PHASE3_INTENSITY - [7:0] */
+#define ARIZONA_PHASE3_INTENSITY_WIDTH                8  /* PHASE3_INTENSITY - [7:0] */
+
+/*
+ * R151 (0x97) - Haptics phase 3 duration
+ */
+#define ARIZONA_PHASE3_DURATION_MASK             0x01FF  /* PHASE3_DURATION - [8:0] */
+#define ARIZONA_PHASE3_DURATION_SHIFT                 0  /* PHASE3_DURATION - [8:0] */
+#define ARIZONA_PHASE3_DURATION_WIDTH                 9  /* PHASE3_DURATION - [8:0] */
+
+/*
+ * R152 (0x98) - Haptics Status
+ */
+#define ARIZONA_ONESHOT_STS                      0x0001  /* ONESHOT_STS */
+#define ARIZONA_ONESHOT_STS_MASK                 0x0001  /* ONESHOT_STS */
+#define ARIZONA_ONESHOT_STS_SHIFT                     0  /* ONESHOT_STS */
+#define ARIZONA_ONESHOT_STS_WIDTH                     1  /* ONESHOT_STS */
+
+/*
+ * R256 (0x100) - Clock 32k 1
+ */
+#define ARIZONA_CLK_32K_ENA                      0x0040  /* CLK_32K_ENA */
+#define ARIZONA_CLK_32K_ENA_MASK                 0x0040  /* CLK_32K_ENA */
+#define ARIZONA_CLK_32K_ENA_SHIFT                     6  /* CLK_32K_ENA */
+#define ARIZONA_CLK_32K_ENA_WIDTH                     1  /* CLK_32K_ENA */
+#define ARIZONA_CLK_32K_SRC_MASK                 0x0003  /* CLK_32K_SRC - [1:0] */
+#define ARIZONA_CLK_32K_SRC_SHIFT                     0  /* CLK_32K_SRC - [1:0] */
+#define ARIZONA_CLK_32K_SRC_WIDTH                     2  /* CLK_32K_SRC - [1:0] */
+
+/*
+ * R257 (0x101) - System Clock 1
+ */
+#define ARIZONA_SYSCLK_FRAC                      0x8000  /* SYSCLK_FRAC */
+#define ARIZONA_SYSCLK_FRAC_MASK                 0x8000  /* SYSCLK_FRAC */
+#define ARIZONA_SYSCLK_FRAC_SHIFT                    15  /* SYSCLK_FRAC */
+#define ARIZONA_SYSCLK_FRAC_WIDTH                     1  /* SYSCLK_FRAC */
+#define ARIZONA_SYSCLK_FREQ_MASK                 0x0700  /* SYSCLK_FREQ - [10:8] */
+#define ARIZONA_SYSCLK_FREQ_SHIFT                     8  /* SYSCLK_FREQ - [10:8] */
+#define ARIZONA_SYSCLK_FREQ_WIDTH                     3  /* SYSCLK_FREQ - [10:8] */
+#define ARIZONA_SYSCLK_ENA                       0x0040  /* SYSCLK_ENA */
+#define ARIZONA_SYSCLK_ENA_MASK                  0x0040  /* SYSCLK_ENA */
+#define ARIZONA_SYSCLK_ENA_SHIFT                      6  /* SYSCLK_ENA */
+#define ARIZONA_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+#define ARIZONA_SYSCLK_SRC_MASK                  0x000F  /* SYSCLK_SRC - [3:0] */
+#define ARIZONA_SYSCLK_SRC_SHIFT                      0  /* SYSCLK_SRC - [3:0] */
+#define ARIZONA_SYSCLK_SRC_WIDTH                      4  /* SYSCLK_SRC - [3:0] */
+
+/*
+ * R258 (0x102) - Sample rate 1
+ */
+#define ARIZONA_SAMPLE_RATE_1_MASK               0x001F  /* SAMPLE_RATE_1 - [4:0] */
+#define ARIZONA_SAMPLE_RATE_1_SHIFT                   0  /* SAMPLE_RATE_1 - [4:0] */
+#define ARIZONA_SAMPLE_RATE_1_WIDTH                   5  /* SAMPLE_RATE_1 - [4:0] */
+
+/*
+ * R259 (0x103) - Sample rate 2
+ */
+#define ARIZONA_SAMPLE_RATE_2_MASK               0x001F  /* SAMPLE_RATE_2 - [4:0] */
+#define ARIZONA_SAMPLE_RATE_2_SHIFT                   0  /* SAMPLE_RATE_2 - [4:0] */
+#define ARIZONA_SAMPLE_RATE_2_WIDTH                   5  /* SAMPLE_RATE_2 - [4:0] */
+
+/*
+ * R260 (0x104) - Sample rate 3
+ */
+#define ARIZONA_SAMPLE_RATE_3_MASK               0x001F  /* SAMPLE_RATE_3 - [4:0] */
+#define ARIZONA_SAMPLE_RATE_3_SHIFT                   0  /* SAMPLE_RATE_3 - [4:0] */
+#define ARIZONA_SAMPLE_RATE_3_WIDTH                   5  /* SAMPLE_RATE_3 - [4:0] */
+
+/*
+ * R266 (0x10A) - Sample rate 1 status
+ */
+#define ARIZONA_SAMPLE_RATE_1_STS_MASK           0x001F  /* SAMPLE_RATE_1_STS - [4:0] */
+#define ARIZONA_SAMPLE_RATE_1_STS_SHIFT               0  /* SAMPLE_RATE_1_STS - [4:0] */
+#define ARIZONA_SAMPLE_RATE_1_STS_WIDTH               5  /* SAMPLE_RATE_1_STS - [4:0] */
+
+/*
+ * R267 (0x10B) - Sample rate 2 status
+ */
+#define ARIZONA_SAMPLE_RATE_2_STS_MASK           0x001F  /* SAMPLE_RATE_2_STS - [4:0] */
+#define ARIZONA_SAMPLE_RATE_2_STS_SHIFT               0  /* SAMPLE_RATE_2_STS - [4:0] */
+#define ARIZONA_SAMPLE_RATE_2_STS_WIDTH               5  /* SAMPLE_RATE_2_STS - [4:0] */
+
+/*
+ * R268 (0x10C) - Sample rate 3 status
+ */
+#define ARIZONA_SAMPLE_RATE_3_STS_MASK           0x001F  /* SAMPLE_RATE_3_STS - [4:0] */
+#define ARIZONA_SAMPLE_RATE_3_STS_SHIFT               0  /* SAMPLE_RATE_3_STS - [4:0] */
+#define ARIZONA_SAMPLE_RATE_3_STS_WIDTH               5  /* SAMPLE_RATE_3_STS - [4:0] */
+
+/*
+ * R274 (0x112) - Async clock 1
+ */
+#define ARIZONA_ASYNC_CLK_FREQ_MASK              0x0700  /* ASYNC_CLK_FREQ - [10:8] */
+#define ARIZONA_ASYNC_CLK_FREQ_SHIFT                  8  /* ASYNC_CLK_FREQ - [10:8] */
+#define ARIZONA_ASYNC_CLK_FREQ_WIDTH                  3  /* ASYNC_CLK_FREQ - [10:8] */
+#define ARIZONA_ASYNC_CLK_ENA                    0x0040  /* ASYNC_CLK_ENA */
+#define ARIZONA_ASYNC_CLK_ENA_MASK               0x0040  /* ASYNC_CLK_ENA */
+#define ARIZONA_ASYNC_CLK_ENA_SHIFT                   6  /* ASYNC_CLK_ENA */
+#define ARIZONA_ASYNC_CLK_ENA_WIDTH                   1  /* ASYNC_CLK_ENA */
+#define ARIZONA_ASYNC_CLK_SRC_MASK               0x000F  /* ASYNC_CLK_SRC - [3:0] */
+#define ARIZONA_ASYNC_CLK_SRC_SHIFT                   0  /* ASYNC_CLK_SRC - [3:0] */
+#define ARIZONA_ASYNC_CLK_SRC_WIDTH                   4  /* ASYNC_CLK_SRC - [3:0] */
+
+/*
+ * R275 (0x113) - Async sample rate 1
+ */
+#define ARIZONA_ASYNC_SAMPLE_RATE_MASK           0x001F  /* ASYNC_SAMPLE_RATE - [4:0] */
+#define ARIZONA_ASYNC_SAMPLE_RATE_SHIFT               0  /* ASYNC_SAMPLE_RATE - [4:0] */
+#define ARIZONA_ASYNC_SAMPLE_RATE_WIDTH               5  /* ASYNC_SAMPLE_RATE - [4:0] */
+
+/*
+ * R283 (0x11B) - Async sample rate 1 status
+ */
+#define ARIZONA_ASYNC_SAMPLE_RATE_STS_MASK       0x001F  /* ASYNC_SAMPLE_RATE_STS - [4:0] */
+#define ARIZONA_ASYNC_SAMPLE_RATE_STS_SHIFT           0  /* ASYNC_SAMPLE_RATE_STS - [4:0] */
+#define ARIZONA_ASYNC_SAMPLE_RATE_STS_WIDTH           5  /* ASYNC_SAMPLE_RATE_STS - [4:0] */
+
+/*
+ * R329 (0x149) - Output system clock
+ */
+#define ARIZONA_OPCLK_ENA                        0x8000  /* OPCLK_ENA */
+#define ARIZONA_OPCLK_ENA_MASK                   0x8000  /* OPCLK_ENA */
+#define ARIZONA_OPCLK_ENA_SHIFT                      15  /* OPCLK_ENA */
+#define ARIZONA_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define ARIZONA_OPCLK_DIV_MASK                   0x00F8  /* OPCLK_DIV - [7:3] */
+#define ARIZONA_OPCLK_DIV_SHIFT                       3  /* OPCLK_DIV - [7:3] */
+#define ARIZONA_OPCLK_DIV_WIDTH                       5  /* OPCLK_DIV - [7:3] */
+#define ARIZONA_OPCLK_SEL_MASK                   0x0007  /* OPCLK_SEL - [2:0] */
+#define ARIZONA_OPCLK_SEL_SHIFT                       0  /* OPCLK_SEL - [2:0] */
+#define ARIZONA_OPCLK_SEL_WIDTH                       3  /* OPCLK_SEL - [2:0] */
+
+/*
+ * R330 (0x14A) - Output async clock
+ */
+#define ARIZONA_OPCLK_ASYNC_ENA                  0x8000  /* OPCLK_ASYNC_ENA */
+#define ARIZONA_OPCLK_ASYNC_ENA_MASK             0x8000  /* OPCLK_ASYNC_ENA */
+#define ARIZONA_OPCLK_ASYNC_ENA_SHIFT                15  /* OPCLK_ASYNC_ENA */
+#define ARIZONA_OPCLK_ASYNC_ENA_WIDTH                 1  /* OPCLK_ASYNC_ENA */
+#define ARIZONA_OPCLK_ASYNC_DIV_MASK             0x00F8  /* OPCLK_ASYNC_DIV - [7:3] */
+#define ARIZONA_OPCLK_ASYNC_DIV_SHIFT                 3  /* OPCLK_ASYNC_DIV - [7:3] */
+#define ARIZONA_OPCLK_ASYNC_DIV_WIDTH                 5  /* OPCLK_ASYNC_DIV - [7:3] */
+#define ARIZONA_OPCLK_ASYNC_SEL_MASK             0x0007  /* OPCLK_ASYNC_SEL - [2:0] */
+#define ARIZONA_OPCLK_ASYNC_SEL_SHIFT                 0  /* OPCLK_ASYNC_SEL - [2:0] */
+#define ARIZONA_OPCLK_ASYNC_SEL_WIDTH                 3  /* OPCLK_ASYNC_SEL - [2:0] */
+
+/*
+ * R338 (0x152) - Rate Estimator 1
+ */
+#define ARIZONA_TRIG_ON_STARTUP                  0x0010  /* TRIG_ON_STARTUP */
+#define ARIZONA_TRIG_ON_STARTUP_MASK             0x0010  /* TRIG_ON_STARTUP */
+#define ARIZONA_TRIG_ON_STARTUP_SHIFT                 4  /* TRIG_ON_STARTUP */
+#define ARIZONA_TRIG_ON_STARTUP_WIDTH                 1  /* TRIG_ON_STARTUP */
+#define ARIZONA_LRCLK_SRC_MASK                   0x000E  /* LRCLK_SRC - [3:1] */
+#define ARIZONA_LRCLK_SRC_SHIFT                       1  /* LRCLK_SRC - [3:1] */
+#define ARIZONA_LRCLK_SRC_WIDTH                       3  /* LRCLK_SRC - [3:1] */
+#define ARIZONA_RATE_EST_ENA                     0x0001  /* RATE_EST_ENA */
+#define ARIZONA_RATE_EST_ENA_MASK                0x0001  /* RATE_EST_ENA */
+#define ARIZONA_RATE_EST_ENA_SHIFT                    0  /* RATE_EST_ENA */
+#define ARIZONA_RATE_EST_ENA_WIDTH                    1  /* RATE_EST_ENA */
+
+/*
+ * R339 (0x153) - Rate Estimator 2
+ */
+#define ARIZONA_SAMPLE_RATE_DETECT_A_MASK        0x001F  /* SAMPLE_RATE_DETECT_A - [4:0] */
+#define ARIZONA_SAMPLE_RATE_DETECT_A_SHIFT            0  /* SAMPLE_RATE_DETECT_A - [4:0] */
+#define ARIZONA_SAMPLE_RATE_DETECT_A_WIDTH            5  /* SAMPLE_RATE_DETECT_A - [4:0] */
+
+/*
+ * R340 (0x154) - Rate Estimator 3
+ */
+#define ARIZONA_SAMPLE_RATE_DETECT_B_MASK        0x001F  /* SAMPLE_RATE_DETECT_B - [4:0] */
+#define ARIZONA_SAMPLE_RATE_DETECT_B_SHIFT            0  /* SAMPLE_RATE_DETECT_B - [4:0] */
+#define ARIZONA_SAMPLE_RATE_DETECT_B_WIDTH            5  /* SAMPLE_RATE_DETECT_B - [4:0] */
+
+/*
+ * R341 (0x155) - Rate Estimator 4
+ */
+#define ARIZONA_SAMPLE_RATE_DETECT_C_MASK        0x001F  /* SAMPLE_RATE_DETECT_C - [4:0] */
+#define ARIZONA_SAMPLE_RATE_DETECT_C_SHIFT            0  /* SAMPLE_RATE_DETECT_C - [4:0] */
+#define ARIZONA_SAMPLE_RATE_DETECT_C_WIDTH            5  /* SAMPLE_RATE_DETECT_C - [4:0] */
+
+/*
+ * R342 (0x156) - Rate Estimator 5
+ */
+#define ARIZONA_SAMPLE_RATE_DETECT_D_MASK        0x001F  /* SAMPLE_RATE_DETECT_D - [4:0] */
+#define ARIZONA_SAMPLE_RATE_DETECT_D_SHIFT            0  /* SAMPLE_RATE_DETECT_D - [4:0] */
+#define ARIZONA_SAMPLE_RATE_DETECT_D_WIDTH            5  /* SAMPLE_RATE_DETECT_D - [4:0] */
+
+/*
+ * R369 (0x171) - FLL1 Control 1
+ */
+#define ARIZONA_FLL1_FREERUN                     0x0002  /* FLL1_FREERUN */
+#define ARIZONA_FLL1_FREERUN_MASK                0x0002  /* FLL1_FREERUN */
+#define ARIZONA_FLL1_FREERUN_SHIFT                    1  /* FLL1_FREERUN */
+#define ARIZONA_FLL1_FREERUN_WIDTH                    1  /* FLL1_FREERUN */
+#define ARIZONA_FLL1_ENA                         0x0001  /* FLL1_ENA */
+#define ARIZONA_FLL1_ENA_MASK                    0x0001  /* FLL1_ENA */
+#define ARIZONA_FLL1_ENA_SHIFT                        0  /* FLL1_ENA */
+#define ARIZONA_FLL1_ENA_WIDTH                        1  /* FLL1_ENA */
+
+/*
+ * R370 (0x172) - FLL1 Control 2
+ */
+#define ARIZONA_FLL1_CTRL_UPD                    0x8000  /* FLL1_CTRL_UPD */
+#define ARIZONA_FLL1_CTRL_UPD_MASK               0x8000  /* FLL1_CTRL_UPD */
+#define ARIZONA_FLL1_CTRL_UPD_SHIFT                  15  /* FLL1_CTRL_UPD */
+#define ARIZONA_FLL1_CTRL_UPD_WIDTH                   1  /* FLL1_CTRL_UPD */
+#define ARIZONA_FLL1_N_MASK                      0x03FF  /* FLL1_N - [9:0] */
+#define ARIZONA_FLL1_N_SHIFT                          0  /* FLL1_N - [9:0] */
+#define ARIZONA_FLL1_N_WIDTH                         10  /* FLL1_N - [9:0] */
+
+/*
+ * R371 (0x173) - FLL1 Control 3
+ */
+#define ARIZONA_FLL1_THETA_MASK                  0xFFFF  /* FLL1_THETA - [15:0] */
+#define ARIZONA_FLL1_THETA_SHIFT                      0  /* FLL1_THETA - [15:0] */
+#define ARIZONA_FLL1_THETA_WIDTH                     16  /* FLL1_THETA - [15:0] */
+
+/*
+ * R372 (0x174) - FLL1 Control 4
+ */
+#define ARIZONA_FLL1_LAMBDA_MASK                 0xFFFF  /* FLL1_LAMBDA - [15:0] */
+#define ARIZONA_FLL1_LAMBDA_SHIFT                     0  /* FLL1_LAMBDA - [15:0] */
+#define ARIZONA_FLL1_LAMBDA_WIDTH                    16  /* FLL1_LAMBDA - [15:0] */
+
+/*
+ * R373 (0x175) - FLL1 Control 5
+ */
+#define ARIZONA_FLL1_FRATIO_MASK                 0x0700  /* FLL1_FRATIO - [10:8] */
+#define ARIZONA_FLL1_FRATIO_SHIFT                     8  /* FLL1_FRATIO - [10:8] */
+#define ARIZONA_FLL1_FRATIO_WIDTH                     3  /* FLL1_FRATIO - [10:8] */
+#define ARIZONA_FLL1_OUTDIV_MASK                 0x000E  /* FLL1_OUTDIV - [3:1] */
+#define ARIZONA_FLL1_OUTDIV_SHIFT                     1  /* FLL1_OUTDIV - [3:1] */
+#define ARIZONA_FLL1_OUTDIV_WIDTH                     3  /* FLL1_OUTDIV - [3:1] */
+
+/*
+ * R374 (0x176) - FLL1 Control 6
+ */
+#define ARIZONA_FLL1_CLK_REF_DIV_MASK            0x00C0  /* FLL1_CLK_REF_DIV - [7:6] */
+#define ARIZONA_FLL1_CLK_REF_DIV_SHIFT                6  /* FLL1_CLK_REF_DIV - [7:6] */
+#define ARIZONA_FLL1_CLK_REF_DIV_WIDTH                2  /* FLL1_CLK_REF_DIV - [7:6] */
+#define ARIZONA_FLL1_CLK_REF_SRC_MASK            0x000F  /* FLL1_CLK_REF_SRC - [3:0] */
+#define ARIZONA_FLL1_CLK_REF_SRC_SHIFT                0  /* FLL1_CLK_REF_SRC - [3:0] */
+#define ARIZONA_FLL1_CLK_REF_SRC_WIDTH                4  /* FLL1_CLK_REF_SRC - [3:0] */
+
+/*
+ * R375 (0x177) - FLL1 Loop Filter Test 1
+ */
+#define ARIZONA_FLL1_FRC_INTEG_UPD               0x8000  /* FLL1_FRC_INTEG_UPD */
+#define ARIZONA_FLL1_FRC_INTEG_UPD_MASK          0x8000  /* FLL1_FRC_INTEG_UPD */
+#define ARIZONA_FLL1_FRC_INTEG_UPD_SHIFT             15  /* FLL1_FRC_INTEG_UPD */
+#define ARIZONA_FLL1_FRC_INTEG_UPD_WIDTH              1  /* FLL1_FRC_INTEG_UPD */
+#define ARIZONA_FLL1_FRC_INTEG_VAL_MASK          0x0FFF  /* FLL1_FRC_INTEG_VAL - [11:0] */
+#define ARIZONA_FLL1_FRC_INTEG_VAL_SHIFT              0  /* FLL1_FRC_INTEG_VAL - [11:0] */
+#define ARIZONA_FLL1_FRC_INTEG_VAL_WIDTH             12  /* FLL1_FRC_INTEG_VAL - [11:0] */
+
+/*
+ * R385 (0x181) - FLL1 Synchroniser 1
+ */
+#define ARIZONA_FLL1_SYNC_ENA                    0x0001  /* FLL1_SYNC_ENA */
+#define ARIZONA_FLL1_SYNC_ENA_MASK               0x0001  /* FLL1_SYNC_ENA */
+#define ARIZONA_FLL1_SYNC_ENA_SHIFT                   0  /* FLL1_SYNC_ENA */
+#define ARIZONA_FLL1_SYNC_ENA_WIDTH                   1  /* FLL1_SYNC_ENA */
+
+/*
+ * R386 (0x182) - FLL1 Synchroniser 2
+ */
+#define ARIZONA_FLL1_SYNC_N_MASK                 0x03FF  /* FLL1_SYNC_N - [9:0] */
+#define ARIZONA_FLL1_SYNC_N_SHIFT                     0  /* FLL1_SYNC_N - [9:0] */
+#define ARIZONA_FLL1_SYNC_N_WIDTH                    10  /* FLL1_SYNC_N - [9:0] */
+
+/*
+ * R387 (0x183) - FLL1 Synchroniser 3
+ */
+#define ARIZONA_FLL1_SYNC_THETA_MASK             0xFFFF  /* FLL1_SYNC_THETA - [15:0] */
+#define ARIZONA_FLL1_SYNC_THETA_SHIFT                 0  /* FLL1_SYNC_THETA - [15:0] */
+#define ARIZONA_FLL1_SYNC_THETA_WIDTH                16  /* FLL1_SYNC_THETA - [15:0] */
+
+/*
+ * R388 (0x184) - FLL1 Synchroniser 4
+ */
+#define ARIZONA_FLL1_SYNC_LAMBDA_MASK            0xFFFF  /* FLL1_SYNC_LAMBDA - [15:0] */
+#define ARIZONA_FLL1_SYNC_LAMBDA_SHIFT                0  /* FLL1_SYNC_LAMBDA - [15:0] */
+#define ARIZONA_FLL1_SYNC_LAMBDA_WIDTH               16  /* FLL1_SYNC_LAMBDA - [15:0] */
+
+/*
+ * R389 (0x185) - FLL1 Synchroniser 5
+ */
+#define ARIZONA_FLL1_SYNC_FRATIO_MASK            0x0700  /* FLL1_SYNC_FRATIO - [10:8] */
+#define ARIZONA_FLL1_SYNC_FRATIO_SHIFT                8  /* FLL1_SYNC_FRATIO - [10:8] */
+#define ARIZONA_FLL1_SYNC_FRATIO_WIDTH                3  /* FLL1_SYNC_FRATIO - [10:8] */
+
+/*
+ * R390 (0x186) - FLL1 Synchroniser 6
+ */
+#define ARIZONA_FLL1_CLK_SYNC_DIV_MASK           0x00C0  /* FLL1_CLK_SYNC_DIV - [7:6] */
+#define ARIZONA_FLL1_CLK_SYNC_DIV_SHIFT               6  /* FLL1_CLK_SYNC_DIV - [7:6] */
+#define ARIZONA_FLL1_CLK_SYNC_DIV_WIDTH               2  /* FLL1_CLK_SYNC_DIV - [7:6] */
+#define ARIZONA_FLL1_CLK_SYNC_SRC_MASK           0x000F  /* FLL1_CLK_SYNC_SRC - [3:0] */
+#define ARIZONA_FLL1_CLK_SYNC_SRC_SHIFT               0  /* FLL1_CLK_SYNC_SRC - [3:0] */
+#define ARIZONA_FLL1_CLK_SYNC_SRC_WIDTH               4  /* FLL1_CLK_SYNC_SRC - [3:0] */
+
+/*
+ * R393 (0x189) - FLL1 Spread Spectrum
+ */
+#define ARIZONA_FLL1_SS_AMPL_MASK                0x0030  /* FLL1_SS_AMPL - [5:4] */
+#define ARIZONA_FLL1_SS_AMPL_SHIFT                    4  /* FLL1_SS_AMPL - [5:4] */
+#define ARIZONA_FLL1_SS_AMPL_WIDTH                    2  /* FLL1_SS_AMPL - [5:4] */
+#define ARIZONA_FLL1_SS_FREQ_MASK                0x000C  /* FLL1_SS_FREQ - [3:2] */
+#define ARIZONA_FLL1_SS_FREQ_SHIFT                    2  /* FLL1_SS_FREQ - [3:2] */
+#define ARIZONA_FLL1_SS_FREQ_WIDTH                    2  /* FLL1_SS_FREQ - [3:2] */
+#define ARIZONA_FLL1_SS_SEL_MASK                 0x0003  /* FLL1_SS_SEL - [1:0] */
+#define ARIZONA_FLL1_SS_SEL_SHIFT                     0  /* FLL1_SS_SEL - [1:0] */
+#define ARIZONA_FLL1_SS_SEL_WIDTH                     2  /* FLL1_SS_SEL - [1:0] */
+
+/*
+ * R394 (0x18A) - FLL1 GPIO Clock
+ */
+#define ARIZONA_FLL1_GPDIV_MASK                  0x00FE  /* FLL1_GPDIV - [7:1] */
+#define ARIZONA_FLL1_GPDIV_SHIFT                      1  /* FLL1_GPDIV - [7:1] */
+#define ARIZONA_FLL1_GPDIV_WIDTH                      7  /* FLL1_GPDIV - [7:1] */
+#define ARIZONA_FLL1_GPDIV_ENA                   0x0001  /* FLL1_GPDIV_ENA */
+#define ARIZONA_FLL1_GPDIV_ENA_MASK              0x0001  /* FLL1_GPDIV_ENA */
+#define ARIZONA_FLL1_GPDIV_ENA_SHIFT                  0  /* FLL1_GPDIV_ENA */
+#define ARIZONA_FLL1_GPDIV_ENA_WIDTH                  1  /* FLL1_GPDIV_ENA */
+
+/*
+ * R401 (0x191) - FLL2 Control 1
+ */
+#define ARIZONA_FLL2_FREERUN                     0x0002  /* FLL2_FREERUN */
+#define ARIZONA_FLL2_FREERUN_MASK                0x0002  /* FLL2_FREERUN */
+#define ARIZONA_FLL2_FREERUN_SHIFT                    1  /* FLL2_FREERUN */
+#define ARIZONA_FLL2_FREERUN_WIDTH                    1  /* FLL2_FREERUN */
+#define ARIZONA_FLL2_ENA                         0x0001  /* FLL2_ENA */
+#define ARIZONA_FLL2_ENA_MASK                    0x0001  /* FLL2_ENA */
+#define ARIZONA_FLL2_ENA_SHIFT                        0  /* FLL2_ENA */
+#define ARIZONA_FLL2_ENA_WIDTH                        1  /* FLL2_ENA */
+
+/*
+ * R402 (0x192) - FLL2 Control 2
+ */
+#define ARIZONA_FLL2_CTRL_UPD                    0x8000  /* FLL2_CTRL_UPD */
+#define ARIZONA_FLL2_CTRL_UPD_MASK               0x8000  /* FLL2_CTRL_UPD */
+#define ARIZONA_FLL2_CTRL_UPD_SHIFT                  15  /* FLL2_CTRL_UPD */
+#define ARIZONA_FLL2_CTRL_UPD_WIDTH                   1  /* FLL2_CTRL_UPD */
+#define ARIZONA_FLL2_N_MASK                      0x03FF  /* FLL2_N - [9:0] */
+#define ARIZONA_FLL2_N_SHIFT                          0  /* FLL2_N - [9:0] */
+#define ARIZONA_FLL2_N_WIDTH                         10  /* FLL2_N - [9:0] */
+
+/*
+ * R403 (0x193) - FLL2 Control 3
+ */
+#define ARIZONA_FLL2_THETA_MASK                  0xFFFF  /* FLL2_THETA - [15:0] */
+#define ARIZONA_FLL2_THETA_SHIFT                      0  /* FLL2_THETA - [15:0] */
+#define ARIZONA_FLL2_THETA_WIDTH                     16  /* FLL2_THETA - [15:0] */
+
+/*
+ * R404 (0x194) - FLL2 Control 4
+ */
+#define ARIZONA_FLL2_LAMBDA_MASK                 0xFFFF  /* FLL2_LAMBDA - [15:0] */
+#define ARIZONA_FLL2_LAMBDA_SHIFT                     0  /* FLL2_LAMBDA - [15:0] */
+#define ARIZONA_FLL2_LAMBDA_WIDTH                    16  /* FLL2_LAMBDA - [15:0] */
+
+/*
+ * R405 (0x195) - FLL2 Control 5
+ */
+#define ARIZONA_FLL2_FRATIO_MASK                 0x0700  /* FLL2_FRATIO - [10:8] */
+#define ARIZONA_FLL2_FRATIO_SHIFT                     8  /* FLL2_FRATIO - [10:8] */
+#define ARIZONA_FLL2_FRATIO_WIDTH                     3  /* FLL2_FRATIO - [10:8] */
+#define ARIZONA_FLL2_OUTDIV_MASK                 0x000E  /* FLL2_OUTDIV - [3:1] */
+#define ARIZONA_FLL2_OUTDIV_SHIFT                     1  /* FLL2_OUTDIV - [3:1] */
+#define ARIZONA_FLL2_OUTDIV_WIDTH                     3  /* FLL2_OUTDIV - [3:1] */
+
+/*
+ * R406 (0x196) - FLL2 Control 6
+ */
+#define ARIZONA_FLL2_CLK_REF_DIV_MASK            0x00C0  /* FLL2_CLK_REF_DIV - [7:6] */
+#define ARIZONA_FLL2_CLK_REF_DIV_SHIFT                6  /* FLL2_CLK_REF_DIV - [7:6] */
+#define ARIZONA_FLL2_CLK_REF_DIV_WIDTH                2  /* FLL2_CLK_REF_DIV - [7:6] */
+#define ARIZONA_FLL2_CLK_REF_SRC_MASK            0x000F  /* FLL2_CLK_REF_SRC - [3:0] */
+#define ARIZONA_FLL2_CLK_REF_SRC_SHIFT                0  /* FLL2_CLK_REF_SRC - [3:0] */
+#define ARIZONA_FLL2_CLK_REF_SRC_WIDTH                4  /* FLL2_CLK_REF_SRC - [3:0] */
+
+/*
+ * R407 (0x197) - FLL2 Loop Filter Test 1
+ */
+#define ARIZONA_FLL2_FRC_INTEG_UPD               0x8000  /* FLL2_FRC_INTEG_UPD */
+#define ARIZONA_FLL2_FRC_INTEG_UPD_MASK          0x8000  /* FLL2_FRC_INTEG_UPD */
+#define ARIZONA_FLL2_FRC_INTEG_UPD_SHIFT             15  /* FLL2_FRC_INTEG_UPD */
+#define ARIZONA_FLL2_FRC_INTEG_UPD_WIDTH              1  /* FLL2_FRC_INTEG_UPD */
+#define ARIZONA_FLL2_FRC_INTEG_VAL_MASK          0x0FFF  /* FLL2_FRC_INTEG_VAL - [11:0] */
+#define ARIZONA_FLL2_FRC_INTEG_VAL_SHIFT              0  /* FLL2_FRC_INTEG_VAL - [11:0] */
+#define ARIZONA_FLL2_FRC_INTEG_VAL_WIDTH             12  /* FLL2_FRC_INTEG_VAL - [11:0] */
+
+/*
+ * R417 (0x1A1) - FLL2 Synchroniser 1
+ */
+#define ARIZONA_FLL2_SYNC_ENA                    0x0001  /* FLL2_SYNC_ENA */
+#define ARIZONA_FLL2_SYNC_ENA_MASK               0x0001  /* FLL2_SYNC_ENA */
+#define ARIZONA_FLL2_SYNC_ENA_SHIFT                   0  /* FLL2_SYNC_ENA */
+#define ARIZONA_FLL2_SYNC_ENA_WIDTH                   1  /* FLL2_SYNC_ENA */
+
+/*
+ * R418 (0x1A2) - FLL2 Synchroniser 2
+ */
+#define ARIZONA_FLL2_SYNC_N_MASK                 0x03FF  /* FLL2_SYNC_N - [9:0] */
+#define ARIZONA_FLL2_SYNC_N_SHIFT                     0  /* FLL2_SYNC_N - [9:0] */
+#define ARIZONA_FLL2_SYNC_N_WIDTH                    10  /* FLL2_SYNC_N - [9:0] */
+
+/*
+ * R419 (0x1A3) - FLL2 Synchroniser 3
+ */
+#define ARIZONA_FLL2_SYNC_THETA_MASK             0xFFFF  /* FLL2_SYNC_THETA - [15:0] */
+#define ARIZONA_FLL2_SYNC_THETA_SHIFT                 0  /* FLL2_SYNC_THETA - [15:0] */
+#define ARIZONA_FLL2_SYNC_THETA_WIDTH                16  /* FLL2_SYNC_THETA - [15:0] */
+
+/*
+ * R420 (0x1A4) - FLL2 Synchroniser 4
+ */
+#define ARIZONA_FLL2_SYNC_LAMBDA_MASK            0xFFFF  /* FLL2_SYNC_LAMBDA - [15:0] */
+#define ARIZONA_FLL2_SYNC_LAMBDA_SHIFT                0  /* FLL2_SYNC_LAMBDA - [15:0] */
+#define ARIZONA_FLL2_SYNC_LAMBDA_WIDTH               16  /* FLL2_SYNC_LAMBDA - [15:0] */
+
+/*
+ * R421 (0x1A5) - FLL2 Synchroniser 5
+ */
+#define ARIZONA_FLL2_SYNC_FRATIO_MASK            0x0700  /* FLL2_SYNC_FRATIO - [10:8] */
+#define ARIZONA_FLL2_SYNC_FRATIO_SHIFT                8  /* FLL2_SYNC_FRATIO - [10:8] */
+#define ARIZONA_FLL2_SYNC_FRATIO_WIDTH                3  /* FLL2_SYNC_FRATIO - [10:8] */
+
+/*
+ * R422 (0x1A6) - FLL2 Synchroniser 6
+ */
+#define ARIZONA_FLL2_CLK_SYNC_DIV_MASK           0x00C0  /* FLL2_CLK_SYNC_DIV - [7:6] */
+#define ARIZONA_FLL2_CLK_SYNC_DIV_SHIFT               6  /* FLL2_CLK_SYNC_DIV - [7:6] */
+#define ARIZONA_FLL2_CLK_SYNC_DIV_WIDTH               2  /* FLL2_CLK_SYNC_DIV - [7:6] */
+#define ARIZONA_FLL2_CLK_SYNC_SRC_MASK           0x000F  /* FLL2_CLK_SYNC_SRC - [3:0] */
+#define ARIZONA_FLL2_CLK_SYNC_SRC_SHIFT               0  /* FLL2_CLK_SYNC_SRC - [3:0] */
+#define ARIZONA_FLL2_CLK_SYNC_SRC_WIDTH               4  /* FLL2_CLK_SYNC_SRC - [3:0] */
+
+/*
+ * R425 (0x1A9) - FLL2 Spread Spectrum
+ */
+#define ARIZONA_FLL2_SS_AMPL_MASK                0x0030  /* FLL2_SS_AMPL - [5:4] */
+#define ARIZONA_FLL2_SS_AMPL_SHIFT                    4  /* FLL2_SS_AMPL - [5:4] */
+#define ARIZONA_FLL2_SS_AMPL_WIDTH                    2  /* FLL2_SS_AMPL - [5:4] */
+#define ARIZONA_FLL2_SS_FREQ_MASK                0x000C  /* FLL2_SS_FREQ - [3:2] */
+#define ARIZONA_FLL2_SS_FREQ_SHIFT                    2  /* FLL2_SS_FREQ - [3:2] */
+#define ARIZONA_FLL2_SS_FREQ_WIDTH                    2  /* FLL2_SS_FREQ - [3:2] */
+#define ARIZONA_FLL2_SS_SEL_MASK                 0x0003  /* FLL2_SS_SEL - [1:0] */
+#define ARIZONA_FLL2_SS_SEL_SHIFT                     0  /* FLL2_SS_SEL - [1:0] */
+#define ARIZONA_FLL2_SS_SEL_WIDTH                     2  /* FLL2_SS_SEL - [1:0] */
+
+/*
+ * R426 (0x1AA) - FLL2 GPIO Clock
+ */
+#define ARIZONA_FLL2_GPDIV_MASK                  0x00FE  /* FLL2_GPDIV - [7:1] */
+#define ARIZONA_FLL2_GPDIV_SHIFT                      1  /* FLL2_GPDIV - [7:1] */
+#define ARIZONA_FLL2_GPDIV_WIDTH                      7  /* FLL2_GPDIV - [7:1] */
+#define ARIZONA_FLL2_GPDIV_ENA                   0x0001  /* FLL2_GPDIV_ENA */
+#define ARIZONA_FLL2_GPDIV_ENA_MASK              0x0001  /* FLL2_GPDIV_ENA */
+#define ARIZONA_FLL2_GPDIV_ENA_SHIFT                  0  /* FLL2_GPDIV_ENA */
+#define ARIZONA_FLL2_GPDIV_ENA_WIDTH                  1  /* FLL2_GPDIV_ENA */
+
+/*
+ * R512 (0x200) - Mic Charge Pump 1
+ */
+#define ARIZONA_CPMIC_DISCH                      0x0004  /* CPMIC_DISCH */
+#define ARIZONA_CPMIC_DISCH_MASK                 0x0004  /* CPMIC_DISCH */
+#define ARIZONA_CPMIC_DISCH_SHIFT                     2  /* CPMIC_DISCH */
+#define ARIZONA_CPMIC_DISCH_WIDTH                     1  /* CPMIC_DISCH */
+#define ARIZONA_CPMIC_BYPASS                     0x0002  /* CPMIC_BYPASS */
+#define ARIZONA_CPMIC_BYPASS_MASK                0x0002  /* CPMIC_BYPASS */
+#define ARIZONA_CPMIC_BYPASS_SHIFT                    1  /* CPMIC_BYPASS */
+#define ARIZONA_CPMIC_BYPASS_WIDTH                    1  /* CPMIC_BYPASS */
+#define ARIZONA_CPMIC_ENA                        0x0001  /* CPMIC_ENA */
+#define ARIZONA_CPMIC_ENA_MASK                   0x0001  /* CPMIC_ENA */
+#define ARIZONA_CPMIC_ENA_SHIFT                       0  /* CPMIC_ENA */
+#define ARIZONA_CPMIC_ENA_WIDTH                       1  /* CPMIC_ENA */
+
+/*
+ * R528 (0x210) - LDO1 Control 1
+ */
+#define ARIZONA_LDO1_VSEL_MASK                   0x07E0  /* LDO1_VSEL - [10:5] */
+#define ARIZONA_LDO1_VSEL_SHIFT                       5  /* LDO1_VSEL - [10:5] */
+#define ARIZONA_LDO1_VSEL_WIDTH                       6  /* LDO1_VSEL - [10:5] */
+#define ARIZONA_LDO1_FAST                        0x0010  /* LDO1_FAST */
+#define ARIZONA_LDO1_FAST_MASK                   0x0010  /* LDO1_FAST */
+#define ARIZONA_LDO1_FAST_SHIFT                       4  /* LDO1_FAST */
+#define ARIZONA_LDO1_FAST_WIDTH                       1  /* LDO1_FAST */
+#define ARIZONA_LDO1_DISCH                       0x0004  /* LDO1_DISCH */
+#define ARIZONA_LDO1_DISCH_MASK                  0x0004  /* LDO1_DISCH */
+#define ARIZONA_LDO1_DISCH_SHIFT                      2  /* LDO1_DISCH */
+#define ARIZONA_LDO1_DISCH_WIDTH                      1  /* LDO1_DISCH */
+#define ARIZONA_LDO1_BYPASS                      0x0002  /* LDO1_BYPASS */
+#define ARIZONA_LDO1_BYPASS_MASK                 0x0002  /* LDO1_BYPASS */
+#define ARIZONA_LDO1_BYPASS_SHIFT                     1  /* LDO1_BYPASS */
+#define ARIZONA_LDO1_BYPASS_WIDTH                     1  /* LDO1_BYPASS */
+#define ARIZONA_LDO1_ENA                         0x0001  /* LDO1_ENA */
+#define ARIZONA_LDO1_ENA_MASK                    0x0001  /* LDO1_ENA */
+#define ARIZONA_LDO1_ENA_SHIFT                        0  /* LDO1_ENA */
+#define ARIZONA_LDO1_ENA_WIDTH                        1  /* LDO1_ENA */
+
+/*
+ * R531 (0x213) - LDO2 Control 1
+ */
+#define ARIZONA_LDO2_VSEL_MASK                   0x07E0  /* LDO2_VSEL - [10:5] */
+#define ARIZONA_LDO2_VSEL_SHIFT                       5  /* LDO2_VSEL - [10:5] */
+#define ARIZONA_LDO2_VSEL_WIDTH                       6  /* LDO2_VSEL - [10:5] */
+#define ARIZONA_LDO2_FAST                        0x0010  /* LDO2_FAST */
+#define ARIZONA_LDO2_FAST_MASK                   0x0010  /* LDO2_FAST */
+#define ARIZONA_LDO2_FAST_SHIFT                       4  /* LDO2_FAST */
+#define ARIZONA_LDO2_FAST_WIDTH                       1  /* LDO2_FAST */
+#define ARIZONA_LDO2_DISCH                       0x0004  /* LDO2_DISCH */
+#define ARIZONA_LDO2_DISCH_MASK                  0x0004  /* LDO2_DISCH */
+#define ARIZONA_LDO2_DISCH_SHIFT                      2  /* LDO2_DISCH */
+#define ARIZONA_LDO2_DISCH_WIDTH                      1  /* LDO2_DISCH */
+#define ARIZONA_LDO2_BYPASS                      0x0002  /* LDO2_BYPASS */
+#define ARIZONA_LDO2_BYPASS_MASK                 0x0002  /* LDO2_BYPASS */
+#define ARIZONA_LDO2_BYPASS_SHIFT                     1  /* LDO2_BYPASS */
+#define ARIZONA_LDO2_BYPASS_WIDTH                     1  /* LDO2_BYPASS */
+#define ARIZONA_LDO2_ENA                         0x0001  /* LDO2_ENA */
+#define ARIZONA_LDO2_ENA_MASK                    0x0001  /* LDO2_ENA */
+#define ARIZONA_LDO2_ENA_SHIFT                        0  /* LDO2_ENA */
+#define ARIZONA_LDO2_ENA_WIDTH                        1  /* LDO2_ENA */
+
+/*
+ * R536 (0x218) - Mic Bias Ctrl 1
+ */
+#define ARIZONA_MICB1_EXT_CAP                    0x8000  /* MICB1_EXT_CAP */
+#define ARIZONA_MICB1_EXT_CAP_MASK               0x8000  /* MICB1_EXT_CAP */
+#define ARIZONA_MICB1_EXT_CAP_SHIFT                  15  /* MICB1_EXT_CAP */
+#define ARIZONA_MICB1_EXT_CAP_WIDTH                   1  /* MICB1_EXT_CAP */
+#define ARIZONA_MICB1_LVL_MASK                   0x01E0  /* MICB1_LVL - [8:5] */
+#define ARIZONA_MICB1_LVL_SHIFT                       5  /* MICB1_LVL - [8:5] */
+#define ARIZONA_MICB1_LVL_WIDTH                       4  /* MICB1_LVL - [8:5] */
+#define ARIZONA_MICB1_FAST                       0x0010  /* MICB1_FAST */
+#define ARIZONA_MICB1_FAST_MASK                  0x0010  /* MICB1_FAST */
+#define ARIZONA_MICB1_FAST_SHIFT                      4  /* MICB1_FAST */
+#define ARIZONA_MICB1_FAST_WIDTH                      1  /* MICB1_FAST */
+#define ARIZONA_MICB1_RATE                       0x0008  /* MICB1_RATE */
+#define ARIZONA_MICB1_RATE_MASK                  0x0008  /* MICB1_RATE */
+#define ARIZONA_MICB1_RATE_SHIFT                      3  /* MICB1_RATE */
+#define ARIZONA_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
+#define ARIZONA_MICB1_DISCH                      0x0004  /* MICB1_DISCH */
+#define ARIZONA_MICB1_DISCH_MASK                 0x0004  /* MICB1_DISCH */
+#define ARIZONA_MICB1_DISCH_SHIFT                     2  /* MICB1_DISCH */
+#define ARIZONA_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
+#define ARIZONA_MICB1_BYPASS                     0x0002  /* MICB1_BYPASS */
+#define ARIZONA_MICB1_BYPASS_MASK                0x0002  /* MICB1_BYPASS */
+#define ARIZONA_MICB1_BYPASS_SHIFT                    1  /* MICB1_BYPASS */
+#define ARIZONA_MICB1_BYPASS_WIDTH                    1  /* MICB1_BYPASS */
+#define ARIZONA_MICB1_ENA                        0x0001  /* MICB1_ENA */
+#define ARIZONA_MICB1_ENA_MASK                   0x0001  /* MICB1_ENA */
+#define ARIZONA_MICB1_ENA_SHIFT                       0  /* MICB1_ENA */
+#define ARIZONA_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
+
+/*
+ * R537 (0x219) - Mic Bias Ctrl 2
+ */
+#define ARIZONA_MICB2_EXT_CAP                    0x8000  /* MICB2_EXT_CAP */
+#define ARIZONA_MICB2_EXT_CAP_MASK               0x8000  /* MICB2_EXT_CAP */
+#define ARIZONA_MICB2_EXT_CAP_SHIFT                  15  /* MICB2_EXT_CAP */
+#define ARIZONA_MICB2_EXT_CAP_WIDTH                   1  /* MICB2_EXT_CAP */
+#define ARIZONA_MICB2_LVL_MASK                   0x01E0  /* MICB2_LVL - [8:5] */
+#define ARIZONA_MICB2_LVL_SHIFT                       5  /* MICB2_LVL - [8:5] */
+#define ARIZONA_MICB2_LVL_WIDTH                       4  /* MICB2_LVL - [8:5] */
+#define ARIZONA_MICB2_FAST                       0x0010  /* MICB2_FAST */
+#define ARIZONA_MICB2_FAST_MASK                  0x0010  /* MICB2_FAST */
+#define ARIZONA_MICB2_FAST_SHIFT                      4  /* MICB2_FAST */
+#define ARIZONA_MICB2_FAST_WIDTH                      1  /* MICB2_FAST */
+#define ARIZONA_MICB2_RATE                       0x0008  /* MICB2_RATE */
+#define ARIZONA_MICB2_RATE_MASK                  0x0008  /* MICB2_RATE */
+#define ARIZONA_MICB2_RATE_SHIFT                      3  /* MICB2_RATE */
+#define ARIZONA_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
+#define ARIZONA_MICB2_DISCH                      0x0004  /* MICB2_DISCH */
+#define ARIZONA_MICB2_DISCH_MASK                 0x0004  /* MICB2_DISCH */
+#define ARIZONA_MICB2_DISCH_SHIFT                     2  /* MICB2_DISCH */
+#define ARIZONA_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
+#define ARIZONA_MICB2_BYPASS                     0x0002  /* MICB2_BYPASS */
+#define ARIZONA_MICB2_BYPASS_MASK                0x0002  /* MICB2_BYPASS */
+#define ARIZONA_MICB2_BYPASS_SHIFT                    1  /* MICB2_BYPASS */
+#define ARIZONA_MICB2_BYPASS_WIDTH                    1  /* MICB2_BYPASS */
+#define ARIZONA_MICB2_ENA                        0x0001  /* MICB2_ENA */
+#define ARIZONA_MICB2_ENA_MASK                   0x0001  /* MICB2_ENA */
+#define ARIZONA_MICB2_ENA_SHIFT                       0  /* MICB2_ENA */
+#define ARIZONA_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
+
+/*
+ * R538 (0x21A) - Mic Bias Ctrl 3
+ */
+#define ARIZONA_MICB3_EXT_CAP                    0x8000  /* MICB3_EXT_CAP */
+#define ARIZONA_MICB3_EXT_CAP_MASK               0x8000  /* MICB3_EXT_CAP */
+#define ARIZONA_MICB3_EXT_CAP_SHIFT                  15  /* MICB3_EXT_CAP */
+#define ARIZONA_MICB3_EXT_CAP_WIDTH                   1  /* MICB3_EXT_CAP */
+#define ARIZONA_MICB3_LVL_MASK                   0x01E0  /* MICB3_LVL - [8:5] */
+#define ARIZONA_MICB3_LVL_SHIFT                       5  /* MICB3_LVL - [8:5] */
+#define ARIZONA_MICB3_LVL_WIDTH                       4  /* MICB3_LVL - [8:5] */
+#define ARIZONA_MICB3_FAST                       0x0010  /* MICB3_FAST */
+#define ARIZONA_MICB3_FAST_MASK                  0x0010  /* MICB3_FAST */
+#define ARIZONA_MICB3_FAST_SHIFT                      4  /* MICB3_FAST */
+#define ARIZONA_MICB3_FAST_WIDTH                      1  /* MICB3_FAST */
+#define ARIZONA_MICB3_RATE                       0x0008  /* MICB3_RATE */
+#define ARIZONA_MICB3_RATE_MASK                  0x0008  /* MICB3_RATE */
+#define ARIZONA_MICB3_RATE_SHIFT                      3  /* MICB3_RATE */
+#define ARIZONA_MICB3_RATE_WIDTH                      1  /* MICB3_RATE */
+#define ARIZONA_MICB3_DISCH                      0x0004  /* MICB3_DISCH */
+#define ARIZONA_MICB3_DISCH_MASK                 0x0004  /* MICB3_DISCH */
+#define ARIZONA_MICB3_DISCH_SHIFT                     2  /* MICB3_DISCH */
+#define ARIZONA_MICB3_DISCH_WIDTH                     1  /* MICB3_DISCH */
+#define ARIZONA_MICB3_BYPASS                     0x0002  /* MICB3_BYPASS */
+#define ARIZONA_MICB3_BYPASS_MASK                0x0002  /* MICB3_BYPASS */
+#define ARIZONA_MICB3_BYPASS_SHIFT                    1  /* MICB3_BYPASS */
+#define ARIZONA_MICB3_BYPASS_WIDTH                    1  /* MICB3_BYPASS */
+#define ARIZONA_MICB3_ENA                        0x0001  /* MICB3_ENA */
+#define ARIZONA_MICB3_ENA_MASK                   0x0001  /* MICB3_ENA */
+#define ARIZONA_MICB3_ENA_SHIFT                       0  /* MICB3_ENA */
+#define ARIZONA_MICB3_ENA_WIDTH                       1  /* MICB3_ENA */
+
+/*
+ * R659 (0x293) - Accessory Detect Mode 1
+ */
+#define ARIZONA_ACCDET_SRC                       0x2000  /* ACCDET_SRC */
+#define ARIZONA_ACCDET_SRC_MASK                  0x2000  /* ACCDET_SRC */
+#define ARIZONA_ACCDET_SRC_SHIFT                     13  /* ACCDET_SRC */
+#define ARIZONA_ACCDET_SRC_WIDTH                      1  /* ACCDET_SRC */
+#define ARIZONA_ACCDET_MODE_MASK                 0x0003  /* ACCDET_MODE - [1:0] */
+#define ARIZONA_ACCDET_MODE_SHIFT                     0  /* ACCDET_MODE - [1:0] */
+#define ARIZONA_ACCDET_MODE_WIDTH                     2  /* ACCDET_MODE - [1:0] */
+
+/*
+ * R667 (0x29B) - Headphone Detect 1
+ */
+#define ARIZONA_HP_STEP_SIZE                     0x0100  /* HP_STEP_SIZE */
+#define ARIZONA_HP_STEP_SIZE_MASK                0x0100  /* HP_STEP_SIZE */
+#define ARIZONA_HP_STEP_SIZE_SHIFT                    8  /* HP_STEP_SIZE */
+#define ARIZONA_HP_STEP_SIZE_WIDTH                    1  /* HP_STEP_SIZE */
+#define ARIZONA_HP_HOLDTIME_MASK                 0x00E0  /* HP_HOLDTIME - [7:5] */
+#define ARIZONA_HP_HOLDTIME_SHIFT                     5  /* HP_HOLDTIME - [7:5] */
+#define ARIZONA_HP_HOLDTIME_WIDTH                     3  /* HP_HOLDTIME - [7:5] */
+#define ARIZONA_HP_CLK_DIV_MASK                  0x0018  /* HP_CLK_DIV - [4:3] */
+#define ARIZONA_HP_CLK_DIV_SHIFT                      3  /* HP_CLK_DIV - [4:3] */
+#define ARIZONA_HP_CLK_DIV_WIDTH                      2  /* HP_CLK_DIV - [4:3] */
+#define ARIZONA_HP_IDAC_STEER                    0x0004  /* HP_IDAC_STEER */
+#define ARIZONA_HP_IDAC_STEER_MASK               0x0004  /* HP_IDAC_STEER */
+#define ARIZONA_HP_IDAC_STEER_SHIFT                   2  /* HP_IDAC_STEER */
+#define ARIZONA_HP_IDAC_STEER_WIDTH                   1  /* HP_IDAC_STEER */
+#define ARIZONA_HP_RATE                          0x0002  /* HP_RATE */
+#define ARIZONA_HP_RATE_MASK                     0x0002  /* HP_RATE */
+#define ARIZONA_HP_RATE_SHIFT                         1  /* HP_RATE */
+#define ARIZONA_HP_RATE_WIDTH                         1  /* HP_RATE */
+#define ARIZONA_HP_POLL                          0x0001  /* HP_POLL */
+#define ARIZONA_HP_POLL_MASK                     0x0001  /* HP_POLL */
+#define ARIZONA_HP_POLL_SHIFT                         0  /* HP_POLL */
+#define ARIZONA_HP_POLL_WIDTH                         1  /* HP_POLL */
+
+/*
+ * R668 (0x29C) - Headphone Detect 2
+ */
+#define ARIZONA_HP_DONE                          0x0080  /* HP_DONE */
+#define ARIZONA_HP_DONE_MASK                     0x0080  /* HP_DONE */
+#define ARIZONA_HP_DONE_SHIFT                         7  /* HP_DONE */
+#define ARIZONA_HP_DONE_WIDTH                         1  /* HP_DONE */
+#define ARIZONA_HP_LVL_MASK                      0x007F  /* HP_LVL - [6:0] */
+#define ARIZONA_HP_LVL_SHIFT                          0  /* HP_LVL - [6:0] */
+#define ARIZONA_HP_LVL_WIDTH                          7  /* HP_LVL - [6:0] */
+
+/*
+ * R675 (0x2A3) - Mic Detect 1
+ */
+#define ARIZONA_MICD_BIAS_STARTTIME_MASK         0xF000  /* MICD_BIAS_STARTTIME - [15:12] */
+#define ARIZONA_MICD_BIAS_STARTTIME_SHIFT            12  /* MICD_BIAS_STARTTIME - [15:12] */
+#define ARIZONA_MICD_BIAS_STARTTIME_WIDTH             4  /* MICD_BIAS_STARTTIME - [15:12] */
+#define ARIZONA_MICD_RATE_MASK                   0x0F00  /* MICD_RATE - [11:8] */
+#define ARIZONA_MICD_RATE_SHIFT                       8  /* MICD_RATE - [11:8] */
+#define ARIZONA_MICD_RATE_WIDTH                       4  /* MICD_RATE - [11:8] */
+#define ARIZONA_MICD_BIAS_SRC_MASK               0x0030  /* MICD_BIAS_SRC - [5:4] */
+#define ARIZONA_MICD_BIAS_SRC_SHIFT                   4  /* MICD_BIAS_SRC - [5:4] */
+#define ARIZONA_MICD_BIAS_SRC_WIDTH                   2  /* MICD_BIAS_SRC - [5:4] */
+#define ARIZONA_MICD_DBTIME                      0x0002  /* MICD_DBTIME */
+#define ARIZONA_MICD_DBTIME_MASK                 0x0002  /* MICD_DBTIME */
+#define ARIZONA_MICD_DBTIME_SHIFT                     1  /* MICD_DBTIME */
+#define ARIZONA_MICD_DBTIME_WIDTH                     1  /* MICD_DBTIME */
+#define ARIZONA_MICD_ENA                         0x0001  /* MICD_ENA */
+#define ARIZONA_MICD_ENA_MASK                    0x0001  /* MICD_ENA */
+#define ARIZONA_MICD_ENA_SHIFT                        0  /* MICD_ENA */
+#define ARIZONA_MICD_ENA_WIDTH                        1  /* MICD_ENA */
+
+/*
+ * R676 (0x2A4) - Mic Detect 2
+ */
+#define ARIZONA_MICD_LVL_SEL_MASK                0x00FF  /* MICD_LVL_SEL - [7:0] */
+#define ARIZONA_MICD_LVL_SEL_SHIFT                    0  /* MICD_LVL_SEL - [7:0] */
+#define ARIZONA_MICD_LVL_SEL_WIDTH                    8  /* MICD_LVL_SEL - [7:0] */
+
+/*
+ * R677 (0x2A5) - Mic Detect 3
+ */
+#define ARIZONA_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
+#define ARIZONA_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
+#define ARIZONA_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
+#define ARIZONA_MICD_VALID                       0x0002  /* MICD_VALID */
+#define ARIZONA_MICD_VALID_MASK                  0x0002  /* MICD_VALID */
+#define ARIZONA_MICD_VALID_SHIFT                      1  /* MICD_VALID */
+#define ARIZONA_MICD_VALID_WIDTH                      1  /* MICD_VALID */
+#define ARIZONA_MICD_STS                         0x0001  /* MICD_STS */
+#define ARIZONA_MICD_STS_MASK                    0x0001  /* MICD_STS */
+#define ARIZONA_MICD_STS_SHIFT                        0  /* MICD_STS */
+#define ARIZONA_MICD_STS_WIDTH                        1  /* MICD_STS */
+
+/*
+ * R707 (0x2C3) - Mic noise mix control 1
+ */
+#define ARIZONA_MICMUTE_RATE_MASK                0x7800  /* MICMUTE_RATE - [14:11] */
+#define ARIZONA_MICMUTE_RATE_SHIFT                   11  /* MICMUTE_RATE - [14:11] */
+#define ARIZONA_MICMUTE_RATE_WIDTH                    4  /* MICMUTE_RATE - [14:11] */
+#define ARIZONA_MICMUTE_MIX_ENA                  0x0040  /* MICMUTE_MIX_ENA */
+#define ARIZONA_MICMUTE_MIX_ENA_MASK             0x0040  /* MICMUTE_MIX_ENA */
+#define ARIZONA_MICMUTE_MIX_ENA_SHIFT                 6  /* MICMUTE_MIX_ENA */
+#define ARIZONA_MICMUTE_MIX_ENA_WIDTH                 1  /* MICMUTE_MIX_ENA */
+
+/*
+ * R715 (0x2CB) - Isolation control
+ */
+#define ARIZONA_ISOLATE_DCVDD1                   0x0001  /* ISOLATE_DCVDD1 */
+#define ARIZONA_ISOLATE_DCVDD1_MASK              0x0001  /* ISOLATE_DCVDD1 */
+#define ARIZONA_ISOLATE_DCVDD1_SHIFT                  0  /* ISOLATE_DCVDD1 */
+#define ARIZONA_ISOLATE_DCVDD1_WIDTH                  1  /* ISOLATE_DCVDD1 */
+
+/*
+ * R723 (0x2D3) - Jack detect analogue
+ */
+#define ARIZONA_JD2_ENA                          0x0002  /* JD2_ENA */
+#define ARIZONA_JD2_ENA_MASK                     0x0002  /* JD2_ENA */
+#define ARIZONA_JD2_ENA_SHIFT                         1  /* JD2_ENA */
+#define ARIZONA_JD2_ENA_WIDTH                         1  /* JD2_ENA */
+#define ARIZONA_JD1_ENA                          0x0001  /* JD1_ENA */
+#define ARIZONA_JD1_ENA_MASK                     0x0001  /* JD1_ENA */
+#define ARIZONA_JD1_ENA_SHIFT                         0  /* JD1_ENA */
+#define ARIZONA_JD1_ENA_WIDTH                         1  /* JD1_ENA */
+
+/*
+ * R768 (0x300) - Input Enables
+ */
+#define ARIZONA_IN4L_ENA                         0x0080  /* IN4L_ENA */
+#define ARIZONA_IN4L_ENA_MASK                    0x0080  /* IN4L_ENA */
+#define ARIZONA_IN4L_ENA_SHIFT                        7  /* IN4L_ENA */
+#define ARIZONA_IN4L_ENA_WIDTH                        1  /* IN4L_ENA */
+#define ARIZONA_IN4R_ENA                         0x0040  /* IN4R_ENA */
+#define ARIZONA_IN4R_ENA_MASK                    0x0040  /* IN4R_ENA */
+#define ARIZONA_IN4R_ENA_SHIFT                        6  /* IN4R_ENA */
+#define ARIZONA_IN4R_ENA_WIDTH                        1  /* IN4R_ENA */
+#define ARIZONA_IN3L_ENA                         0x0020  /* IN3L_ENA */
+#define ARIZONA_IN3L_ENA_MASK                    0x0020  /* IN3L_ENA */
+#define ARIZONA_IN3L_ENA_SHIFT                        5  /* IN3L_ENA */
+#define ARIZONA_IN3L_ENA_WIDTH                        1  /* IN3L_ENA */
+#define ARIZONA_IN3R_ENA                         0x0010  /* IN3R_ENA */
+#define ARIZONA_IN3R_ENA_MASK                    0x0010  /* IN3R_ENA */
+#define ARIZONA_IN3R_ENA_SHIFT                        4  /* IN3R_ENA */
+#define ARIZONA_IN3R_ENA_WIDTH                        1  /* IN3R_ENA */
+#define ARIZONA_IN2L_ENA                         0x0008  /* IN2L_ENA */
+#define ARIZONA_IN2L_ENA_MASK                    0x0008  /* IN2L_ENA */
+#define ARIZONA_IN2L_ENA_SHIFT                        3  /* IN2L_ENA */
+#define ARIZONA_IN2L_ENA_WIDTH                        1  /* IN2L_ENA */
+#define ARIZONA_IN2R_ENA                         0x0004  /* IN2R_ENA */
+#define ARIZONA_IN2R_ENA_MASK                    0x0004  /* IN2R_ENA */
+#define ARIZONA_IN2R_ENA_SHIFT                        2  /* IN2R_ENA */
+#define ARIZONA_IN2R_ENA_WIDTH                        1  /* IN2R_ENA */
+#define ARIZONA_IN1L_ENA                         0x0002  /* IN1L_ENA */
+#define ARIZONA_IN1L_ENA_MASK                    0x0002  /* IN1L_ENA */
+#define ARIZONA_IN1L_ENA_SHIFT                        1  /* IN1L_ENA */
+#define ARIZONA_IN1L_ENA_WIDTH                        1  /* IN1L_ENA */
+#define ARIZONA_IN1R_ENA                         0x0001  /* IN1R_ENA */
+#define ARIZONA_IN1R_ENA_MASK                    0x0001  /* IN1R_ENA */
+#define ARIZONA_IN1R_ENA_SHIFT                        0  /* IN1R_ENA */
+#define ARIZONA_IN1R_ENA_WIDTH                        1  /* IN1R_ENA */
+
+/*
+ * R776 (0x308) - Input Rate
+ */
+#define ARIZONA_IN_RATE_MASK                     0x7800  /* IN_RATE - [14:11] */
+#define ARIZONA_IN_RATE_SHIFT                        11  /* IN_RATE - [14:11] */
+#define ARIZONA_IN_RATE_WIDTH                         4  /* IN_RATE - [14:11] */
+
+/*
+ * R777 (0x309) - Input Volume Ramp
+ */
+#define ARIZONA_IN_VD_RAMP_MASK                  0x0070  /* IN_VD_RAMP - [6:4] */
+#define ARIZONA_IN_VD_RAMP_SHIFT                      4  /* IN_VD_RAMP - [6:4] */
+#define ARIZONA_IN_VD_RAMP_WIDTH                      3  /* IN_VD_RAMP - [6:4] */
+#define ARIZONA_IN_VI_RAMP_MASK                  0x0007  /* IN_VI_RAMP - [2:0] */
+#define ARIZONA_IN_VI_RAMP_SHIFT                      0  /* IN_VI_RAMP - [2:0] */
+#define ARIZONA_IN_VI_RAMP_WIDTH                      3  /* IN_VI_RAMP - [2:0] */
+
+/*
+ * R784 (0x310) - IN1L Control
+ */
+#define ARIZONA_IN1_OSR_MASK                     0x6000  /* IN1_OSR - [14:13] */
+#define ARIZONA_IN1_OSR_SHIFT                        13  /* IN1_OSR - [14:13] */
+#define ARIZONA_IN1_OSR_WIDTH                         2  /* IN1_OSR - [14:13] */
+#define ARIZONA_IN1_DMIC_SUP_MASK                0x1800  /* IN1_DMIC_SUP - [12:11] */
+#define ARIZONA_IN1_DMIC_SUP_SHIFT                   11  /* IN1_DMIC_SUP - [12:11] */
+#define ARIZONA_IN1_DMIC_SUP_WIDTH                    2  /* IN1_DMIC_SUP - [12:11] */
+#define ARIZONA_IN1_MODE_MASK                    0x0600  /* IN1_MODE - [10:9] */
+#define ARIZONA_IN1_MODE_SHIFT                        9  /* IN1_MODE - [10:9] */
+#define ARIZONA_IN1_MODE_WIDTH                        2  /* IN1_MODE - [10:9] */
+#define ARIZONA_IN1L_PGA_VOL_MASK                0x00FE  /* IN1L_PGA_VOL - [7:1] */
+#define ARIZONA_IN1L_PGA_VOL_SHIFT                    1  /* IN1L_PGA_VOL - [7:1] */
+#define ARIZONA_IN1L_PGA_VOL_WIDTH                    7  /* IN1L_PGA_VOL - [7:1] */
+
+/*
+ * R785 (0x311) - ADC Digital Volume 1L
+ */
+#define ARIZONA_IN_VU                            0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_MASK                       0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_SHIFT                           9  /* IN_VU */
+#define ARIZONA_IN_VU_WIDTH                           1  /* IN_VU */
+#define ARIZONA_IN1L_MUTE                        0x0100  /* IN1L_MUTE */
+#define ARIZONA_IN1L_MUTE_MASK                   0x0100  /* IN1L_MUTE */
+#define ARIZONA_IN1L_MUTE_SHIFT                       8  /* IN1L_MUTE */
+#define ARIZONA_IN1L_MUTE_WIDTH                       1  /* IN1L_MUTE */
+#define ARIZONA_IN1L_DIG_VOL_MASK                0x00FF  /* IN1L_DIG_VOL - [7:0] */
+#define ARIZONA_IN1L_DIG_VOL_SHIFT                    0  /* IN1L_DIG_VOL - [7:0] */
+#define ARIZONA_IN1L_DIG_VOL_WIDTH                    8  /* IN1L_DIG_VOL - [7:0] */
+
+/*
+ * R786 (0x312) - DMIC1L Control
+ */
+#define ARIZONA_IN1_DMICL_DLY_MASK               0x003F  /* IN1_DMICL_DLY - [5:0] */
+#define ARIZONA_IN1_DMICL_DLY_SHIFT                   0  /* IN1_DMICL_DLY - [5:0] */
+#define ARIZONA_IN1_DMICL_DLY_WIDTH                   6  /* IN1_DMICL_DLY - [5:0] */
+
+/*
+ * R788 (0x314) - IN1R Control
+ */
+#define ARIZONA_IN1R_PGA_VOL_MASK                0x00FE  /* IN1R_PGA_VOL - [7:1] */
+#define ARIZONA_IN1R_PGA_VOL_SHIFT                    1  /* IN1R_PGA_VOL - [7:1] */
+#define ARIZONA_IN1R_PGA_VOL_WIDTH                    7  /* IN1R_PGA_VOL - [7:1] */
+
+/*
+ * R789 (0x315) - ADC Digital Volume 1R
+ */
+#define ARIZONA_IN_VU                            0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_MASK                       0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_SHIFT                           9  /* IN_VU */
+#define ARIZONA_IN_VU_WIDTH                           1  /* IN_VU */
+#define ARIZONA_IN1R_MUTE                        0x0100  /* IN1R_MUTE */
+#define ARIZONA_IN1R_MUTE_MASK                   0x0100  /* IN1R_MUTE */
+#define ARIZONA_IN1R_MUTE_SHIFT                       8  /* IN1R_MUTE */
+#define ARIZONA_IN1R_MUTE_WIDTH                       1  /* IN1R_MUTE */
+#define ARIZONA_IN1R_DIG_VOL_MASK                0x00FF  /* IN1R_DIG_VOL - [7:0] */
+#define ARIZONA_IN1R_DIG_VOL_SHIFT                    0  /* IN1R_DIG_VOL - [7:0] */
+#define ARIZONA_IN1R_DIG_VOL_WIDTH                    8  /* IN1R_DIG_VOL - [7:0] */
+
+/*
+ * R790 (0x316) - DMIC1R Control
+ */
+#define ARIZONA_IN1_DMICR_DLY_MASK               0x003F  /* IN1_DMICR_DLY - [5:0] */
+#define ARIZONA_IN1_DMICR_DLY_SHIFT                   0  /* IN1_DMICR_DLY - [5:0] */
+#define ARIZONA_IN1_DMICR_DLY_WIDTH                   6  /* IN1_DMICR_DLY - [5:0] */
+
+/*
+ * R792 (0x318) - IN2L Control
+ */
+#define ARIZONA_IN2_OSR_MASK                     0x6000  /* IN2_OSR - [14:13] */
+#define ARIZONA_IN2_OSR_SHIFT                        13  /* IN2_OSR - [14:13] */
+#define ARIZONA_IN2_OSR_WIDTH                         2  /* IN2_OSR - [14:13] */
+#define ARIZONA_IN2_DMIC_SUP_MASK                0x1800  /* IN2_DMIC_SUP - [12:11] */
+#define ARIZONA_IN2_DMIC_SUP_SHIFT                   11  /* IN2_DMIC_SUP - [12:11] */
+#define ARIZONA_IN2_DMIC_SUP_WIDTH                    2  /* IN2_DMIC_SUP - [12:11] */
+#define ARIZONA_IN2_MODE_MASK                    0x0600  /* IN2_MODE - [10:9] */
+#define ARIZONA_IN2_MODE_SHIFT                        9  /* IN2_MODE - [10:9] */
+#define ARIZONA_IN2_MODE_WIDTH                        2  /* IN2_MODE - [10:9] */
+#define ARIZONA_IN2L_PGA_VOL_MASK                0x00FE  /* IN2L_PGA_VOL - [7:1] */
+#define ARIZONA_IN2L_PGA_VOL_SHIFT                    1  /* IN2L_PGA_VOL - [7:1] */
+#define ARIZONA_IN2L_PGA_VOL_WIDTH                    7  /* IN2L_PGA_VOL - [7:1] */
+
+/*
+ * R793 (0x319) - ADC Digital Volume 2L
+ */
+#define ARIZONA_IN_VU                            0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_MASK                       0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_SHIFT                           9  /* IN_VU */
+#define ARIZONA_IN_VU_WIDTH                           1  /* IN_VU */
+#define ARIZONA_IN2L_MUTE                        0x0100  /* IN2L_MUTE */
+#define ARIZONA_IN2L_MUTE_MASK                   0x0100  /* IN2L_MUTE */
+#define ARIZONA_IN2L_MUTE_SHIFT                       8  /* IN2L_MUTE */
+#define ARIZONA_IN2L_MUTE_WIDTH                       1  /* IN2L_MUTE */
+#define ARIZONA_IN2L_DIG_VOL_MASK                0x00FF  /* IN2L_DIG_VOL - [7:0] */
+#define ARIZONA_IN2L_DIG_VOL_SHIFT                    0  /* IN2L_DIG_VOL - [7:0] */
+#define ARIZONA_IN2L_DIG_VOL_WIDTH                    8  /* IN2L_DIG_VOL - [7:0] */
+
+/*
+ * R794 (0x31A) - DMIC2L Control
+ */
+#define ARIZONA_IN2_DMICL_DLY_MASK               0x003F  /* IN2_DMICL_DLY - [5:0] */
+#define ARIZONA_IN2_DMICL_DLY_SHIFT                   0  /* IN2_DMICL_DLY - [5:0] */
+#define ARIZONA_IN2_DMICL_DLY_WIDTH                   6  /* IN2_DMICL_DLY - [5:0] */
+
+/*
+ * R796 (0x31C) - IN2R Control
+ */
+#define ARIZONA_IN2R_PGA_VOL_MASK                0x00FE  /* IN2R_PGA_VOL - [7:1] */
+#define ARIZONA_IN2R_PGA_VOL_SHIFT                    1  /* IN2R_PGA_VOL - [7:1] */
+#define ARIZONA_IN2R_PGA_VOL_WIDTH                    7  /* IN2R_PGA_VOL - [7:1] */
+
+/*
+ * R797 (0x31D) - ADC Digital Volume 2R
+ */
+#define ARIZONA_IN_VU                            0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_MASK                       0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_SHIFT                           9  /* IN_VU */
+#define ARIZONA_IN_VU_WIDTH                           1  /* IN_VU */
+#define ARIZONA_IN2R_MUTE                        0x0100  /* IN2R_MUTE */
+#define ARIZONA_IN2R_MUTE_MASK                   0x0100  /* IN2R_MUTE */
+#define ARIZONA_IN2R_MUTE_SHIFT                       8  /* IN2R_MUTE */
+#define ARIZONA_IN2R_MUTE_WIDTH                       1  /* IN2R_MUTE */
+#define ARIZONA_IN2R_DIG_VOL_MASK                0x00FF  /* IN2R_DIG_VOL - [7:0] */
+#define ARIZONA_IN2R_DIG_VOL_SHIFT                    0  /* IN2R_DIG_VOL - [7:0] */
+#define ARIZONA_IN2R_DIG_VOL_WIDTH                    8  /* IN2R_DIG_VOL - [7:0] */
+
+/*
+ * R798 (0x31E) - DMIC2R Control
+ */
+#define ARIZONA_IN2_DMICR_DLY_MASK               0x003F  /* IN2_DMICR_DLY - [5:0] */
+#define ARIZONA_IN2_DMICR_DLY_SHIFT                   0  /* IN2_DMICR_DLY - [5:0] */
+#define ARIZONA_IN2_DMICR_DLY_WIDTH                   6  /* IN2_DMICR_DLY - [5:0] */
+
+/*
+ * R800 (0x320) - IN3L Control
+ */
+#define ARIZONA_IN3_OSR_MASK                     0x6000  /* IN3_OSR - [14:13] */
+#define ARIZONA_IN3_OSR_SHIFT                        13  /* IN3_OSR - [14:13] */
+#define ARIZONA_IN3_OSR_WIDTH                         2  /* IN3_OSR - [14:13] */
+#define ARIZONA_IN3_DMIC_SUP_MASK                0x1800  /* IN3_DMIC_SUP - [12:11] */
+#define ARIZONA_IN3_DMIC_SUP_SHIFT                   11  /* IN3_DMIC_SUP - [12:11] */
+#define ARIZONA_IN3_DMIC_SUP_WIDTH                    2  /* IN3_DMIC_SUP - [12:11] */
+#define ARIZONA_IN3_MODE_MASK                    0x0600  /* IN3_MODE - [10:9] */
+#define ARIZONA_IN3_MODE_SHIFT                        9  /* IN3_MODE - [10:9] */
+#define ARIZONA_IN3_MODE_WIDTH                        2  /* IN3_MODE - [10:9] */
+#define ARIZONA_IN3L_PGA_VOL_MASK                0x00FE  /* IN3L_PGA_VOL - [7:1] */
+#define ARIZONA_IN3L_PGA_VOL_SHIFT                    1  /* IN3L_PGA_VOL - [7:1] */
+#define ARIZONA_IN3L_PGA_VOL_WIDTH                    7  /* IN3L_PGA_VOL - [7:1] */
+
+/*
+ * R801 (0x321) - ADC Digital Volume 3L
+ */
+#define ARIZONA_IN_VU                            0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_MASK                       0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_SHIFT                           9  /* IN_VU */
+#define ARIZONA_IN_VU_WIDTH                           1  /* IN_VU */
+#define ARIZONA_IN3L_MUTE                        0x0100  /* IN3L_MUTE */
+#define ARIZONA_IN3L_MUTE_MASK                   0x0100  /* IN3L_MUTE */
+#define ARIZONA_IN3L_MUTE_SHIFT                       8  /* IN3L_MUTE */
+#define ARIZONA_IN3L_MUTE_WIDTH                       1  /* IN3L_MUTE */
+#define ARIZONA_IN3L_DIG_VOL_MASK                0x00FF  /* IN3L_DIG_VOL - [7:0] */
+#define ARIZONA_IN3L_DIG_VOL_SHIFT                    0  /* IN3L_DIG_VOL - [7:0] */
+#define ARIZONA_IN3L_DIG_VOL_WIDTH                    8  /* IN3L_DIG_VOL - [7:0] */
+
+/*
+ * R802 (0x322) - DMIC3L Control
+ */
+#define ARIZONA_IN3_DMICL_DLY_MASK               0x003F  /* IN3_DMICL_DLY - [5:0] */
+#define ARIZONA_IN3_DMICL_DLY_SHIFT                   0  /* IN3_DMICL_DLY - [5:0] */
+#define ARIZONA_IN3_DMICL_DLY_WIDTH                   6  /* IN3_DMICL_DLY - [5:0] */
+
+/*
+ * R804 (0x324) - IN3R Control
+ */
+#define ARIZONA_IN3R_PGA_VOL_MASK                0x00FE  /* IN3R_PGA_VOL - [7:1] */
+#define ARIZONA_IN3R_PGA_VOL_SHIFT                    1  /* IN3R_PGA_VOL - [7:1] */
+#define ARIZONA_IN3R_PGA_VOL_WIDTH                    7  /* IN3R_PGA_VOL - [7:1] */
+
+/*
+ * R805 (0x325) - ADC Digital Volume 3R
+ */
+#define ARIZONA_IN_VU                            0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_MASK                       0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_SHIFT                           9  /* IN_VU */
+#define ARIZONA_IN_VU_WIDTH                           1  /* IN_VU */
+#define ARIZONA_IN3R_MUTE                        0x0100  /* IN3R_MUTE */
+#define ARIZONA_IN3R_MUTE_MASK                   0x0100  /* IN3R_MUTE */
+#define ARIZONA_IN3R_MUTE_SHIFT                       8  /* IN3R_MUTE */
+#define ARIZONA_IN3R_MUTE_WIDTH                       1  /* IN3R_MUTE */
+#define ARIZONA_IN3R_DIG_VOL_MASK                0x00FF  /* IN3R_DIG_VOL - [7:0] */
+#define ARIZONA_IN3R_DIG_VOL_SHIFT                    0  /* IN3R_DIG_VOL - [7:0] */
+#define ARIZONA_IN3R_DIG_VOL_WIDTH                    8  /* IN3R_DIG_VOL - [7:0] */
+
+/*
+ * R806 (0x326) - DMIC3R Control
+ */
+#define ARIZONA_IN3_DMICR_DLY_MASK               0x003F  /* IN3_DMICR_DLY - [5:0] */
+#define ARIZONA_IN3_DMICR_DLY_SHIFT                   0  /* IN3_DMICR_DLY - [5:0] */
+#define ARIZONA_IN3_DMICR_DLY_WIDTH                   6  /* IN3_DMICR_DLY - [5:0] */
+
+/*
+ * R808 (0x328) - IN4 Control
+ */
+#define ARIZONA_IN4_OSR_MASK                     0x6000  /* IN4_OSR - [14:13] */
+#define ARIZONA_IN4_OSR_SHIFT                        13  /* IN4_OSR - [14:13] */
+#define ARIZONA_IN4_OSR_WIDTH                         2  /* IN4_OSR - [14:13] */
+#define ARIZONA_IN4_DMIC_SUP_MASK                0x1800  /* IN4_DMIC_SUP - [12:11] */
+#define ARIZONA_IN4_DMIC_SUP_SHIFT                   11  /* IN4_DMIC_SUP - [12:11] */
+#define ARIZONA_IN4_DMIC_SUP_WIDTH                    2  /* IN4_DMIC_SUP - [12:11] */
+
+/*
+ * R809 (0x329) - ADC Digital Volume 4L
+ */
+#define ARIZONA_IN_VU                            0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_MASK                       0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_SHIFT                           9  /* IN_VU */
+#define ARIZONA_IN_VU_WIDTH                           1  /* IN_VU */
+#define ARIZONA_IN4L_MUTE                        0x0100  /* IN4L_MUTE */
+#define ARIZONA_IN4L_MUTE_MASK                   0x0100  /* IN4L_MUTE */
+#define ARIZONA_IN4L_MUTE_SHIFT                       8  /* IN4L_MUTE */
+#define ARIZONA_IN4L_MUTE_WIDTH                       1  /* IN4L_MUTE */
+#define ARIZONA_IN4L_DIG_VOL_MASK                0x00FF  /* IN4L_DIG_VOL - [7:0] */
+#define ARIZONA_IN4L_DIG_VOL_SHIFT                    0  /* IN4L_DIG_VOL - [7:0] */
+#define ARIZONA_IN4L_DIG_VOL_WIDTH                    8  /* IN4L_DIG_VOL - [7:0] */
+
+/*
+ * R810 (0x32A) - DMIC4L Control
+ */
+#define ARIZONA_IN4L_DMIC_DLY_MASK               0x003F  /* IN4L_DMIC_DLY - [5:0] */
+#define ARIZONA_IN4L_DMIC_DLY_SHIFT                   0  /* IN4L_DMIC_DLY - [5:0] */
+#define ARIZONA_IN4L_DMIC_DLY_WIDTH                   6  /* IN4L_DMIC_DLY - [5:0] */
+
+/*
+ * R813 (0x32D) - ADC Digital Volume 4R
+ */
+#define ARIZONA_IN_VU                            0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_MASK                       0x0200  /* IN_VU */
+#define ARIZONA_IN_VU_SHIFT                           9  /* IN_VU */
+#define ARIZONA_IN_VU_WIDTH                           1  /* IN_VU */
+#define ARIZONA_IN4R_MUTE                        0x0100  /* IN4R_MUTE */
+#define ARIZONA_IN4R_MUTE_MASK                   0x0100  /* IN4R_MUTE */
+#define ARIZONA_IN4R_MUTE_SHIFT                       8  /* IN4R_MUTE */
+#define ARIZONA_IN4R_MUTE_WIDTH                       1  /* IN4R_MUTE */
+#define ARIZONA_IN4R_DIG_VOL_MASK                0x00FF  /* IN4R_DIG_VOL - [7:0] */
+#define ARIZONA_IN4R_DIG_VOL_SHIFT                    0  /* IN4R_DIG_VOL - [7:0] */
+#define ARIZONA_IN4R_DIG_VOL_WIDTH                    8  /* IN4R_DIG_VOL - [7:0] */
+
+/*
+ * R814 (0x32E) - DMIC4R Control
+ */
+#define ARIZONA_IN4R_DMIC_DLY_MASK               0x003F  /* IN4R_DMIC_DLY - [5:0] */
+#define ARIZONA_IN4R_DMIC_DLY_SHIFT                   0  /* IN4R_DMIC_DLY - [5:0] */
+#define ARIZONA_IN4R_DMIC_DLY_WIDTH                   6  /* IN4R_DMIC_DLY - [5:0] */
+
+/*
+ * R1024 (0x400) - Output Enables 1
+ */
+#define ARIZONA_OUT6L_ENA                        0x0800  /* OUT6L_ENA */
+#define ARIZONA_OUT6L_ENA_MASK                   0x0800  /* OUT6L_ENA */
+#define ARIZONA_OUT6L_ENA_SHIFT                      11  /* OUT6L_ENA */
+#define ARIZONA_OUT6L_ENA_WIDTH                       1  /* OUT6L_ENA */
+#define ARIZONA_OUT6R_ENA                        0x0400  /* OUT6R_ENA */
+#define ARIZONA_OUT6R_ENA_MASK                   0x0400  /* OUT6R_ENA */
+#define ARIZONA_OUT6R_ENA_SHIFT                      10  /* OUT6R_ENA */
+#define ARIZONA_OUT6R_ENA_WIDTH                       1  /* OUT6R_ENA */
+#define ARIZONA_OUT5L_ENA                        0x0200  /* OUT5L_ENA */
+#define ARIZONA_OUT5L_ENA_MASK                   0x0200  /* OUT5L_ENA */
+#define ARIZONA_OUT5L_ENA_SHIFT                       9  /* OUT5L_ENA */
+#define ARIZONA_OUT5L_ENA_WIDTH                       1  /* OUT5L_ENA */
+#define ARIZONA_OUT5R_ENA                        0x0100  /* OUT5R_ENA */
+#define ARIZONA_OUT5R_ENA_MASK                   0x0100  /* OUT5R_ENA */
+#define ARIZONA_OUT5R_ENA_SHIFT                       8  /* OUT5R_ENA */
+#define ARIZONA_OUT5R_ENA_WIDTH                       1  /* OUT5R_ENA */
+#define ARIZONA_OUT4L_ENA                        0x0080  /* OUT4L_ENA */
+#define ARIZONA_OUT4L_ENA_MASK                   0x0080  /* OUT4L_ENA */
+#define ARIZONA_OUT4L_ENA_SHIFT                       7  /* OUT4L_ENA */
+#define ARIZONA_OUT4L_ENA_WIDTH                       1  /* OUT4L_ENA */
+#define ARIZONA_OUT4R_ENA                        0x0040  /* OUT4R_ENA */
+#define ARIZONA_OUT4R_ENA_MASK                   0x0040  /* OUT4R_ENA */
+#define ARIZONA_OUT4R_ENA_SHIFT                       6  /* OUT4R_ENA */
+#define ARIZONA_OUT4R_ENA_WIDTH                       1  /* OUT4R_ENA */
+#define ARIZONA_OUT3L_ENA                        0x0020  /* OUT3L_ENA */
+#define ARIZONA_OUT3L_ENA_MASK                   0x0020  /* OUT3L_ENA */
+#define ARIZONA_OUT3L_ENA_SHIFT                       5  /* OUT3L_ENA */
+#define ARIZONA_OUT3L_ENA_WIDTH                       1  /* OUT3L_ENA */
+#define ARIZONA_OUT3R_ENA                        0x0010  /* OUT3R_ENA */
+#define ARIZONA_OUT3R_ENA_MASK                   0x0010  /* OUT3R_ENA */
+#define ARIZONA_OUT3R_ENA_SHIFT                       4  /* OUT3R_ENA */
+#define ARIZONA_OUT3R_ENA_WIDTH                       1  /* OUT3R_ENA */
+#define ARIZONA_OUT2L_ENA                        0x0008  /* OUT2L_ENA */
+#define ARIZONA_OUT2L_ENA_MASK                   0x0008  /* OUT2L_ENA */
+#define ARIZONA_OUT2L_ENA_SHIFT                       3  /* OUT2L_ENA */
+#define ARIZONA_OUT2L_ENA_WIDTH                       1  /* OUT2L_ENA */
+#define ARIZONA_OUT2R_ENA                        0x0004  /* OUT2R_ENA */
+#define ARIZONA_OUT2R_ENA_MASK                   0x0004  /* OUT2R_ENA */
+#define ARIZONA_OUT2R_ENA_SHIFT                       2  /* OUT2R_ENA */
+#define ARIZONA_OUT2R_ENA_WIDTH                       1  /* OUT2R_ENA */
+#define ARIZONA_OUT1L_ENA                        0x0002  /* OUT1L_ENA */
+#define ARIZONA_OUT1L_ENA_MASK                   0x0002  /* OUT1L_ENA */
+#define ARIZONA_OUT1L_ENA_SHIFT                       1  /* OUT1L_ENA */
+#define ARIZONA_OUT1L_ENA_WIDTH                       1  /* OUT1L_ENA */
+#define ARIZONA_OUT1R_ENA                        0x0001  /* OUT1R_ENA */
+#define ARIZONA_OUT1R_ENA_MASK                   0x0001  /* OUT1R_ENA */
+#define ARIZONA_OUT1R_ENA_SHIFT                       0  /* OUT1R_ENA */
+#define ARIZONA_OUT1R_ENA_WIDTH                       1  /* OUT1R_ENA */
+
+/*
+ * R1025 (0x401) - Output Status 1
+ */
+#define ARIZONA_OUT6L_ENA_STS                    0x0800  /* OUT6L_ENA_STS */
+#define ARIZONA_OUT6L_ENA_STS_MASK               0x0800  /* OUT6L_ENA_STS */
+#define ARIZONA_OUT6L_ENA_STS_SHIFT                  11  /* OUT6L_ENA_STS */
+#define ARIZONA_OUT6L_ENA_STS_WIDTH                   1  /* OUT6L_ENA_STS */
+#define ARIZONA_OUT6R_ENA_STS                    0x0400  /* OUT6R_ENA_STS */
+#define ARIZONA_OUT6R_ENA_STS_MASK               0x0400  /* OUT6R_ENA_STS */
+#define ARIZONA_OUT6R_ENA_STS_SHIFT                  10  /* OUT6R_ENA_STS */
+#define ARIZONA_OUT6R_ENA_STS_WIDTH                   1  /* OUT6R_ENA_STS */
+#define ARIZONA_OUT5L_ENA_STS                    0x0200  /* OUT5L_ENA_STS */
+#define ARIZONA_OUT5L_ENA_STS_MASK               0x0200  /* OUT5L_ENA_STS */
+#define ARIZONA_OUT5L_ENA_STS_SHIFT                   9  /* OUT5L_ENA_STS */
+#define ARIZONA_OUT5L_ENA_STS_WIDTH                   1  /* OUT5L_ENA_STS */
+#define ARIZONA_OUT5R_ENA_STS                    0x0100  /* OUT5R_ENA_STS */
+#define ARIZONA_OUT5R_ENA_STS_MASK               0x0100  /* OUT5R_ENA_STS */
+#define ARIZONA_OUT5R_ENA_STS_SHIFT                   8  /* OUT5R_ENA_STS */
+#define ARIZONA_OUT5R_ENA_STS_WIDTH                   1  /* OUT5R_ENA_STS */
+#define ARIZONA_OUT4L_ENA_STS                    0x0080  /* OUT4L_ENA_STS */
+#define ARIZONA_OUT4L_ENA_STS_MASK               0x0080  /* OUT4L_ENA_STS */
+#define ARIZONA_OUT4L_ENA_STS_SHIFT                   7  /* OUT4L_ENA_STS */
+#define ARIZONA_OUT4L_ENA_STS_WIDTH                   1  /* OUT4L_ENA_STS */
+#define ARIZONA_OUT4R_ENA_STS                    0x0040  /* OUT4R_ENA_STS */
+#define ARIZONA_OUT4R_ENA_STS_MASK               0x0040  /* OUT4R_ENA_STS */
+#define ARIZONA_OUT4R_ENA_STS_SHIFT                   6  /* OUT4R_ENA_STS */
+#define ARIZONA_OUT4R_ENA_STS_WIDTH                   1  /* OUT4R_ENA_STS */
+
+/*
+ * R1032 (0x408) - Output Rate 1
+ */
+#define ARIZONA_OUT_RATE_MASK                    0x7800  /* OUT_RATE - [14:11] */
+#define ARIZONA_OUT_RATE_SHIFT                       11  /* OUT_RATE - [14:11] */
+#define ARIZONA_OUT_RATE_WIDTH                        4  /* OUT_RATE - [14:11] */
+
+/*
+ * R1033 (0x409) - Output Volume Ramp
+ */
+#define ARIZONA_OUT_VD_RAMP_MASK                 0x0070  /* OUT_VD_RAMP - [6:4] */
+#define ARIZONA_OUT_VD_RAMP_SHIFT                     4  /* OUT_VD_RAMP - [6:4] */
+#define ARIZONA_OUT_VD_RAMP_WIDTH                     3  /* OUT_VD_RAMP - [6:4] */
+#define ARIZONA_OUT_VI_RAMP_MASK                 0x0007  /* OUT_VI_RAMP - [2:0] */
+#define ARIZONA_OUT_VI_RAMP_SHIFT                     0  /* OUT_VI_RAMP - [2:0] */
+#define ARIZONA_OUT_VI_RAMP_WIDTH                     3  /* OUT_VI_RAMP - [2:0] */
+
+/*
+ * R1040 (0x410) - Output Path Config 1L
+ */
+#define ARIZONA_OUT1_LP_MODE                     0x8000  /* OUT1_LP_MODE */
+#define ARIZONA_OUT1_LP_MODE_MASK                0x8000  /* OUT1_LP_MODE */
+#define ARIZONA_OUT1_LP_MODE_SHIFT                   15  /* OUT1_LP_MODE */
+#define ARIZONA_OUT1_LP_MODE_WIDTH                    1  /* OUT1_LP_MODE */
+#define ARIZONA_OUT1_OSR                         0x2000  /* OUT1_OSR */
+#define ARIZONA_OUT1_OSR_MASK                    0x2000  /* OUT1_OSR */
+#define ARIZONA_OUT1_OSR_SHIFT                       13  /* OUT1_OSR */
+#define ARIZONA_OUT1_OSR_WIDTH                        1  /* OUT1_OSR */
+#define ARIZONA_OUT1_MONO                        0x1000  /* OUT1_MONO */
+#define ARIZONA_OUT1_MONO_MASK                   0x1000  /* OUT1_MONO */
+#define ARIZONA_OUT1_MONO_SHIFT                      12  /* OUT1_MONO */
+#define ARIZONA_OUT1_MONO_WIDTH                       1  /* OUT1_MONO */
+#define ARIZONA_OUT1L_ANC_SRC_MASK               0x0C00  /* OUT1L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT1L_ANC_SRC_SHIFT                  10  /* OUT1L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT1L_ANC_SRC_WIDTH                   2  /* OUT1L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT1L_PGA_VOL_MASK               0x00FE  /* OUT1L_PGA_VOL - [7:1] */
+#define ARIZONA_OUT1L_PGA_VOL_SHIFT                   1  /* OUT1L_PGA_VOL - [7:1] */
+#define ARIZONA_OUT1L_PGA_VOL_WIDTH                   7  /* OUT1L_PGA_VOL - [7:1] */
+
+/*
+ * R1041 (0x411) - DAC Digital Volume 1L
+ */
+#define ARIZONA_OUT_VU                           0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define ARIZONA_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define ARIZONA_OUT1L_MUTE                       0x0100  /* OUT1L_MUTE */
+#define ARIZONA_OUT1L_MUTE_MASK                  0x0100  /* OUT1L_MUTE */
+#define ARIZONA_OUT1L_MUTE_SHIFT                      8  /* OUT1L_MUTE */
+#define ARIZONA_OUT1L_MUTE_WIDTH                      1  /* OUT1L_MUTE */
+#define ARIZONA_OUT1L_VOL_MASK                   0x00FF  /* OUT1L_VOL - [7:0] */
+#define ARIZONA_OUT1L_VOL_SHIFT                       0  /* OUT1L_VOL - [7:0] */
+#define ARIZONA_OUT1L_VOL_WIDTH                       8  /* OUT1L_VOL - [7:0] */
+
+/*
+ * R1042 (0x412) - DAC Volume Limit 1L
+ */
+#define ARIZONA_OUT1L_VOL_LIM_MASK               0x00FF  /* OUT1L_VOL_LIM - [7:0] */
+#define ARIZONA_OUT1L_VOL_LIM_SHIFT                   0  /* OUT1L_VOL_LIM - [7:0] */
+#define ARIZONA_OUT1L_VOL_LIM_WIDTH                   8  /* OUT1L_VOL_LIM - [7:0] */
+
+/*
+ * R1043 (0x413) - Noise Gate Select 1L
+ */
+#define ARIZONA_OUT1L_NGATE_SRC_MASK             0x0FFF  /* OUT1L_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT1L_NGATE_SRC_SHIFT                 0  /* OUT1L_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT1L_NGATE_SRC_WIDTH                12  /* OUT1L_NGATE_SRC - [11:0] */
+
+/*
+ * R1044 (0x414) - Output Path Config 1R
+ */
+#define ARIZONA_OUT1R_ANC_SRC_MASK               0x0C00  /* OUT1R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT1R_ANC_SRC_SHIFT                  10  /* OUT1R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT1R_ANC_SRC_WIDTH                   2  /* OUT1R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT1R_PGA_VOL_MASK               0x00FE  /* OUT1R_PGA_VOL - [7:1] */
+#define ARIZONA_OUT1R_PGA_VOL_SHIFT                   1  /* OUT1R_PGA_VOL - [7:1] */
+#define ARIZONA_OUT1R_PGA_VOL_WIDTH                   7  /* OUT1R_PGA_VOL - [7:1] */
+
+/*
+ * R1045 (0x415) - DAC Digital Volume 1R
+ */
+#define ARIZONA_OUT_VU                           0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define ARIZONA_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define ARIZONA_OUT1R_MUTE                       0x0100  /* OUT1R_MUTE */
+#define ARIZONA_OUT1R_MUTE_MASK                  0x0100  /* OUT1R_MUTE */
+#define ARIZONA_OUT1R_MUTE_SHIFT                      8  /* OUT1R_MUTE */
+#define ARIZONA_OUT1R_MUTE_WIDTH                      1  /* OUT1R_MUTE */
+#define ARIZONA_OUT1R_VOL_MASK                   0x00FF  /* OUT1R_VOL - [7:0] */
+#define ARIZONA_OUT1R_VOL_SHIFT                       0  /* OUT1R_VOL - [7:0] */
+#define ARIZONA_OUT1R_VOL_WIDTH                       8  /* OUT1R_VOL - [7:0] */
+
+/*
+ * R1046 (0x416) - DAC Volume Limit 1R
+ */
+#define ARIZONA_OUT1R_VOL_LIM_MASK               0x00FF  /* OUT1R_VOL_LIM - [7:0] */
+#define ARIZONA_OUT1R_VOL_LIM_SHIFT                   0  /* OUT1R_VOL_LIM - [7:0] */
+#define ARIZONA_OUT1R_VOL_LIM_WIDTH                   8  /* OUT1R_VOL_LIM - [7:0] */
+
+/*
+ * R1047 (0x417) - Noise Gate Select 1R
+ */
+#define ARIZONA_OUT1R_NGATE_SRC_MASK             0x0FFF  /* OUT1R_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT1R_NGATE_SRC_SHIFT                 0  /* OUT1R_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT1R_NGATE_SRC_WIDTH                12  /* OUT1R_NGATE_SRC - [11:0] */
+
+/*
+ * R1048 (0x418) - Output Path Config 2L
+ */
+#define ARIZONA_OUT2_LP_MODE                     0x8000  /* OUT2_LP_MODE */
+#define ARIZONA_OUT2_LP_MODE_MASK                0x8000  /* OUT2_LP_MODE */
+#define ARIZONA_OUT2_LP_MODE_SHIFT                   15  /* OUT2_LP_MODE */
+#define ARIZONA_OUT2_LP_MODE_WIDTH                    1  /* OUT2_LP_MODE */
+#define ARIZONA_OUT2_OSR                         0x2000  /* OUT2_OSR */
+#define ARIZONA_OUT2_OSR_MASK                    0x2000  /* OUT2_OSR */
+#define ARIZONA_OUT2_OSR_SHIFT                       13  /* OUT2_OSR */
+#define ARIZONA_OUT2_OSR_WIDTH                        1  /* OUT2_OSR */
+#define ARIZONA_OUT2_MONO                        0x1000  /* OUT2_MONO */
+#define ARIZONA_OUT2_MONO_MASK                   0x1000  /* OUT2_MONO */
+#define ARIZONA_OUT2_MONO_SHIFT                      12  /* OUT2_MONO */
+#define ARIZONA_OUT2_MONO_WIDTH                       1  /* OUT2_MONO */
+#define ARIZONA_OUT2L_ANC_SRC_MASK               0x0C00  /* OUT2L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT2L_ANC_SRC_SHIFT                  10  /* OUT2L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT2L_ANC_SRC_WIDTH                   2  /* OUT2L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT2L_PGA_VOL_MASK               0x00FE  /* OUT2L_PGA_VOL - [7:1] */
+#define ARIZONA_OUT2L_PGA_VOL_SHIFT                   1  /* OUT2L_PGA_VOL - [7:1] */
+#define ARIZONA_OUT2L_PGA_VOL_WIDTH                   7  /* OUT2L_PGA_VOL - [7:1] */
+
+/*
+ * R1049 (0x419) - DAC Digital Volume 2L
+ */
+#define ARIZONA_OUT_VU                           0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define ARIZONA_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define ARIZONA_OUT2L_MUTE                       0x0100  /* OUT2L_MUTE */
+#define ARIZONA_OUT2L_MUTE_MASK                  0x0100  /* OUT2L_MUTE */
+#define ARIZONA_OUT2L_MUTE_SHIFT                      8  /* OUT2L_MUTE */
+#define ARIZONA_OUT2L_MUTE_WIDTH                      1  /* OUT2L_MUTE */
+#define ARIZONA_OUT2L_VOL_MASK                   0x00FF  /* OUT2L_VOL - [7:0] */
+#define ARIZONA_OUT2L_VOL_SHIFT                       0  /* OUT2L_VOL - [7:0] */
+#define ARIZONA_OUT2L_VOL_WIDTH                       8  /* OUT2L_VOL - [7:0] */
+
+/*
+ * R1050 (0x41A) - DAC Volume Limit 2L
+ */
+#define ARIZONA_OUT2L_VOL_LIM_MASK               0x00FF  /* OUT2L_VOL_LIM - [7:0] */
+#define ARIZONA_OUT2L_VOL_LIM_SHIFT                   0  /* OUT2L_VOL_LIM - [7:0] */
+#define ARIZONA_OUT2L_VOL_LIM_WIDTH                   8  /* OUT2L_VOL_LIM - [7:0] */
+
+/*
+ * R1051 (0x41B) - Noise Gate Select 2L
+ */
+#define ARIZONA_OUT2L_NGATE_SRC_MASK             0x0FFF  /* OUT2L_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT2L_NGATE_SRC_SHIFT                 0  /* OUT2L_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT2L_NGATE_SRC_WIDTH                12  /* OUT2L_NGATE_SRC - [11:0] */
+
+/*
+ * R1052 (0x41C) - Output Path Config 2R
+ */
+#define ARIZONA_OUT2R_ANC_SRC_MASK               0x0C00  /* OUT2R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT2R_ANC_SRC_SHIFT                  10  /* OUT2R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT2R_ANC_SRC_WIDTH                   2  /* OUT2R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT2R_PGA_VOL_MASK               0x00FE  /* OUT2R_PGA_VOL - [7:1] */
+#define ARIZONA_OUT2R_PGA_VOL_SHIFT                   1  /* OUT2R_PGA_VOL - [7:1] */
+#define ARIZONA_OUT2R_PGA_VOL_WIDTH                   7  /* OUT2R_PGA_VOL - [7:1] */
+
+/*
+ * R1053 (0x41D) - DAC Digital Volume 2R
+ */
+#define ARIZONA_OUT_VU                           0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define ARIZONA_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define ARIZONA_OUT2R_MUTE                       0x0100  /* OUT2R_MUTE */
+#define ARIZONA_OUT2R_MUTE_MASK                  0x0100  /* OUT2R_MUTE */
+#define ARIZONA_OUT2R_MUTE_SHIFT                      8  /* OUT2R_MUTE */
+#define ARIZONA_OUT2R_MUTE_WIDTH                      1  /* OUT2R_MUTE */
+#define ARIZONA_OUT2R_VOL_MASK                   0x00FF  /* OUT2R_VOL - [7:0] */
+#define ARIZONA_OUT2R_VOL_SHIFT                       0  /* OUT2R_VOL - [7:0] */
+#define ARIZONA_OUT2R_VOL_WIDTH                       8  /* OUT2R_VOL - [7:0] */
+
+/*
+ * R1054 (0x41E) - DAC Volume Limit 2R
+ */
+#define ARIZONA_OUT2R_VOL_LIM_MASK               0x00FF  /* OUT2R_VOL_LIM - [7:0] */
+#define ARIZONA_OUT2R_VOL_LIM_SHIFT                   0  /* OUT2R_VOL_LIM - [7:0] */
+#define ARIZONA_OUT2R_VOL_LIM_WIDTH                   8  /* OUT2R_VOL_LIM - [7:0] */
+
+/*
+ * R1055 (0x41F) - Noise Gate Select 2R
+ */
+#define ARIZONA_OUT2R_NGATE_SRC_MASK             0x0FFF  /* OUT2R_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT2R_NGATE_SRC_SHIFT                 0  /* OUT2R_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT2R_NGATE_SRC_WIDTH                12  /* OUT2R_NGATE_SRC - [11:0] */
+
+/*
+ * R1056 (0x420) - Output Path Config 3L
+ */
+#define ARIZONA_OUT3_LP_MODE                     0x8000  /* OUT3_LP_MODE */
+#define ARIZONA_OUT3_LP_MODE_MASK                0x8000  /* OUT3_LP_MODE */
+#define ARIZONA_OUT3_LP_MODE_SHIFT                   15  /* OUT3_LP_MODE */
+#define ARIZONA_OUT3_LP_MODE_WIDTH                    1  /* OUT3_LP_MODE */
+#define ARIZONA_OUT3_OSR                         0x2000  /* OUT3_OSR */
+#define ARIZONA_OUT3_OSR_MASK                    0x2000  /* OUT3_OSR */
+#define ARIZONA_OUT3_OSR_SHIFT                       13  /* OUT3_OSR */
+#define ARIZONA_OUT3_OSR_WIDTH                        1  /* OUT3_OSR */
+#define ARIZONA_OUT3_MONO                        0x1000  /* OUT3_MONO */
+#define ARIZONA_OUT3_MONO_MASK                   0x1000  /* OUT3_MONO */
+#define ARIZONA_OUT3_MONO_SHIFT                      12  /* OUT3_MONO */
+#define ARIZONA_OUT3_MONO_WIDTH                       1  /* OUT3_MONO */
+#define ARIZONA_OUT3L_ANC_SRC_MASK               0x0C00  /* OUT3L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT3L_ANC_SRC_SHIFT                  10  /* OUT3L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT3L_ANC_SRC_WIDTH                   2  /* OUT3L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT3L_PGA_VOL_MASK               0x00FE  /* OUT3L_PGA_VOL - [7:1] */
+#define ARIZONA_OUT3L_PGA_VOL_SHIFT                   1  /* OUT3L_PGA_VOL - [7:1] */
+#define ARIZONA_OUT3L_PGA_VOL_WIDTH                   7  /* OUT3L_PGA_VOL - [7:1] */
+
+/*
+ * R1057 (0x421) - DAC Digital Volume 3L
+ */
+#define ARIZONA_OUT_VU                           0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define ARIZONA_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define ARIZONA_OUT3L_MUTE                       0x0100  /* OUT3L_MUTE */
+#define ARIZONA_OUT3L_MUTE_MASK                  0x0100  /* OUT3L_MUTE */
+#define ARIZONA_OUT3L_MUTE_SHIFT                      8  /* OUT3L_MUTE */
+#define ARIZONA_OUT3L_MUTE_WIDTH                      1  /* OUT3L_MUTE */
+#define ARIZONA_OUT3L_VOL_MASK                   0x00FF  /* OUT3L_VOL - [7:0] */
+#define ARIZONA_OUT3L_VOL_SHIFT                       0  /* OUT3L_VOL - [7:0] */
+#define ARIZONA_OUT3L_VOL_WIDTH                       8  /* OUT3L_VOL - [7:0] */
+
+/*
+ * R1058 (0x422) - DAC Volume Limit 3L
+ */
+#define ARIZONA_OUT3L_VOL_LIM_MASK               0x00FF  /* OUT3L_VOL_LIM - [7:0] */
+#define ARIZONA_OUT3L_VOL_LIM_SHIFT                   0  /* OUT3L_VOL_LIM - [7:0] */
+#define ARIZONA_OUT3L_VOL_LIM_WIDTH                   8  /* OUT3L_VOL_LIM - [7:0] */
+
+/*
+ * R1059 (0x423) - Noise Gate Select 3L
+ */
+#define ARIZONA_OUT3_NGATE_SRC_MASK              0x0FFF  /* OUT3_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT3_NGATE_SRC_SHIFT                  0  /* OUT3_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT3_NGATE_SRC_WIDTH                 12  /* OUT3_NGATE_SRC - [11:0] */
+
+/*
+ * R1060 (0x424) - Output Path Config 3R
+ */
+#define ARIZONA_OUT3R_PGA_VOL_MASK               0x00FE  /* OUT3R_PGA_VOL - [7:1] */
+#define ARIZONA_OUT3R_PGA_VOL_SHIFT                   1  /* OUT3R_PGA_VOL - [7:1] */
+#define ARIZONA_OUT3R_PGA_VOL_WIDTH                   7  /* OUT3R_PGA_VOL - [7:1] */
+
+/*
+ * R1061 (0x425) - DAC Digital Volume 3R
+ */
+#define ARIZONA_OUT_VU                           0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define ARIZONA_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define ARIZONA_OUT3R_MUTE                       0x0100  /* OUT3R_MUTE */
+#define ARIZONA_OUT3R_MUTE_MASK                  0x0100  /* OUT3R_MUTE */
+#define ARIZONA_OUT3R_MUTE_SHIFT                      8  /* OUT3R_MUTE */
+#define ARIZONA_OUT3R_MUTE_WIDTH                      1  /* OUT3R_MUTE */
+#define ARIZONA_OUT3R_VOL_MASK                   0x00FF  /* OUT3R_VOL - [7:0] */
+#define ARIZONA_OUT3R_VOL_SHIFT                       0  /* OUT3R_VOL - [7:0] */
+#define ARIZONA_OUT3R_VOL_WIDTH                       8  /* OUT3R_VOL - [7:0] */
+
+/*
+ * R1062 (0x426) - DAC Volume Limit 3R
+ */
+#define ARIZONA_OUT3R_ANC_SRC_MASK               0x0C00  /* OUT3R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT3R_ANC_SRC_SHIFT                  10  /* OUT3R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT3R_ANC_SRC_WIDTH                   2  /* OUT3R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT3R_VOL_LIM_MASK               0x00FF  /* OUT3R_VOL_LIM - [7:0] */
+#define ARIZONA_OUT3R_VOL_LIM_SHIFT                   0  /* OUT3R_VOL_LIM - [7:0] */
+#define ARIZONA_OUT3R_VOL_LIM_WIDTH                   8  /* OUT3R_VOL_LIM - [7:0] */
+
+/*
+ * R1064 (0x428) - Output Path Config 4L
+ */
+#define ARIZONA_OUT4_OSR                         0x2000  /* OUT4_OSR */
+#define ARIZONA_OUT4_OSR_MASK                    0x2000  /* OUT4_OSR */
+#define ARIZONA_OUT4_OSR_SHIFT                       13  /* OUT4_OSR */
+#define ARIZONA_OUT4_OSR_WIDTH                        1  /* OUT4_OSR */
+#define ARIZONA_OUT4L_ANC_SRC_MASK               0x0C00  /* OUT4L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT4L_ANC_SRC_SHIFT                  10  /* OUT4L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT4L_ANC_SRC_WIDTH                   2  /* OUT4L_ANC_SRC - [11:10] */
+
+/*
+ * R1065 (0x429) - DAC Digital Volume 4L
+ */
+#define ARIZONA_OUT_VU                           0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define ARIZONA_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define ARIZONA_OUT4L_MUTE                       0x0100  /* OUT4L_MUTE */
+#define ARIZONA_OUT4L_MUTE_MASK                  0x0100  /* OUT4L_MUTE */
+#define ARIZONA_OUT4L_MUTE_SHIFT                      8  /* OUT4L_MUTE */
+#define ARIZONA_OUT4L_MUTE_WIDTH                      1  /* OUT4L_MUTE */
+#define ARIZONA_OUT4L_VOL_MASK                   0x00FF  /* OUT4L_VOL - [7:0] */
+#define ARIZONA_OUT4L_VOL_SHIFT                       0  /* OUT4L_VOL - [7:0] */
+#define ARIZONA_OUT4L_VOL_WIDTH                       8  /* OUT4L_VOL - [7:0] */
+
+/*
+ * R1066 (0x42A) - Out Volume 4L
+ */
+#define ARIZONA_OUT4L_VOL_LIM_MASK               0x00FF  /* OUT4L_VOL_LIM - [7:0] */
+#define ARIZONA_OUT4L_VOL_LIM_SHIFT                   0  /* OUT4L_VOL_LIM - [7:0] */
+#define ARIZONA_OUT4L_VOL_LIM_WIDTH                   8  /* OUT4L_VOL_LIM - [7:0] */
+
+/*
+ * R1067 (0x42B) - Noise Gate Select 4L
+ */
+#define ARIZONA_OUT4L_NGATE_SRC_MASK             0x0FFF  /* OUT4L_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT4L_NGATE_SRC_SHIFT                 0  /* OUT4L_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT4L_NGATE_SRC_WIDTH                12  /* OUT4L_NGATE_SRC - [11:0] */
+
+/*
+ * R1068 (0x42C) - Output Path Config 4R
+ */
+#define ARIZONA_OUT4R_ANC_SRC_MASK               0x0C00  /* OUT4R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT4R_ANC_SRC_SHIFT                  10  /* OUT4R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT4R_ANC_SRC_WIDTH                   2  /* OUT4R_ANC_SRC - [11:10] */
+
+/*
+ * R1069 (0x42D) - DAC Digital Volume 4R
+ */
+#define ARIZONA_OUT_VU                           0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define ARIZONA_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define ARIZONA_OUT4R_MUTE                       0x0100  /* OUT4R_MUTE */
+#define ARIZONA_OUT4R_MUTE_MASK                  0x0100  /* OUT4R_MUTE */
+#define ARIZONA_OUT4R_MUTE_SHIFT                      8  /* OUT4R_MUTE */
+#define ARIZONA_OUT4R_MUTE_WIDTH                      1  /* OUT4R_MUTE */
+#define ARIZONA_OUT4R_VOL_MASK                   0x00FF  /* OUT4R_VOL - [7:0] */
+#define ARIZONA_OUT4R_VOL_SHIFT                       0  /* OUT4R_VOL - [7:0] */
+#define ARIZONA_OUT4R_VOL_WIDTH                       8  /* OUT4R_VOL - [7:0] */
+
+/*
+ * R1070 (0x42E) - Out Volume 4R
+ */
+#define ARIZONA_OUT4R_VOL_LIM_MASK               0x00FF  /* OUT4R_VOL_LIM - [7:0] */
+#define ARIZONA_OUT4R_VOL_LIM_SHIFT                   0  /* OUT4R_VOL_LIM - [7:0] */
+#define ARIZONA_OUT4R_VOL_LIM_WIDTH                   8  /* OUT4R_VOL_LIM - [7:0] */
+
+/*
+ * R1071 (0x42F) - Noise Gate Select 4R
+ */
+#define ARIZONA_OUT4R_NGATE_SRC_MASK             0x0FFF  /* OUT4R_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT4R_NGATE_SRC_SHIFT                 0  /* OUT4R_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT4R_NGATE_SRC_WIDTH                12  /* OUT4R_NGATE_SRC - [11:0] */
+
+/*
+ * R1072 (0x430) - Output Path Config 5L
+ */
+#define ARIZONA_OUT5_OSR                         0x2000  /* OUT5_OSR */
+#define ARIZONA_OUT5_OSR_MASK                    0x2000  /* OUT5_OSR */
+#define ARIZONA_OUT5_OSR_SHIFT                       13  /* OUT5_OSR */
+#define ARIZONA_OUT5_OSR_WIDTH                        1  /* OUT5_OSR */
+#define ARIZONA_OUT5L_ANC_SRC_MASK               0x0C00  /* OUT5L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT5L_ANC_SRC_SHIFT                  10  /* OUT5L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT5L_ANC_SRC_WIDTH                   2  /* OUT5L_ANC_SRC - [11:10] */
+
+/*
+ * R1073 (0x431) - DAC Digital Volume 5L
+ */
+#define ARIZONA_OUT_VU                           0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define ARIZONA_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define ARIZONA_OUT5L_MUTE                       0x0100  /* OUT5L_MUTE */
+#define ARIZONA_OUT5L_MUTE_MASK                  0x0100  /* OUT5L_MUTE */
+#define ARIZONA_OUT5L_MUTE_SHIFT                      8  /* OUT5L_MUTE */
+#define ARIZONA_OUT5L_MUTE_WIDTH                      1  /* OUT5L_MUTE */
+#define ARIZONA_OUT5L_VOL_MASK                   0x00FF  /* OUT5L_VOL - [7:0] */
+#define ARIZONA_OUT5L_VOL_SHIFT                       0  /* OUT5L_VOL - [7:0] */
+#define ARIZONA_OUT5L_VOL_WIDTH                       8  /* OUT5L_VOL - [7:0] */
+
+/*
+ * R1074 (0x432) - DAC Volume Limit 5L
+ */
+#define ARIZONA_OUT5L_VOL_LIM_MASK               0x00FF  /* OUT5L_VOL_LIM - [7:0] */
+#define ARIZONA_OUT5L_VOL_LIM_SHIFT                   0  /* OUT5L_VOL_LIM - [7:0] */
+#define ARIZONA_OUT5L_VOL_LIM_WIDTH                   8  /* OUT5L_VOL_LIM - [7:0] */
+
+/*
+ * R1075 (0x433) - Noise Gate Select 5L
+ */
+#define ARIZONA_OUT5L_NGATE_SRC_MASK             0x0FFF  /* OUT5L_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT5L_NGATE_SRC_SHIFT                 0  /* OUT5L_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT5L_NGATE_SRC_WIDTH                12  /* OUT5L_NGATE_SRC - [11:0] */
+
+/*
+ * R1076 (0x434) - Output Path Config 5R
+ */
+#define ARIZONA_OUT5R_ANC_SRC_MASK               0x0C00  /* OUT5R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT5R_ANC_SRC_SHIFT                  10  /* OUT5R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT5R_ANC_SRC_WIDTH                   2  /* OUT5R_ANC_SRC - [11:10] */
+
+/*
+ * R1077 (0x435) - DAC Digital Volume 5R
+ */
+#define ARIZONA_OUT_VU                           0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define ARIZONA_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define ARIZONA_OUT5R_MUTE                       0x0100  /* OUT5R_MUTE */
+#define ARIZONA_OUT5R_MUTE_MASK                  0x0100  /* OUT5R_MUTE */
+#define ARIZONA_OUT5R_MUTE_SHIFT                      8  /* OUT5R_MUTE */
+#define ARIZONA_OUT5R_MUTE_WIDTH                      1  /* OUT5R_MUTE */
+#define ARIZONA_OUT5R_VOL_MASK                   0x00FF  /* OUT5R_VOL - [7:0] */
+#define ARIZONA_OUT5R_VOL_SHIFT                       0  /* OUT5R_VOL - [7:0] */
+#define ARIZONA_OUT5R_VOL_WIDTH                       8  /* OUT5R_VOL - [7:0] */
+
+/*
+ * R1078 (0x436) - DAC Volume Limit 5R
+ */
+#define ARIZONA_OUT5R_VOL_LIM_MASK               0x00FF  /* OUT5R_VOL_LIM - [7:0] */
+#define ARIZONA_OUT5R_VOL_LIM_SHIFT                   0  /* OUT5R_VOL_LIM - [7:0] */
+#define ARIZONA_OUT5R_VOL_LIM_WIDTH                   8  /* OUT5R_VOL_LIM - [7:0] */
+
+/*
+ * R1079 (0x437) - Noise Gate Select 5R
+ */
+#define ARIZONA_OUT5R_NGATE_SRC_MASK             0x0FFF  /* OUT5R_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT5R_NGATE_SRC_SHIFT                 0  /* OUT5R_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT5R_NGATE_SRC_WIDTH                12  /* OUT5R_NGATE_SRC - [11:0] */
+
+/*
+ * R1080 (0x438) - Output Path Config 6L
+ */
+#define ARIZONA_OUT6_OSR                         0x2000  /* OUT6_OSR */
+#define ARIZONA_OUT6_OSR_MASK                    0x2000  /* OUT6_OSR */
+#define ARIZONA_OUT6_OSR_SHIFT                       13  /* OUT6_OSR */
+#define ARIZONA_OUT6_OSR_WIDTH                        1  /* OUT6_OSR */
+#define ARIZONA_OUT6L_ANC_SRC_MASK               0x0C00  /* OUT6L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT6L_ANC_SRC_SHIFT                  10  /* OUT6L_ANC_SRC - [11:10] */
+#define ARIZONA_OUT6L_ANC_SRC_WIDTH                   2  /* OUT6L_ANC_SRC - [11:10] */
+
+/*
+ * R1081 (0x439) - DAC Digital Volume 6L
+ */
+#define ARIZONA_OUT_VU                           0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define ARIZONA_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define ARIZONA_OUT6L_MUTE                       0x0100  /* OUT6L_MUTE */
+#define ARIZONA_OUT6L_MUTE_MASK                  0x0100  /* OUT6L_MUTE */
+#define ARIZONA_OUT6L_MUTE_SHIFT                      8  /* OUT6L_MUTE */
+#define ARIZONA_OUT6L_MUTE_WIDTH                      1  /* OUT6L_MUTE */
+#define ARIZONA_OUT6L_VOL_MASK                   0x00FF  /* OUT6L_VOL - [7:0] */
+#define ARIZONA_OUT6L_VOL_SHIFT                       0  /* OUT6L_VOL - [7:0] */
+#define ARIZONA_OUT6L_VOL_WIDTH                       8  /* OUT6L_VOL - [7:0] */
+
+/*
+ * R1082 (0x43A) - DAC Volume Limit 6L
+ */
+#define ARIZONA_OUT6L_VOL_LIM_MASK               0x00FF  /* OUT6L_VOL_LIM - [7:0] */
+#define ARIZONA_OUT6L_VOL_LIM_SHIFT                   0  /* OUT6L_VOL_LIM - [7:0] */
+#define ARIZONA_OUT6L_VOL_LIM_WIDTH                   8  /* OUT6L_VOL_LIM - [7:0] */
+
+/*
+ * R1083 (0x43B) - Noise Gate Select 6L
+ */
+#define ARIZONA_OUT6L_NGATE_SRC_MASK             0x0FFF  /* OUT6L_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT6L_NGATE_SRC_SHIFT                 0  /* OUT6L_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT6L_NGATE_SRC_WIDTH                12  /* OUT6L_NGATE_SRC - [11:0] */
+
+/*
+ * R1084 (0x43C) - Output Path Config 6R
+ */
+#define ARIZONA_OUT6R_ANC_SRC_MASK               0x0C00  /* OUT6R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT6R_ANC_SRC_SHIFT                  10  /* OUT6R_ANC_SRC - [11:10] */
+#define ARIZONA_OUT6R_ANC_SRC_WIDTH                   2  /* OUT6R_ANC_SRC - [11:10] */
+
+/*
+ * R1085 (0x43D) - DAC Digital Volume 6R
+ */
+#define ARIZONA_OUT_VU                           0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_MASK                      0x0200  /* OUT_VU */
+#define ARIZONA_OUT_VU_SHIFT                          9  /* OUT_VU */
+#define ARIZONA_OUT_VU_WIDTH                          1  /* OUT_VU */
+#define ARIZONA_OUT6R_MUTE                       0x0100  /* OUT6R_MUTE */
+#define ARIZONA_OUT6R_MUTE_MASK                  0x0100  /* OUT6R_MUTE */
+#define ARIZONA_OUT6R_MUTE_SHIFT                      8  /* OUT6R_MUTE */
+#define ARIZONA_OUT6R_MUTE_WIDTH                      1  /* OUT6R_MUTE */
+#define ARIZONA_OUT6R_VOL_MASK                   0x00FF  /* OUT6R_VOL - [7:0] */
+#define ARIZONA_OUT6R_VOL_SHIFT                       0  /* OUT6R_VOL - [7:0] */
+#define ARIZONA_OUT6R_VOL_WIDTH                       8  /* OUT6R_VOL - [7:0] */
+
+/*
+ * R1086 (0x43E) - DAC Volume Limit 6R
+ */
+#define ARIZONA_OUT6R_VOL_LIM_MASK               0x00FF  /* OUT6R_VOL_LIM - [7:0] */
+#define ARIZONA_OUT6R_VOL_LIM_SHIFT                   0  /* OUT6R_VOL_LIM - [7:0] */
+#define ARIZONA_OUT6R_VOL_LIM_WIDTH                   8  /* OUT6R_VOL_LIM - [7:0] */
+
+/*
+ * R1087 (0x43F) - Noise Gate Select 6R
+ */
+#define ARIZONA_OUT6R_NGATE_SRC_MASK             0x0FFF  /* OUT6R_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT6R_NGATE_SRC_SHIFT                 0  /* OUT6R_NGATE_SRC - [11:0] */
+#define ARIZONA_OUT6R_NGATE_SRC_WIDTH                12  /* OUT6R_NGATE_SRC - [11:0] */
+
+/*
+ * R1104 (0x450) - DAC AEC Control 1
+ */
+#define ARIZONA_AEC_LOOPBACK_SRC_MASK            0x003C  /* AEC_LOOPBACK_SRC - [5:2] */
+#define ARIZONA_AEC_LOOPBACK_SRC_SHIFT                2  /* AEC_LOOPBACK_SRC - [5:2] */
+#define ARIZONA_AEC_LOOPBACK_SRC_WIDTH                4  /* AEC_LOOPBACK_SRC - [5:2] */
+#define ARIZONA_AEC_ENA_STS                      0x0002  /* AEC_ENA_STS */
+#define ARIZONA_AEC_ENA_STS_MASK                 0x0002  /* AEC_ENA_STS */
+#define ARIZONA_AEC_ENA_STS_SHIFT                     1  /* AEC_ENA_STS */
+#define ARIZONA_AEC_ENA_STS_WIDTH                     1  /* AEC_ENA_STS */
+#define ARIZONA_AEC_LOOPBACK_ENA                 0x0001  /* AEC_LOOPBACK_ENA */
+#define ARIZONA_AEC_LOOPBACK_ENA_MASK            0x0001  /* AEC_LOOPBACK_ENA */
+#define ARIZONA_AEC_LOOPBACK_ENA_SHIFT                0  /* AEC_LOOPBACK_ENA */
+#define ARIZONA_AEC_LOOPBACK_ENA_WIDTH                1  /* AEC_LOOPBACK_ENA */
+
+/*
+ * R1112 (0x458) - Noise Gate Control
+ */
+#define ARIZONA_NGATE_HOLD_MASK                  0x0030  /* NGATE_HOLD - [5:4] */
+#define ARIZONA_NGATE_HOLD_SHIFT                      4  /* NGATE_HOLD - [5:4] */
+#define ARIZONA_NGATE_HOLD_WIDTH                      2  /* NGATE_HOLD - [5:4] */
+#define ARIZONA_NGATE_THR_MASK                   0x000E  /* NGATE_THR - [3:1] */
+#define ARIZONA_NGATE_THR_SHIFT                       1  /* NGATE_THR - [3:1] */
+#define ARIZONA_NGATE_THR_WIDTH                       3  /* NGATE_THR - [3:1] */
+#define ARIZONA_NGATE_ENA                        0x0001  /* NGATE_ENA */
+#define ARIZONA_NGATE_ENA_MASK                   0x0001  /* NGATE_ENA */
+#define ARIZONA_NGATE_ENA_SHIFT                       0  /* NGATE_ENA */
+#define ARIZONA_NGATE_ENA_WIDTH                       1  /* NGATE_ENA */
+
+/*
+ * R1168 (0x490) - PDM SPK1 CTRL 1
+ */
+#define ARIZONA_SPK1R_MUTE                       0x2000  /* SPK1R_MUTE */
+#define ARIZONA_SPK1R_MUTE_MASK                  0x2000  /* SPK1R_MUTE */
+#define ARIZONA_SPK1R_MUTE_SHIFT                     13  /* SPK1R_MUTE */
+#define ARIZONA_SPK1R_MUTE_WIDTH                      1  /* SPK1R_MUTE */
+#define ARIZONA_SPK1L_MUTE                       0x1000  /* SPK1L_MUTE */
+#define ARIZONA_SPK1L_MUTE_MASK                  0x1000  /* SPK1L_MUTE */
+#define ARIZONA_SPK1L_MUTE_SHIFT                     12  /* SPK1L_MUTE */
+#define ARIZONA_SPK1L_MUTE_WIDTH                      1  /* SPK1L_MUTE */
+#define ARIZONA_SPK1_MUTE_ENDIAN                 0x0100  /* SPK1_MUTE_ENDIAN */
+#define ARIZONA_SPK1_MUTE_ENDIAN_MASK            0x0100  /* SPK1_MUTE_ENDIAN */
+#define ARIZONA_SPK1_MUTE_ENDIAN_SHIFT                8  /* SPK1_MUTE_ENDIAN */
+#define ARIZONA_SPK1_MUTE_ENDIAN_WIDTH                1  /* SPK1_MUTE_ENDIAN */
+#define ARIZONA_SPK1_MUTE_SEQ1_MASK              0x00FF  /* SPK1_MUTE_SEQ1 - [7:0] */
+#define ARIZONA_SPK1_MUTE_SEQ1_SHIFT                  0  /* SPK1_MUTE_SEQ1 - [7:0] */
+#define ARIZONA_SPK1_MUTE_SEQ1_WIDTH                  8  /* SPK1_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R1169 (0x491) - PDM SPK1 CTRL 2
+ */
+#define ARIZONA_SPK1_FMT                         0x0001  /* SPK1_FMT */
+#define ARIZONA_SPK1_FMT_MASK                    0x0001  /* SPK1_FMT */
+#define ARIZONA_SPK1_FMT_SHIFT                        0  /* SPK1_FMT */
+#define ARIZONA_SPK1_FMT_WIDTH                        1  /* SPK1_FMT */
+
+/*
+ * R1170 (0x492) - PDM SPK2 CTRL 1
+ */
+#define ARIZONA_SPK2R_MUTE                       0x2000  /* SPK2R_MUTE */
+#define ARIZONA_SPK2R_MUTE_MASK                  0x2000  /* SPK2R_MUTE */
+#define ARIZONA_SPK2R_MUTE_SHIFT                     13  /* SPK2R_MUTE */
+#define ARIZONA_SPK2R_MUTE_WIDTH                      1  /* SPK2R_MUTE */
+#define ARIZONA_SPK2L_MUTE                       0x1000  /* SPK2L_MUTE */
+#define ARIZONA_SPK2L_MUTE_MASK                  0x1000  /* SPK2L_MUTE */
+#define ARIZONA_SPK2L_MUTE_SHIFT                     12  /* SPK2L_MUTE */
+#define ARIZONA_SPK2L_MUTE_WIDTH                      1  /* SPK2L_MUTE */
+#define ARIZONA_SPK2_MUTE_ENDIAN                 0x0100  /* SPK2_MUTE_ENDIAN */
+#define ARIZONA_SPK2_MUTE_ENDIAN_MASK            0x0100  /* SPK2_MUTE_ENDIAN */
+#define ARIZONA_SPK2_MUTE_ENDIAN_SHIFT                8  /* SPK2_MUTE_ENDIAN */
+#define ARIZONA_SPK2_MUTE_ENDIAN_WIDTH                1  /* SPK2_MUTE_ENDIAN */
+#define ARIZONA_SPK2_MUTE_SEQ_MASK               0x00FF  /* SPK2_MUTE_SEQ - [7:0] */
+#define ARIZONA_SPK2_MUTE_SEQ_SHIFT                   0  /* SPK2_MUTE_SEQ - [7:0] */
+#define ARIZONA_SPK2_MUTE_SEQ_WIDTH                   8  /* SPK2_MUTE_SEQ - [7:0] */
+
+/*
+ * R1171 (0x493) - PDM SPK2 CTRL 2
+ */
+#define ARIZONA_SPK2_FMT                         0x0001  /* SPK2_FMT */
+#define ARIZONA_SPK2_FMT_MASK                    0x0001  /* SPK2_FMT */
+#define ARIZONA_SPK2_FMT_SHIFT                        0  /* SPK2_FMT */
+#define ARIZONA_SPK2_FMT_WIDTH                        1  /* SPK2_FMT */
+
+/*
+ * R1244 (0x4DC) - DAC comp 1
+ */
+#define ARIZONA_OUT_COMP_COEFF_MASK              0xFFFF  /* OUT_COMP_COEFF - [15:0] */
+#define ARIZONA_OUT_COMP_COEFF_SHIFT                  0  /* OUT_COMP_COEFF - [15:0] */
+#define ARIZONA_OUT_COMP_COEFF_WIDTH                 16  /* OUT_COMP_COEFF - [15:0] */
+
+/*
+ * R1245 (0x4DD) - DAC comp 2
+ */
+#define ARIZONA_OUT_COMP_COEFF_1                 0x0002  /* OUT_COMP_COEFF */
+#define ARIZONA_OUT_COMP_COEFF_1_MASK            0x0002  /* OUT_COMP_COEFF */
+#define ARIZONA_OUT_COMP_COEFF_1_SHIFT                1  /* OUT_COMP_COEFF */
+#define ARIZONA_OUT_COMP_COEFF_1_WIDTH                1  /* OUT_COMP_COEFF */
+#define ARIZONA_OUT_COMP_COEFF_SEL               0x0001  /* OUT_COMP_COEFF_SEL */
+#define ARIZONA_OUT_COMP_COEFF_SEL_MASK          0x0001  /* OUT_COMP_COEFF_SEL */
+#define ARIZONA_OUT_COMP_COEFF_SEL_SHIFT              0  /* OUT_COMP_COEFF_SEL */
+#define ARIZONA_OUT_COMP_COEFF_SEL_WIDTH              1  /* OUT_COMP_COEFF_SEL */
+
+/*
+ * R1246 (0x4DE) - DAC comp 3
+ */
+#define ARIZONA_AEC_COMP_COEFF_MASK              0xFFFF  /* AEC_COMP_COEFF - [15:0] */
+#define ARIZONA_AEC_COMP_COEFF_SHIFT                  0  /* AEC_COMP_COEFF - [15:0] */
+#define ARIZONA_AEC_COMP_COEFF_WIDTH                 16  /* AEC_COMP_COEFF - [15:0] */
+
+/*
+ * R1247 (0x4DF) - DAC comp 4
+ */
+#define ARIZONA_AEC_COMP_COEFF_1                 0x0002  /* AEC_COMP_COEFF */
+#define ARIZONA_AEC_COMP_COEFF_1_MASK            0x0002  /* AEC_COMP_COEFF */
+#define ARIZONA_AEC_COMP_COEFF_1_SHIFT                1  /* AEC_COMP_COEFF */
+#define ARIZONA_AEC_COMP_COEFF_1_WIDTH                1  /* AEC_COMP_COEFF */
+#define ARIZONA_AEC_COMP_COEFF_SEL               0x0001  /* AEC_COMP_COEFF_SEL */
+#define ARIZONA_AEC_COMP_COEFF_SEL_MASK          0x0001  /* AEC_COMP_COEFF_SEL */
+#define ARIZONA_AEC_COMP_COEFF_SEL_SHIFT              0  /* AEC_COMP_COEFF_SEL */
+#define ARIZONA_AEC_COMP_COEFF_SEL_WIDTH              1  /* AEC_COMP_COEFF_SEL */
+
+/*
+ * R1280 (0x500) - AIF1 BCLK Ctrl
+ */
+#define ARIZONA_AIF1_BCLK_INV                    0x0080  /* AIF1_BCLK_INV */
+#define ARIZONA_AIF1_BCLK_INV_MASK               0x0080  /* AIF1_BCLK_INV */
+#define ARIZONA_AIF1_BCLK_INV_SHIFT                   7  /* AIF1_BCLK_INV */
+#define ARIZONA_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
+#define ARIZONA_AIF1_BCLK_FRC                    0x0040  /* AIF1_BCLK_FRC */
+#define ARIZONA_AIF1_BCLK_FRC_MASK               0x0040  /* AIF1_BCLK_FRC */
+#define ARIZONA_AIF1_BCLK_FRC_SHIFT                   6  /* AIF1_BCLK_FRC */
+#define ARIZONA_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
+#define ARIZONA_AIF1_BCLK_MSTR                   0x0020  /* AIF1_BCLK_MSTR */
+#define ARIZONA_AIF1_BCLK_MSTR_MASK              0x0020  /* AIF1_BCLK_MSTR */
+#define ARIZONA_AIF1_BCLK_MSTR_SHIFT                  5  /* AIF1_BCLK_MSTR */
+#define ARIZONA_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
+#define ARIZONA_AIF1_BCLK_FREQ_MASK              0x001F  /* AIF1_BCLK_FREQ - [4:0] */
+#define ARIZONA_AIF1_BCLK_FREQ_SHIFT                  0  /* AIF1_BCLK_FREQ - [4:0] */
+#define ARIZONA_AIF1_BCLK_FREQ_WIDTH                  5  /* AIF1_BCLK_FREQ - [4:0] */
+
+/*
+ * R1281 (0x501) - AIF1 Tx Pin Ctrl
+ */
+#define ARIZONA_AIF1TX_DAT_TRI                   0x0020  /* AIF1TX_DAT_TRI */
+#define ARIZONA_AIF1TX_DAT_TRI_MASK              0x0020  /* AIF1TX_DAT_TRI */
+#define ARIZONA_AIF1TX_DAT_TRI_SHIFT                  5  /* AIF1TX_DAT_TRI */
+#define ARIZONA_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
+#define ARIZONA_AIF1TX_LRCLK_SRC                 0x0008  /* AIF1TX_LRCLK_SRC */
+#define ARIZONA_AIF1TX_LRCLK_SRC_MASK            0x0008  /* AIF1TX_LRCLK_SRC */
+#define ARIZONA_AIF1TX_LRCLK_SRC_SHIFT                3  /* AIF1TX_LRCLK_SRC */
+#define ARIZONA_AIF1TX_LRCLK_SRC_WIDTH                1  /* AIF1TX_LRCLK_SRC */
+#define ARIZONA_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
+#define ARIZONA_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
+#define ARIZONA_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
+#define ARIZONA_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
+#define ARIZONA_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
+#define ARIZONA_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
+#define ARIZONA_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
+#define ARIZONA_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
+#define ARIZONA_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
+#define ARIZONA_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
+#define ARIZONA_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
+#define ARIZONA_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
+
+/*
+ * R1282 (0x502) - AIF1 Rx Pin Ctrl
+ */
+#define ARIZONA_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
+#define ARIZONA_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
+#define ARIZONA_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
+#define ARIZONA_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
+#define ARIZONA_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
+#define ARIZONA_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
+#define ARIZONA_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
+#define ARIZONA_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
+#define ARIZONA_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
+#define ARIZONA_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
+#define ARIZONA_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
+#define ARIZONA_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
+
+/*
+ * R1283 (0x503) - AIF1 Rate Ctrl
+ */
+#define ARIZONA_AIF1_RATE_MASK                   0x7800  /* AIF1_RATE - [14:11] */
+#define ARIZONA_AIF1_RATE_SHIFT                      11  /* AIF1_RATE - [14:11] */
+#define ARIZONA_AIF1_RATE_WIDTH                       4  /* AIF1_RATE - [14:11] */
+#define ARIZONA_AIF1_TRI                         0x0040  /* AIF1_TRI */
+#define ARIZONA_AIF1_TRI_MASK                    0x0040  /* AIF1_TRI */
+#define ARIZONA_AIF1_TRI_SHIFT                        6  /* AIF1_TRI */
+#define ARIZONA_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
+
+/*
+ * R1284 (0x504) - AIF1 Format
+ */
+#define ARIZONA_AIF1_FMT_MASK                    0x0007  /* AIF1_FMT - [2:0] */
+#define ARIZONA_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [2:0] */
+#define ARIZONA_AIF1_FMT_WIDTH                        3  /* AIF1_FMT - [2:0] */
+
+/*
+ * R1285 (0x505) - AIF1 Tx BCLK Rate
+ */
+#define ARIZONA_AIF1TX_BCPF_MASK                 0x1FFF  /* AIF1TX_BCPF - [12:0] */
+#define ARIZONA_AIF1TX_BCPF_SHIFT                     0  /* AIF1TX_BCPF - [12:0] */
+#define ARIZONA_AIF1TX_BCPF_WIDTH                    13  /* AIF1TX_BCPF - [12:0] */
+
+/*
+ * R1286 (0x506) - AIF1 Rx BCLK Rate
+ */
+#define ARIZONA_AIF1RX_BCPF_MASK                 0x1FFF  /* AIF1RX_BCPF - [12:0] */
+#define ARIZONA_AIF1RX_BCPF_SHIFT                     0  /* AIF1RX_BCPF - [12:0] */
+#define ARIZONA_AIF1RX_BCPF_WIDTH                    13  /* AIF1RX_BCPF - [12:0] */
+
+/*
+ * R1287 (0x507) - AIF1 Frame Ctrl 1
+ */
+#define ARIZONA_AIF1TX_WL_MASK                   0x3F00  /* AIF1TX_WL - [13:8] */
+#define ARIZONA_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [13:8] */
+#define ARIZONA_AIF1TX_WL_WIDTH                       6  /* AIF1TX_WL - [13:8] */
+#define ARIZONA_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
+#define ARIZONA_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
+#define ARIZONA_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
+
+/*
+ * R1288 (0x508) - AIF1 Frame Ctrl 2
+ */
+#define ARIZONA_AIF1RX_WL_MASK                   0x3F00  /* AIF1RX_WL - [13:8] */
+#define ARIZONA_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [13:8] */
+#define ARIZONA_AIF1RX_WL_WIDTH                       6  /* AIF1RX_WL - [13:8] */
+#define ARIZONA_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
+#define ARIZONA_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
+#define ARIZONA_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
+
+/*
+ * R1289 (0x509) - AIF1 Frame Ctrl 3
+ */
+#define ARIZONA_AIF1TX1_SLOT_MASK                0x003F  /* AIF1TX1_SLOT - [5:0] */
+#define ARIZONA_AIF1TX1_SLOT_SHIFT                    0  /* AIF1TX1_SLOT - [5:0] */
+#define ARIZONA_AIF1TX1_SLOT_WIDTH                    6  /* AIF1TX1_SLOT - [5:0] */
+
+/*
+ * R1290 (0x50A) - AIF1 Frame Ctrl 4
+ */
+#define ARIZONA_AIF1TX2_SLOT_MASK                0x003F  /* AIF1TX2_SLOT - [5:0] */
+#define ARIZONA_AIF1TX2_SLOT_SHIFT                    0  /* AIF1TX2_SLOT - [5:0] */
+#define ARIZONA_AIF1TX2_SLOT_WIDTH                    6  /* AIF1TX2_SLOT - [5:0] */
+
+/*
+ * R1291 (0x50B) - AIF1 Frame Ctrl 5
+ */
+#define ARIZONA_AIF1TX3_SLOT_MASK                0x003F  /* AIF1TX3_SLOT - [5:0] */
+#define ARIZONA_AIF1TX3_SLOT_SHIFT                    0  /* AIF1TX3_SLOT - [5:0] */
+#define ARIZONA_AIF1TX3_SLOT_WIDTH                    6  /* AIF1TX3_SLOT - [5:0] */
+
+/*
+ * R1292 (0x50C) - AIF1 Frame Ctrl 6
+ */
+#define ARIZONA_AIF1TX4_SLOT_MASK                0x003F  /* AIF1TX4_SLOT - [5:0] */
+#define ARIZONA_AIF1TX4_SLOT_SHIFT                    0  /* AIF1TX4_SLOT - [5:0] */
+#define ARIZONA_AIF1TX4_SLOT_WIDTH                    6  /* AIF1TX4_SLOT - [5:0] */
+
+/*
+ * R1293 (0x50D) - AIF1 Frame Ctrl 7
+ */
+#define ARIZONA_AIF1TX5_SLOT_MASK                0x003F  /* AIF1TX5_SLOT - [5:0] */
+#define ARIZONA_AIF1TX5_SLOT_SHIFT                    0  /* AIF1TX5_SLOT - [5:0] */
+#define ARIZONA_AIF1TX5_SLOT_WIDTH                    6  /* AIF1TX5_SLOT - [5:0] */
+
+/*
+ * R1294 (0x50E) - AIF1 Frame Ctrl 8
+ */
+#define ARIZONA_AIF1TX6_SLOT_MASK                0x003F  /* AIF1TX6_SLOT - [5:0] */
+#define ARIZONA_AIF1TX6_SLOT_SHIFT                    0  /* AIF1TX6_SLOT - [5:0] */
+#define ARIZONA_AIF1TX6_SLOT_WIDTH                    6  /* AIF1TX6_SLOT - [5:0] */
+
+/*
+ * R1295 (0x50F) - AIF1 Frame Ctrl 9
+ */
+#define ARIZONA_AIF1TX7_SLOT_MASK                0x003F  /* AIF1TX7_SLOT - [5:0] */
+#define ARIZONA_AIF1TX7_SLOT_SHIFT                    0  /* AIF1TX7_SLOT - [5:0] */
+#define ARIZONA_AIF1TX7_SLOT_WIDTH                    6  /* AIF1TX7_SLOT - [5:0] */
+
+/*
+ * R1296 (0x510) - AIF1 Frame Ctrl 10
+ */
+#define ARIZONA_AIF1TX8_SLOT_MASK                0x003F  /* AIF1TX8_SLOT - [5:0] */
+#define ARIZONA_AIF1TX8_SLOT_SHIFT                    0  /* AIF1TX8_SLOT - [5:0] */
+#define ARIZONA_AIF1TX8_SLOT_WIDTH                    6  /* AIF1TX8_SLOT - [5:0] */
+
+/*
+ * R1297 (0x511) - AIF1 Frame Ctrl 11
+ */
+#define ARIZONA_AIF1RX1_SLOT_MASK                0x003F  /* AIF1RX1_SLOT - [5:0] */
+#define ARIZONA_AIF1RX1_SLOT_SHIFT                    0  /* AIF1RX1_SLOT - [5:0] */
+#define ARIZONA_AIF1RX1_SLOT_WIDTH                    6  /* AIF1RX1_SLOT - [5:0] */
+
+/*
+ * R1298 (0x512) - AIF1 Frame Ctrl 12
+ */
+#define ARIZONA_AIF1RX2_SLOT_MASK                0x003F  /* AIF1RX2_SLOT - [5:0] */
+#define ARIZONA_AIF1RX2_SLOT_SHIFT                    0  /* AIF1RX2_SLOT - [5:0] */
+#define ARIZONA_AIF1RX2_SLOT_WIDTH                    6  /* AIF1RX2_SLOT - [5:0] */
+
+/*
+ * R1299 (0x513) - AIF1 Frame Ctrl 13
+ */
+#define ARIZONA_AIF1RX3_SLOT_MASK                0x003F  /* AIF1RX3_SLOT - [5:0] */
+#define ARIZONA_AIF1RX3_SLOT_SHIFT                    0  /* AIF1RX3_SLOT - [5:0] */
+#define ARIZONA_AIF1RX3_SLOT_WIDTH                    6  /* AIF1RX3_SLOT - [5:0] */
+
+/*
+ * R1300 (0x514) - AIF1 Frame Ctrl 14
+ */
+#define ARIZONA_AIF1RX4_SLOT_MASK                0x003F  /* AIF1RX4_SLOT - [5:0] */
+#define ARIZONA_AIF1RX4_SLOT_SHIFT                    0  /* AIF1RX4_SLOT - [5:0] */
+#define ARIZONA_AIF1RX4_SLOT_WIDTH                    6  /* AIF1RX4_SLOT - [5:0] */
+
+/*
+ * R1301 (0x515) - AIF1 Frame Ctrl 15
+ */
+#define ARIZONA_AIF1RX5_SLOT_MASK                0x003F  /* AIF1RX5_SLOT - [5:0] */
+#define ARIZONA_AIF1RX5_SLOT_SHIFT                    0  /* AIF1RX5_SLOT - [5:0] */
+#define ARIZONA_AIF1RX5_SLOT_WIDTH                    6  /* AIF1RX5_SLOT - [5:0] */
+
+/*
+ * R1302 (0x516) - AIF1 Frame Ctrl 16
+ */
+#define ARIZONA_AIF1RX6_SLOT_MASK                0x003F  /* AIF1RX6_SLOT - [5:0] */
+#define ARIZONA_AIF1RX6_SLOT_SHIFT                    0  /* AIF1RX6_SLOT - [5:0] */
+#define ARIZONA_AIF1RX6_SLOT_WIDTH                    6  /* AIF1RX6_SLOT - [5:0] */
+
+/*
+ * R1303 (0x517) - AIF1 Frame Ctrl 17
+ */
+#define ARIZONA_AIF1RX7_SLOT_MASK                0x003F  /* AIF1RX7_SLOT - [5:0] */
+#define ARIZONA_AIF1RX7_SLOT_SHIFT                    0  /* AIF1RX7_SLOT - [5:0] */
+#define ARIZONA_AIF1RX7_SLOT_WIDTH                    6  /* AIF1RX7_SLOT - [5:0] */
+
+/*
+ * R1304 (0x518) - AIF1 Frame Ctrl 18
+ */
+#define ARIZONA_AIF1RX8_SLOT_MASK                0x003F  /* AIF1RX8_SLOT - [5:0] */
+#define ARIZONA_AIF1RX8_SLOT_SHIFT                    0  /* AIF1RX8_SLOT - [5:0] */
+#define ARIZONA_AIF1RX8_SLOT_WIDTH                    6  /* AIF1RX8_SLOT - [5:0] */
+
+/*
+ * R1305 (0x519) - AIF1 Tx Enables
+ */
+#define ARIZONA_AIF1TX8_ENA                      0x0080  /* AIF1TX8_ENA */
+#define ARIZONA_AIF1TX8_ENA_MASK                 0x0080  /* AIF1TX8_ENA */
+#define ARIZONA_AIF1TX8_ENA_SHIFT                     7  /* AIF1TX8_ENA */
+#define ARIZONA_AIF1TX8_ENA_WIDTH                     1  /* AIF1TX8_ENA */
+#define ARIZONA_AIF1TX7_ENA                      0x0040  /* AIF1TX7_ENA */
+#define ARIZONA_AIF1TX7_ENA_MASK                 0x0040  /* AIF1TX7_ENA */
+#define ARIZONA_AIF1TX7_ENA_SHIFT                     6  /* AIF1TX7_ENA */
+#define ARIZONA_AIF1TX7_ENA_WIDTH                     1  /* AIF1TX7_ENA */
+#define ARIZONA_AIF1TX6_ENA                      0x0020  /* AIF1TX6_ENA */
+#define ARIZONA_AIF1TX6_ENA_MASK                 0x0020  /* AIF1TX6_ENA */
+#define ARIZONA_AIF1TX6_ENA_SHIFT                     5  /* AIF1TX6_ENA */
+#define ARIZONA_AIF1TX6_ENA_WIDTH                     1  /* AIF1TX6_ENA */
+#define ARIZONA_AIF1TX5_ENA                      0x0010  /* AIF1TX5_ENA */
+#define ARIZONA_AIF1TX5_ENA_MASK                 0x0010  /* AIF1TX5_ENA */
+#define ARIZONA_AIF1TX5_ENA_SHIFT                     4  /* AIF1TX5_ENA */
+#define ARIZONA_AIF1TX5_ENA_WIDTH                     1  /* AIF1TX5_ENA */
+#define ARIZONA_AIF1TX4_ENA                      0x0008  /* AIF1TX4_ENA */
+#define ARIZONA_AIF1TX4_ENA_MASK                 0x0008  /* AIF1TX4_ENA */
+#define ARIZONA_AIF1TX4_ENA_SHIFT                     3  /* AIF1TX4_ENA */
+#define ARIZONA_AIF1TX4_ENA_WIDTH                     1  /* AIF1TX4_ENA */
+#define ARIZONA_AIF1TX3_ENA                      0x0004  /* AIF1TX3_ENA */
+#define ARIZONA_AIF1TX3_ENA_MASK                 0x0004  /* AIF1TX3_ENA */
+#define ARIZONA_AIF1TX3_ENA_SHIFT                     2  /* AIF1TX3_ENA */
+#define ARIZONA_AIF1TX3_ENA_WIDTH                     1  /* AIF1TX3_ENA */
+#define ARIZONA_AIF1TX2_ENA                      0x0002  /* AIF1TX2_ENA */
+#define ARIZONA_AIF1TX2_ENA_MASK                 0x0002  /* AIF1TX2_ENA */
+#define ARIZONA_AIF1TX2_ENA_SHIFT                     1  /* AIF1TX2_ENA */
+#define ARIZONA_AIF1TX2_ENA_WIDTH                     1  /* AIF1TX2_ENA */
+#define ARIZONA_AIF1TX1_ENA                      0x0001  /* AIF1TX1_ENA */
+#define ARIZONA_AIF1TX1_ENA_MASK                 0x0001  /* AIF1TX1_ENA */
+#define ARIZONA_AIF1TX1_ENA_SHIFT                     0  /* AIF1TX1_ENA */
+#define ARIZONA_AIF1TX1_ENA_WIDTH                     1  /* AIF1TX1_ENA */
+
+/*
+ * R1306 (0x51A) - AIF1 Rx Enables
+ */
+#define ARIZONA_AIF1RX8_ENA                      0x0080  /* AIF1RX8_ENA */
+#define ARIZONA_AIF1RX8_ENA_MASK                 0x0080  /* AIF1RX8_ENA */
+#define ARIZONA_AIF1RX8_ENA_SHIFT                     7  /* AIF1RX8_ENA */
+#define ARIZONA_AIF1RX8_ENA_WIDTH                     1  /* AIF1RX8_ENA */
+#define ARIZONA_AIF1RX7_ENA                      0x0040  /* AIF1RX7_ENA */
+#define ARIZONA_AIF1RX7_ENA_MASK                 0x0040  /* AIF1RX7_ENA */
+#define ARIZONA_AIF1RX7_ENA_SHIFT                     6  /* AIF1RX7_ENA */
+#define ARIZONA_AIF1RX7_ENA_WIDTH                     1  /* AIF1RX7_ENA */
+#define ARIZONA_AIF1RX6_ENA                      0x0020  /* AIF1RX6_ENA */
+#define ARIZONA_AIF1RX6_ENA_MASK                 0x0020  /* AIF1RX6_ENA */
+#define ARIZONA_AIF1RX6_ENA_SHIFT                     5  /* AIF1RX6_ENA */
+#define ARIZONA_AIF1RX6_ENA_WIDTH                     1  /* AIF1RX6_ENA */
+#define ARIZONA_AIF1RX5_ENA                      0x0010  /* AIF1RX5_ENA */
+#define ARIZONA_AIF1RX5_ENA_MASK                 0x0010  /* AIF1RX5_ENA */
+#define ARIZONA_AIF1RX5_ENA_SHIFT                     4  /* AIF1RX5_ENA */
+#define ARIZONA_AIF1RX5_ENA_WIDTH                     1  /* AIF1RX5_ENA */
+#define ARIZONA_AIF1RX4_ENA                      0x0008  /* AIF1RX4_ENA */
+#define ARIZONA_AIF1RX4_ENA_MASK                 0x0008  /* AIF1RX4_ENA */
+#define ARIZONA_AIF1RX4_ENA_SHIFT                     3  /* AIF1RX4_ENA */
+#define ARIZONA_AIF1RX4_ENA_WIDTH                     1  /* AIF1RX4_ENA */
+#define ARIZONA_AIF1RX3_ENA                      0x0004  /* AIF1RX3_ENA */
+#define ARIZONA_AIF1RX3_ENA_MASK                 0x0004  /* AIF1RX3_ENA */
+#define ARIZONA_AIF1RX3_ENA_SHIFT                     2  /* AIF1RX3_ENA */
+#define ARIZONA_AIF1RX3_ENA_WIDTH                     1  /* AIF1RX3_ENA */
+#define ARIZONA_AIF1RX2_ENA                      0x0002  /* AIF1RX2_ENA */
+#define ARIZONA_AIF1RX2_ENA_MASK                 0x0002  /* AIF1RX2_ENA */
+#define ARIZONA_AIF1RX2_ENA_SHIFT                     1  /* AIF1RX2_ENA */
+#define ARIZONA_AIF1RX2_ENA_WIDTH                     1  /* AIF1RX2_ENA */
+#define ARIZONA_AIF1RX1_ENA                      0x0001  /* AIF1RX1_ENA */
+#define ARIZONA_AIF1RX1_ENA_MASK                 0x0001  /* AIF1RX1_ENA */
+#define ARIZONA_AIF1RX1_ENA_SHIFT                     0  /* AIF1RX1_ENA */
+#define ARIZONA_AIF1RX1_ENA_WIDTH                     1  /* AIF1RX1_ENA */
+
+/*
+ * R1307 (0x51B) - AIF1 Force Write
+ */
+#define ARIZONA_AIF1_FRC_WR                      0x0001  /* AIF1_FRC_WR */
+#define ARIZONA_AIF1_FRC_WR_MASK                 0x0001  /* AIF1_FRC_WR */
+#define ARIZONA_AIF1_FRC_WR_SHIFT                     0  /* AIF1_FRC_WR */
+#define ARIZONA_AIF1_FRC_WR_WIDTH                     1  /* AIF1_FRC_WR */
+
+/*
+ * R1344 (0x540) - AIF2 BCLK Ctrl
+ */
+#define ARIZONA_AIF2_BCLK_INV                    0x0080  /* AIF2_BCLK_INV */
+#define ARIZONA_AIF2_BCLK_INV_MASK               0x0080  /* AIF2_BCLK_INV */
+#define ARIZONA_AIF2_BCLK_INV_SHIFT                   7  /* AIF2_BCLK_INV */
+#define ARIZONA_AIF2_BCLK_INV_WIDTH                   1  /* AIF2_BCLK_INV */
+#define ARIZONA_AIF2_BCLK_FRC                    0x0040  /* AIF2_BCLK_FRC */
+#define ARIZONA_AIF2_BCLK_FRC_MASK               0x0040  /* AIF2_BCLK_FRC */
+#define ARIZONA_AIF2_BCLK_FRC_SHIFT                   6  /* AIF2_BCLK_FRC */
+#define ARIZONA_AIF2_BCLK_FRC_WIDTH                   1  /* AIF2_BCLK_FRC */
+#define ARIZONA_AIF2_BCLK_MSTR                   0x0020  /* AIF2_BCLK_MSTR */
+#define ARIZONA_AIF2_BCLK_MSTR_MASK              0x0020  /* AIF2_BCLK_MSTR */
+#define ARIZONA_AIF2_BCLK_MSTR_SHIFT                  5  /* AIF2_BCLK_MSTR */
+#define ARIZONA_AIF2_BCLK_MSTR_WIDTH                  1  /* AIF2_BCLK_MSTR */
+#define ARIZONA_AIF2_BCLK_FREQ_MASK              0x001F  /* AIF2_BCLK_FREQ - [4:0] */
+#define ARIZONA_AIF2_BCLK_FREQ_SHIFT                  0  /* AIF2_BCLK_FREQ - [4:0] */
+#define ARIZONA_AIF2_BCLK_FREQ_WIDTH                  5  /* AIF2_BCLK_FREQ - [4:0] */
+
+/*
+ * R1345 (0x541) - AIF2 Tx Pin Ctrl
+ */
+#define ARIZONA_AIF2TX_DAT_TRI                   0x0020  /* AIF2TX_DAT_TRI */
+#define ARIZONA_AIF2TX_DAT_TRI_MASK              0x0020  /* AIF2TX_DAT_TRI */
+#define ARIZONA_AIF2TX_DAT_TRI_SHIFT                  5  /* AIF2TX_DAT_TRI */
+#define ARIZONA_AIF2TX_DAT_TRI_WIDTH                  1  /* AIF2TX_DAT_TRI */
+#define ARIZONA_AIF2TX_LRCLK_SRC                 0x0008  /* AIF2TX_LRCLK_SRC */
+#define ARIZONA_AIF2TX_LRCLK_SRC_MASK            0x0008  /* AIF2TX_LRCLK_SRC */
+#define ARIZONA_AIF2TX_LRCLK_SRC_SHIFT                3  /* AIF2TX_LRCLK_SRC */
+#define ARIZONA_AIF2TX_LRCLK_SRC_WIDTH                1  /* AIF2TX_LRCLK_SRC */
+#define ARIZONA_AIF2TX_LRCLK_INV                 0x0004  /* AIF2TX_LRCLK_INV */
+#define ARIZONA_AIF2TX_LRCLK_INV_MASK            0x0004  /* AIF2TX_LRCLK_INV */
+#define ARIZONA_AIF2TX_LRCLK_INV_SHIFT                2  /* AIF2TX_LRCLK_INV */
+#define ARIZONA_AIF2TX_LRCLK_INV_WIDTH                1  /* AIF2TX_LRCLK_INV */
+#define ARIZONA_AIF2TX_LRCLK_FRC                 0x0002  /* AIF2TX_LRCLK_FRC */
+#define ARIZONA_AIF2TX_LRCLK_FRC_MASK            0x0002  /* AIF2TX_LRCLK_FRC */
+#define ARIZONA_AIF2TX_LRCLK_FRC_SHIFT                1  /* AIF2TX_LRCLK_FRC */
+#define ARIZONA_AIF2TX_LRCLK_FRC_WIDTH                1  /* AIF2TX_LRCLK_FRC */
+#define ARIZONA_AIF2TX_LRCLK_MSTR                0x0001  /* AIF2TX_LRCLK_MSTR */
+#define ARIZONA_AIF2TX_LRCLK_MSTR_MASK           0x0001  /* AIF2TX_LRCLK_MSTR */
+#define ARIZONA_AIF2TX_LRCLK_MSTR_SHIFT               0  /* AIF2TX_LRCLK_MSTR */
+#define ARIZONA_AIF2TX_LRCLK_MSTR_WIDTH               1  /* AIF2TX_LRCLK_MSTR */
+
+/*
+ * R1346 (0x542) - AIF2 Rx Pin Ctrl
+ */
+#define ARIZONA_AIF2RX_LRCLK_INV                 0x0004  /* AIF2RX_LRCLK_INV */
+#define ARIZONA_AIF2RX_LRCLK_INV_MASK            0x0004  /* AIF2RX_LRCLK_INV */
+#define ARIZONA_AIF2RX_LRCLK_INV_SHIFT                2  /* AIF2RX_LRCLK_INV */
+#define ARIZONA_AIF2RX_LRCLK_INV_WIDTH                1  /* AIF2RX_LRCLK_INV */
+#define ARIZONA_AIF2RX_LRCLK_FRC                 0x0002  /* AIF2RX_LRCLK_FRC */
+#define ARIZONA_AIF2RX_LRCLK_FRC_MASK            0x0002  /* AIF2RX_LRCLK_FRC */
+#define ARIZONA_AIF2RX_LRCLK_FRC_SHIFT                1  /* AIF2RX_LRCLK_FRC */
+#define ARIZONA_AIF2RX_LRCLK_FRC_WIDTH                1  /* AIF2RX_LRCLK_FRC */
+#define ARIZONA_AIF2RX_LRCLK_MSTR                0x0001  /* AIF2RX_LRCLK_MSTR */
+#define ARIZONA_AIF2RX_LRCLK_MSTR_MASK           0x0001  /* AIF2RX_LRCLK_MSTR */
+#define ARIZONA_AIF2RX_LRCLK_MSTR_SHIFT               0  /* AIF2RX_LRCLK_MSTR */
+#define ARIZONA_AIF2RX_LRCLK_MSTR_WIDTH               1  /* AIF2RX_LRCLK_MSTR */
+
+/*
+ * R1347 (0x543) - AIF2 Rate Ctrl
+ */
+#define ARIZONA_AIF2_RATE_MASK                   0x7800  /* AIF2_RATE - [14:11] */
+#define ARIZONA_AIF2_RATE_SHIFT                      11  /* AIF2_RATE - [14:11] */
+#define ARIZONA_AIF2_RATE_WIDTH                       4  /* AIF2_RATE - [14:11] */
+#define ARIZONA_AIF2_TRI                         0x0040  /* AIF2_TRI */
+#define ARIZONA_AIF2_TRI_MASK                    0x0040  /* AIF2_TRI */
+#define ARIZONA_AIF2_TRI_SHIFT                        6  /* AIF2_TRI */
+#define ARIZONA_AIF2_TRI_WIDTH                        1  /* AIF2_TRI */
+
+/*
+ * R1348 (0x544) - AIF2 Format
+ */
+#define ARIZONA_AIF2_FMT_MASK                    0x0007  /* AIF2_FMT - [2:0] */
+#define ARIZONA_AIF2_FMT_SHIFT                        0  /* AIF2_FMT - [2:0] */
+#define ARIZONA_AIF2_FMT_WIDTH                        3  /* AIF2_FMT - [2:0] */
+
+/*
+ * R1349 (0x545) - AIF2 Tx BCLK Rate
+ */
+#define ARIZONA_AIF2TX_BCPF_MASK                 0x1FFF  /* AIF2TX_BCPF - [12:0] */
+#define ARIZONA_AIF2TX_BCPF_SHIFT                     0  /* AIF2TX_BCPF - [12:0] */
+#define ARIZONA_AIF2TX_BCPF_WIDTH                    13  /* AIF2TX_BCPF - [12:0] */
+
+/*
+ * R1350 (0x546) - AIF2 Rx BCLK Rate
+ */
+#define ARIZONA_AIF2RX_BCPF_MASK                 0x1FFF  /* AIF2RX_BCPF - [12:0] */
+#define ARIZONA_AIF2RX_BCPF_SHIFT                     0  /* AIF2RX_BCPF - [12:0] */
+#define ARIZONA_AIF2RX_BCPF_WIDTH                    13  /* AIF2RX_BCPF - [12:0] */
+
+/*
+ * R1351 (0x547) - AIF2 Frame Ctrl 1
+ */
+#define ARIZONA_AIF2TX_WL_MASK                   0x3F00  /* AIF2TX_WL - [13:8] */
+#define ARIZONA_AIF2TX_WL_SHIFT                       8  /* AIF2TX_WL - [13:8] */
+#define ARIZONA_AIF2TX_WL_WIDTH                       6  /* AIF2TX_WL - [13:8] */
+#define ARIZONA_AIF2TX_SLOT_LEN_MASK             0x00FF  /* AIF2TX_SLOT_LEN - [7:0] */
+#define ARIZONA_AIF2TX_SLOT_LEN_SHIFT                 0  /* AIF2TX_SLOT_LEN - [7:0] */
+#define ARIZONA_AIF2TX_SLOT_LEN_WIDTH                 8  /* AIF2TX_SLOT_LEN - [7:0] */
+
+/*
+ * R1352 (0x548) - AIF2 Frame Ctrl 2
+ */
+#define ARIZONA_AIF2RX_WL_MASK                   0x3F00  /* AIF2RX_WL - [13:8] */
+#define ARIZONA_AIF2RX_WL_SHIFT                       8  /* AIF2RX_WL - [13:8] */
+#define ARIZONA_AIF2RX_WL_WIDTH                       6  /* AIF2RX_WL - [13:8] */
+#define ARIZONA_AIF2RX_SLOT_LEN_MASK             0x00FF  /* AIF2RX_SLOT_LEN - [7:0] */
+#define ARIZONA_AIF2RX_SLOT_LEN_SHIFT                 0  /* AIF2RX_SLOT_LEN - [7:0] */
+#define ARIZONA_AIF2RX_SLOT_LEN_WIDTH                 8  /* AIF2RX_SLOT_LEN - [7:0] */
+
+/*
+ * R1353 (0x549) - AIF2 Frame Ctrl 3
+ */
+#define ARIZONA_AIF2TX1_SLOT_MASK                0x003F  /* AIF2TX1_SLOT - [5:0] */
+#define ARIZONA_AIF2TX1_SLOT_SHIFT                    0  /* AIF2TX1_SLOT - [5:0] */
+#define ARIZONA_AIF2TX1_SLOT_WIDTH                    6  /* AIF2TX1_SLOT - [5:0] */
+
+/*
+ * R1354 (0x54A) - AIF2 Frame Ctrl 4
+ */
+#define ARIZONA_AIF2TX2_SLOT_MASK                0x003F  /* AIF2TX2_SLOT - [5:0] */
+#define ARIZONA_AIF2TX2_SLOT_SHIFT                    0  /* AIF2TX2_SLOT - [5:0] */
+#define ARIZONA_AIF2TX2_SLOT_WIDTH                    6  /* AIF2TX2_SLOT - [5:0] */
+
+/*
+ * R1361 (0x551) - AIF2 Frame Ctrl 11
+ */
+#define ARIZONA_AIF2RX1_SLOT_MASK                0x003F  /* AIF2RX1_SLOT - [5:0] */
+#define ARIZONA_AIF2RX1_SLOT_SHIFT                    0  /* AIF2RX1_SLOT - [5:0] */
+#define ARIZONA_AIF2RX1_SLOT_WIDTH                    6  /* AIF2RX1_SLOT - [5:0] */
+
+/*
+ * R1362 (0x552) - AIF2 Frame Ctrl 12
+ */
+#define ARIZONA_AIF2RX2_SLOT_MASK                0x003F  /* AIF2RX2_SLOT - [5:0] */
+#define ARIZONA_AIF2RX2_SLOT_SHIFT                    0  /* AIF2RX2_SLOT - [5:0] */
+#define ARIZONA_AIF2RX2_SLOT_WIDTH                    6  /* AIF2RX2_SLOT - [5:0] */
+
+/*
+ * R1369 (0x559) - AIF2 Tx Enables
+ */
+#define ARIZONA_AIF2TX2_ENA                      0x0002  /* AIF2TX2_ENA */
+#define ARIZONA_AIF2TX2_ENA_MASK                 0x0002  /* AIF2TX2_ENA */
+#define ARIZONA_AIF2TX2_ENA_SHIFT                     1  /* AIF2TX2_ENA */
+#define ARIZONA_AIF2TX2_ENA_WIDTH                     1  /* AIF2TX2_ENA */
+#define ARIZONA_AIF2TX1_ENA                      0x0001  /* AIF2TX1_ENA */
+#define ARIZONA_AIF2TX1_ENA_MASK                 0x0001  /* AIF2TX1_ENA */
+#define ARIZONA_AIF2TX1_ENA_SHIFT                     0  /* AIF2TX1_ENA */
+#define ARIZONA_AIF2TX1_ENA_WIDTH                     1  /* AIF2TX1_ENA */
+
+/*
+ * R1370 (0x55A) - AIF2 Rx Enables
+ */
+#define ARIZONA_AIF2RX2_ENA                      0x0002  /* AIF2RX2_ENA */
+#define ARIZONA_AIF2RX2_ENA_MASK                 0x0002  /* AIF2RX2_ENA */
+#define ARIZONA_AIF2RX2_ENA_SHIFT                     1  /* AIF2RX2_ENA */
+#define ARIZONA_AIF2RX2_ENA_WIDTH                     1  /* AIF2RX2_ENA */
+#define ARIZONA_AIF2RX1_ENA                      0x0001  /* AIF2RX1_ENA */
+#define ARIZONA_AIF2RX1_ENA_MASK                 0x0001  /* AIF2RX1_ENA */
+#define ARIZONA_AIF2RX1_ENA_SHIFT                     0  /* AIF2RX1_ENA */
+#define ARIZONA_AIF2RX1_ENA_WIDTH                     1  /* AIF2RX1_ENA */
+
+/*
+ * R1371 (0x55B) - AIF2 Force Write
+ */
+#define ARIZONA_AIF2_FRC_WR                      0x0001  /* AIF2_FRC_WR */
+#define ARIZONA_AIF2_FRC_WR_MASK                 0x0001  /* AIF2_FRC_WR */
+#define ARIZONA_AIF2_FRC_WR_SHIFT                     0  /* AIF2_FRC_WR */
+#define ARIZONA_AIF2_FRC_WR_WIDTH                     1  /* AIF2_FRC_WR */
+
+/*
+ * R1408 (0x580) - AIF3 BCLK Ctrl
+ */
+#define ARIZONA_AIF3_BCLK_INV                    0x0080  /* AIF3_BCLK_INV */
+#define ARIZONA_AIF3_BCLK_INV_MASK               0x0080  /* AIF3_BCLK_INV */
+#define ARIZONA_AIF3_BCLK_INV_SHIFT                   7  /* AIF3_BCLK_INV */
+#define ARIZONA_AIF3_BCLK_INV_WIDTH                   1  /* AIF3_BCLK_INV */
+#define ARIZONA_AIF3_BCLK_FRC                    0x0040  /* AIF3_BCLK_FRC */
+#define ARIZONA_AIF3_BCLK_FRC_MASK               0x0040  /* AIF3_BCLK_FRC */
+#define ARIZONA_AIF3_BCLK_FRC_SHIFT                   6  /* AIF3_BCLK_FRC */
+#define ARIZONA_AIF3_BCLK_FRC_WIDTH                   1  /* AIF3_BCLK_FRC */
+#define ARIZONA_AIF3_BCLK_MSTR                   0x0020  /* AIF3_BCLK_MSTR */
+#define ARIZONA_AIF3_BCLK_MSTR_MASK              0x0020  /* AIF3_BCLK_MSTR */
+#define ARIZONA_AIF3_BCLK_MSTR_SHIFT                  5  /* AIF3_BCLK_MSTR */
+#define ARIZONA_AIF3_BCLK_MSTR_WIDTH                  1  /* AIF3_BCLK_MSTR */
+#define ARIZONA_AIF3_BCLK_FREQ_MASK              0x001F  /* AIF3_BCLK_FREQ - [4:0] */
+#define ARIZONA_AIF3_BCLK_FREQ_SHIFT                  0  /* AIF3_BCLK_FREQ - [4:0] */
+#define ARIZONA_AIF3_BCLK_FREQ_WIDTH                  5  /* AIF3_BCLK_FREQ - [4:0] */
+
+/*
+ * R1409 (0x581) - AIF3 Tx Pin Ctrl
+ */
+#define ARIZONA_AIF3TX_DAT_TRI                   0x0020  /* AIF3TX_DAT_TRI */
+#define ARIZONA_AIF3TX_DAT_TRI_MASK              0x0020  /* AIF3TX_DAT_TRI */
+#define ARIZONA_AIF3TX_DAT_TRI_SHIFT                  5  /* AIF3TX_DAT_TRI */
+#define ARIZONA_AIF3TX_DAT_TRI_WIDTH                  1  /* AIF3TX_DAT_TRI */
+#define ARIZONA_AIF3TX_LRCLK_SRC                 0x0008  /* AIF3TX_LRCLK_SRC */
+#define ARIZONA_AIF3TX_LRCLK_SRC_MASK            0x0008  /* AIF3TX_LRCLK_SRC */
+#define ARIZONA_AIF3TX_LRCLK_SRC_SHIFT                3  /* AIF3TX_LRCLK_SRC */
+#define ARIZONA_AIF3TX_LRCLK_SRC_WIDTH                1  /* AIF3TX_LRCLK_SRC */
+#define ARIZONA_AIF3TX_LRCLK_INV                 0x0004  /* AIF3TX_LRCLK_INV */
+#define ARIZONA_AIF3TX_LRCLK_INV_MASK            0x0004  /* AIF3TX_LRCLK_INV */
+#define ARIZONA_AIF3TX_LRCLK_INV_SHIFT                2  /* AIF3TX_LRCLK_INV */
+#define ARIZONA_AIF3TX_LRCLK_INV_WIDTH                1  /* AIF3TX_LRCLK_INV */
+#define ARIZONA_AIF3TX_LRCLK_FRC                 0x0002  /* AIF3TX_LRCLK_FRC */
+#define ARIZONA_AIF3TX_LRCLK_FRC_MASK            0x0002  /* AIF3TX_LRCLK_FRC */
+#define ARIZONA_AIF3TX_LRCLK_FRC_SHIFT                1  /* AIF3TX_LRCLK_FRC */
+#define ARIZONA_AIF3TX_LRCLK_FRC_WIDTH                1  /* AIF3TX_LRCLK_FRC */
+#define ARIZONA_AIF3TX_LRCLK_MSTR                0x0001  /* AIF3TX_LRCLK_MSTR */
+#define ARIZONA_AIF3TX_LRCLK_MSTR_MASK           0x0001  /* AIF3TX_LRCLK_MSTR */
+#define ARIZONA_AIF3TX_LRCLK_MSTR_SHIFT               0  /* AIF3TX_LRCLK_MSTR */
+#define ARIZONA_AIF3TX_LRCLK_MSTR_WIDTH               1  /* AIF3TX_LRCLK_MSTR */
+
+/*
+ * R1410 (0x582) - AIF3 Rx Pin Ctrl
+ */
+#define ARIZONA_AIF3RX_LRCLK_INV                 0x0004  /* AIF3RX_LRCLK_INV */
+#define ARIZONA_AIF3RX_LRCLK_INV_MASK            0x0004  /* AIF3RX_LRCLK_INV */
+#define ARIZONA_AIF3RX_LRCLK_INV_SHIFT                2  /* AIF3RX_LRCLK_INV */
+#define ARIZONA_AIF3RX_LRCLK_INV_WIDTH                1  /* AIF3RX_LRCLK_INV */
+#define ARIZONA_AIF3RX_LRCLK_FRC                 0x0002  /* AIF3RX_LRCLK_FRC */
+#define ARIZONA_AIF3RX_LRCLK_FRC_MASK            0x0002  /* AIF3RX_LRCLK_FRC */
+#define ARIZONA_AIF3RX_LRCLK_FRC_SHIFT                1  /* AIF3RX_LRCLK_FRC */
+#define ARIZONA_AIF3RX_LRCLK_FRC_WIDTH                1  /* AIF3RX_LRCLK_FRC */
+#define ARIZONA_AIF3RX_LRCLK_MSTR                0x0001  /* AIF3RX_LRCLK_MSTR */
+#define ARIZONA_AIF3RX_LRCLK_MSTR_MASK           0x0001  /* AIF3RX_LRCLK_MSTR */
+#define ARIZONA_AIF3RX_LRCLK_MSTR_SHIFT               0  /* AIF3RX_LRCLK_MSTR */
+#define ARIZONA_AIF3RX_LRCLK_MSTR_WIDTH               1  /* AIF3RX_LRCLK_MSTR */
+
+/*
+ * R1411 (0x583) - AIF3 Rate Ctrl
+ */
+#define ARIZONA_AIF3_RATE_MASK                   0x7800  /* AIF3_RATE - [14:11] */
+#define ARIZONA_AIF3_RATE_SHIFT                      11  /* AIF3_RATE - [14:11] */
+#define ARIZONA_AIF3_RATE_WIDTH                       4  /* AIF3_RATE - [14:11] */
+#define ARIZONA_AIF3_TRI                         0x0040  /* AIF3_TRI */
+#define ARIZONA_AIF3_TRI_MASK                    0x0040  /* AIF3_TRI */
+#define ARIZONA_AIF3_TRI_SHIFT                        6  /* AIF3_TRI */
+#define ARIZONA_AIF3_TRI_WIDTH                        1  /* AIF3_TRI */
+
+/*
+ * R1412 (0x584) - AIF3 Format
+ */
+#define ARIZONA_AIF3_FMT_MASK                    0x0007  /* AIF3_FMT - [2:0] */
+#define ARIZONA_AIF3_FMT_SHIFT                        0  /* AIF3_FMT - [2:0] */
+#define ARIZONA_AIF3_FMT_WIDTH                        3  /* AIF3_FMT - [2:0] */
+
+/*
+ * R1413 (0x585) - AIF3 Tx BCLK Rate
+ */
+#define ARIZONA_AIF3TX_BCPF_MASK                 0x1FFF  /* AIF3TX_BCPF - [12:0] */
+#define ARIZONA_AIF3TX_BCPF_SHIFT                     0  /* AIF3TX_BCPF - [12:0] */
+#define ARIZONA_AIF3TX_BCPF_WIDTH                    13  /* AIF3TX_BCPF - [12:0] */
+
+/*
+ * R1414 (0x586) - AIF3 Rx BCLK Rate
+ */
+#define ARIZONA_AIF3RX_BCPF_MASK                 0x1FFF  /* AIF3RX_BCPF - [12:0] */
+#define ARIZONA_AIF3RX_BCPF_SHIFT                     0  /* AIF3RX_BCPF - [12:0] */
+#define ARIZONA_AIF3RX_BCPF_WIDTH                    13  /* AIF3RX_BCPF - [12:0] */
+
+/*
+ * R1415 (0x587) - AIF3 Frame Ctrl 1
+ */
+#define ARIZONA_AIF3TX_WL_MASK                   0x3F00  /* AIF3TX_WL - [13:8] */
+#define ARIZONA_AIF3TX_WL_SHIFT                       8  /* AIF3TX_WL - [13:8] */
+#define ARIZONA_AIF3TX_WL_WIDTH                       6  /* AIF3TX_WL - [13:8] */
+#define ARIZONA_AIF3TX_SLOT_LEN_MASK             0x00FF  /* AIF3TX_SLOT_LEN - [7:0] */
+#define ARIZONA_AIF3TX_SLOT_LEN_SHIFT                 0  /* AIF3TX_SLOT_LEN - [7:0] */
+#define ARIZONA_AIF3TX_SLOT_LEN_WIDTH                 8  /* AIF3TX_SLOT_LEN - [7:0] */
+
+/*
+ * R1416 (0x588) - AIF3 Frame Ctrl 2
+ */
+#define ARIZONA_AIF3RX_WL_MASK                   0x3F00  /* AIF3RX_WL - [13:8] */
+#define ARIZONA_AIF3RX_WL_SHIFT                       8  /* AIF3RX_WL - [13:8] */
+#define ARIZONA_AIF3RX_WL_WIDTH                       6  /* AIF3RX_WL - [13:8] */
+#define ARIZONA_AIF3RX_SLOT_LEN_MASK             0x00FF  /* AIF3RX_SLOT_LEN - [7:0] */
+#define ARIZONA_AIF3RX_SLOT_LEN_SHIFT                 0  /* AIF3RX_SLOT_LEN - [7:0] */
+#define ARIZONA_AIF3RX_SLOT_LEN_WIDTH                 8  /* AIF3RX_SLOT_LEN - [7:0] */
+
+/*
+ * R1417 (0x589) - AIF3 Frame Ctrl 3
+ */
+#define ARIZONA_AIF3TX1_SLOT_MASK                0x003F  /* AIF3TX1_SLOT - [5:0] */
+#define ARIZONA_AIF3TX1_SLOT_SHIFT                    0  /* AIF3TX1_SLOT - [5:0] */
+#define ARIZONA_AIF3TX1_SLOT_WIDTH                    6  /* AIF3TX1_SLOT - [5:0] */
+
+/*
+ * R1418 (0x58A) - AIF3 Frame Ctrl 4
+ */
+#define ARIZONA_AIF3TX2_SLOT_MASK                0x003F  /* AIF3TX2_SLOT - [5:0] */
+#define ARIZONA_AIF3TX2_SLOT_SHIFT                    0  /* AIF3TX2_SLOT - [5:0] */
+#define ARIZONA_AIF3TX2_SLOT_WIDTH                    6  /* AIF3TX2_SLOT - [5:0] */
+
+/*
+ * R1425 (0x591) - AIF3 Frame Ctrl 11
+ */
+#define ARIZONA_AIF3RX1_SLOT_MASK                0x003F  /* AIF3RX1_SLOT - [5:0] */
+#define ARIZONA_AIF3RX1_SLOT_SHIFT                    0  /* AIF3RX1_SLOT - [5:0] */
+#define ARIZONA_AIF3RX1_SLOT_WIDTH                    6  /* AIF3RX1_SLOT - [5:0] */
+
+/*
+ * R1426 (0x592) - AIF3 Frame Ctrl 12
+ */
+#define ARIZONA_AIF3RX2_SLOT_MASK                0x003F  /* AIF3RX2_SLOT - [5:0] */
+#define ARIZONA_AIF3RX2_SLOT_SHIFT                    0  /* AIF3RX2_SLOT - [5:0] */
+#define ARIZONA_AIF3RX2_SLOT_WIDTH                    6  /* AIF3RX2_SLOT - [5:0] */
+
+/*
+ * R1433 (0x599) - AIF3 Tx Enables
+ */
+#define ARIZONA_AIF3TX2_ENA                      0x0002  /* AIF3TX2_ENA */
+#define ARIZONA_AIF3TX2_ENA_MASK                 0x0002  /* AIF3TX2_ENA */
+#define ARIZONA_AIF3TX2_ENA_SHIFT                     1  /* AIF3TX2_ENA */
+#define ARIZONA_AIF3TX2_ENA_WIDTH                     1  /* AIF3TX2_ENA */
+#define ARIZONA_AIF3TX1_ENA                      0x0001  /* AIF3TX1_ENA */
+#define ARIZONA_AIF3TX1_ENA_MASK                 0x0001  /* AIF3TX1_ENA */
+#define ARIZONA_AIF3TX1_ENA_SHIFT                     0  /* AIF3TX1_ENA */
+#define ARIZONA_AIF3TX1_ENA_WIDTH                     1  /* AIF3TX1_ENA */
+
+/*
+ * R1434 (0x59A) - AIF3 Rx Enables
+ */
+#define ARIZONA_AIF3RX2_ENA                      0x0002  /* AIF3RX2_ENA */
+#define ARIZONA_AIF3RX2_ENA_MASK                 0x0002  /* AIF3RX2_ENA */
+#define ARIZONA_AIF3RX2_ENA_SHIFT                     1  /* AIF3RX2_ENA */
+#define ARIZONA_AIF3RX2_ENA_WIDTH                     1  /* AIF3RX2_ENA */
+#define ARIZONA_AIF3RX1_ENA                      0x0001  /* AIF3RX1_ENA */
+#define ARIZONA_AIF3RX1_ENA_MASK                 0x0001  /* AIF3RX1_ENA */
+#define ARIZONA_AIF3RX1_ENA_SHIFT                     0  /* AIF3RX1_ENA */
+#define ARIZONA_AIF3RX1_ENA_WIDTH                     1  /* AIF3RX1_ENA */
+
+/*
+ * R1435 (0x59B) - AIF3 Force Write
+ */
+#define ARIZONA_AIF3_FRC_WR                      0x0001  /* AIF3_FRC_WR */
+#define ARIZONA_AIF3_FRC_WR_MASK                 0x0001  /* AIF3_FRC_WR */
+#define ARIZONA_AIF3_FRC_WR_SHIFT                     0  /* AIF3_FRC_WR */
+#define ARIZONA_AIF3_FRC_WR_WIDTH                     1  /* AIF3_FRC_WR */
+
+/*
+ * R1507 (0x5E3) - SLIMbus Framer Ref Gear
+ */
+#define ARIZONA_SLIMCLK_SRC                      0x0010  /* SLIMCLK_SRC */
+#define ARIZONA_SLIMCLK_SRC_MASK                 0x0010  /* SLIMCLK_SRC */
+#define ARIZONA_SLIMCLK_SRC_SHIFT                     4  /* SLIMCLK_SRC */
+#define ARIZONA_SLIMCLK_SRC_WIDTH                     1  /* SLIMCLK_SRC */
+#define ARIZONA_FRAMER_REF_GEAR_MASK             0x000F  /* FRAMER_REF_GEAR - [3:0] */
+#define ARIZONA_FRAMER_REF_GEAR_SHIFT                 0  /* FRAMER_REF_GEAR - [3:0] */
+#define ARIZONA_FRAMER_REF_GEAR_WIDTH                 4  /* FRAMER_REF_GEAR - [3:0] */
+
+/*
+ * R1509 (0x5E5) - SLIMbus Rates 1
+ */
+#define ARIZONA_SLIMRX2_RATE_MASK                0x7800  /* SLIMRX2_RATE - [14:11] */
+#define ARIZONA_SLIMRX2_RATE_SHIFT                   11  /* SLIMRX2_RATE - [14:11] */
+#define ARIZONA_SLIMRX2_RATE_WIDTH                    4  /* SLIMRX2_RATE - [14:11] */
+#define ARIZONA_SLIMRX1_RATE_MASK                0x0078  /* SLIMRX1_RATE - [6:3] */
+#define ARIZONA_SLIMRX1_RATE_SHIFT                    3  /* SLIMRX1_RATE - [6:3] */
+#define ARIZONA_SLIMRX1_RATE_WIDTH                    4  /* SLIMRX1_RATE - [6:3] */
+
+/*
+ * R1510 (0x5E6) - SLIMbus Rates 2
+ */
+#define ARIZONA_SLIMRX4_RATE_MASK                0x7800  /* SLIMRX4_RATE - [14:11] */
+#define ARIZONA_SLIMRX4_RATE_SHIFT                   11  /* SLIMRX4_RATE - [14:11] */
+#define ARIZONA_SLIMRX4_RATE_WIDTH                    4  /* SLIMRX4_RATE - [14:11] */
+#define ARIZONA_SLIMRX3_RATE_MASK                0x0078  /* SLIMRX3_RATE - [6:3] */
+#define ARIZONA_SLIMRX3_RATE_SHIFT                    3  /* SLIMRX3_RATE - [6:3] */
+#define ARIZONA_SLIMRX3_RATE_WIDTH                    4  /* SLIMRX3_RATE - [6:3] */
+
+/*
+ * R1511 (0x5E7) - SLIMbus Rates 3
+ */
+#define ARIZONA_SLIMRX6_RATE_MASK                0x7800  /* SLIMRX6_RATE - [14:11] */
+#define ARIZONA_SLIMRX6_RATE_SHIFT                   11  /* SLIMRX6_RATE - [14:11] */
+#define ARIZONA_SLIMRX6_RATE_WIDTH                    4  /* SLIMRX6_RATE - [14:11] */
+#define ARIZONA_SLIMRX5_RATE_MASK                0x0078  /* SLIMRX5_RATE - [6:3] */
+#define ARIZONA_SLIMRX5_RATE_SHIFT                    3  /* SLIMRX5_RATE - [6:3] */
+#define ARIZONA_SLIMRX5_RATE_WIDTH                    4  /* SLIMRX5_RATE - [6:3] */
+
+/*
+ * R1512 (0x5E8) - SLIMbus Rates 4
+ */
+#define ARIZONA_SLIMRX8_RATE_MASK                0x7800  /* SLIMRX8_RATE - [14:11] */
+#define ARIZONA_SLIMRX8_RATE_SHIFT                   11  /* SLIMRX8_RATE - [14:11] */
+#define ARIZONA_SLIMRX8_RATE_WIDTH                    4  /* SLIMRX8_RATE - [14:11] */
+#define ARIZONA_SLIMRX7_RATE_MASK                0x0078  /* SLIMRX7_RATE - [6:3] */
+#define ARIZONA_SLIMRX7_RATE_SHIFT                    3  /* SLIMRX7_RATE - [6:3] */
+#define ARIZONA_SLIMRX7_RATE_WIDTH                    4  /* SLIMRX7_RATE - [6:3] */
+
+/*
+ * R1513 (0x5E9) - SLIMbus Rates 5
+ */
+#define ARIZONA_SLIMTX2_RATE_MASK                0x7800  /* SLIMTX2_RATE - [14:11] */
+#define ARIZONA_SLIMTX2_RATE_SHIFT                   11  /* SLIMTX2_RATE - [14:11] */
+#define ARIZONA_SLIMTX2_RATE_WIDTH                    4  /* SLIMTX2_RATE - [14:11] */
+#define ARIZONA_SLIMTX1_RATE_MASK                0x0078  /* SLIMTX1_RATE - [6:3] */
+#define ARIZONA_SLIMTX1_RATE_SHIFT                    3  /* SLIMTX1_RATE - [6:3] */
+#define ARIZONA_SLIMTX1_RATE_WIDTH                    4  /* SLIMTX1_RATE - [6:3] */
+
+/*
+ * R1514 (0x5EA) - SLIMbus Rates 6
+ */
+#define ARIZONA_SLIMTX4_RATE_MASK                0x7800  /* SLIMTX4_RATE - [14:11] */
+#define ARIZONA_SLIMTX4_RATE_SHIFT                   11  /* SLIMTX4_RATE - [14:11] */
+#define ARIZONA_SLIMTX4_RATE_WIDTH                    4  /* SLIMTX4_RATE - [14:11] */
+#define ARIZONA_SLIMTX3_RATE_MASK                0x0078  /* SLIMTX3_RATE - [6:3] */
+#define ARIZONA_SLIMTX3_RATE_SHIFT                    3  /* SLIMTX3_RATE - [6:3] */
+#define ARIZONA_SLIMTX3_RATE_WIDTH                    4  /* SLIMTX3_RATE - [6:3] */
+
+/*
+ * R1515 (0x5EB) - SLIMbus Rates 7
+ */
+#define ARIZONA_SLIMTX6_RATE_MASK                0x7800  /* SLIMTX6_RATE - [14:11] */
+#define ARIZONA_SLIMTX6_RATE_SHIFT                   11  /* SLIMTX6_RATE - [14:11] */
+#define ARIZONA_SLIMTX6_RATE_WIDTH                    4  /* SLIMTX6_RATE - [14:11] */
+#define ARIZONA_SLIMTX5_RATE_MASK                0x0078  /* SLIMTX5_RATE - [6:3] */
+#define ARIZONA_SLIMTX5_RATE_SHIFT                    3  /* SLIMTX5_RATE - [6:3] */
+#define ARIZONA_SLIMTX5_RATE_WIDTH                    4  /* SLIMTX5_RATE - [6:3] */
+
+/*
+ * R1516 (0x5EC) - SLIMbus Rates 8
+ */
+#define ARIZONA_SLIMTX8_RATE_MASK                0x7800  /* SLIMTX8_RATE - [14:11] */
+#define ARIZONA_SLIMTX8_RATE_SHIFT                   11  /* SLIMTX8_RATE - [14:11] */
+#define ARIZONA_SLIMTX8_RATE_WIDTH                    4  /* SLIMTX8_RATE - [14:11] */
+#define ARIZONA_SLIMTX7_RATE_MASK                0x0078  /* SLIMTX7_RATE - [6:3] */
+#define ARIZONA_SLIMTX7_RATE_SHIFT                    3  /* SLIMTX7_RATE - [6:3] */
+#define ARIZONA_SLIMTX7_RATE_WIDTH                    4  /* SLIMTX7_RATE - [6:3] */
+
+/*
+ * R1525 (0x5F5) - SLIMbus RX Channel Enable
+ */
+#define ARIZONA_SLIMRX8_ENA                      0x0080  /* SLIMRX8_ENA */
+#define ARIZONA_SLIMRX8_ENA_MASK                 0x0080  /* SLIMRX8_ENA */
+#define ARIZONA_SLIMRX8_ENA_SHIFT                     7  /* SLIMRX8_ENA */
+#define ARIZONA_SLIMRX8_ENA_WIDTH                     1  /* SLIMRX8_ENA */
+#define ARIZONA_SLIMRX7_ENA                      0x0040  /* SLIMRX7_ENA */
+#define ARIZONA_SLIMRX7_ENA_MASK                 0x0040  /* SLIMRX7_ENA */
+#define ARIZONA_SLIMRX7_ENA_SHIFT                     6  /* SLIMRX7_ENA */
+#define ARIZONA_SLIMRX7_ENA_WIDTH                     1  /* SLIMRX7_ENA */
+#define ARIZONA_SLIMRX6_ENA                      0x0020  /* SLIMRX6_ENA */
+#define ARIZONA_SLIMRX6_ENA_MASK                 0x0020  /* SLIMRX6_ENA */
+#define ARIZONA_SLIMRX6_ENA_SHIFT                     5  /* SLIMRX6_ENA */
+#define ARIZONA_SLIMRX6_ENA_WIDTH                     1  /* SLIMRX6_ENA */
+#define ARIZONA_SLIMRX5_ENA                      0x0010  /* SLIMRX5_ENA */
+#define ARIZONA_SLIMRX5_ENA_MASK                 0x0010  /* SLIMRX5_ENA */
+#define ARIZONA_SLIMRX5_ENA_SHIFT                     4  /* SLIMRX5_ENA */
+#define ARIZONA_SLIMRX5_ENA_WIDTH                     1  /* SLIMRX5_ENA */
+#define ARIZONA_SLIMRX4_ENA                      0x0008  /* SLIMRX4_ENA */
+#define ARIZONA_SLIMRX4_ENA_MASK                 0x0008  /* SLIMRX4_ENA */
+#define ARIZONA_SLIMRX4_ENA_SHIFT                     3  /* SLIMRX4_ENA */
+#define ARIZONA_SLIMRX4_ENA_WIDTH                     1  /* SLIMRX4_ENA */
+#define ARIZONA_SLIMRX3_ENA                      0x0004  /* SLIMRX3_ENA */
+#define ARIZONA_SLIMRX3_ENA_MASK                 0x0004  /* SLIMRX3_ENA */
+#define ARIZONA_SLIMRX3_ENA_SHIFT                     2  /* SLIMRX3_ENA */
+#define ARIZONA_SLIMRX3_ENA_WIDTH                     1  /* SLIMRX3_ENA */
+#define ARIZONA_SLIMRX2_ENA                      0x0002  /* SLIMRX2_ENA */
+#define ARIZONA_SLIMRX2_ENA_MASK                 0x0002  /* SLIMRX2_ENA */
+#define ARIZONA_SLIMRX2_ENA_SHIFT                     1  /* SLIMRX2_ENA */
+#define ARIZONA_SLIMRX2_ENA_WIDTH                     1  /* SLIMRX2_ENA */
+#define ARIZONA_SLIMRX1_ENA                      0x0001  /* SLIMRX1_ENA */
+#define ARIZONA_SLIMRX1_ENA_MASK                 0x0001  /* SLIMRX1_ENA */
+#define ARIZONA_SLIMRX1_ENA_SHIFT                     0  /* SLIMRX1_ENA */
+#define ARIZONA_SLIMRX1_ENA_WIDTH                     1  /* SLIMRX1_ENA */
+
+/*
+ * R1526 (0x5F6) - SLIMbus TX Channel Enable
+ */
+#define ARIZONA_SLIMTX8_ENA                      0x0080  /* SLIMTX8_ENA */
+#define ARIZONA_SLIMTX8_ENA_MASK                 0x0080  /* SLIMTX8_ENA */
+#define ARIZONA_SLIMTX8_ENA_SHIFT                     7  /* SLIMTX8_ENA */
+#define ARIZONA_SLIMTX8_ENA_WIDTH                     1  /* SLIMTX8_ENA */
+#define ARIZONA_SLIMTX7_ENA                      0x0040  /* SLIMTX7_ENA */
+#define ARIZONA_SLIMTX7_ENA_MASK                 0x0040  /* SLIMTX7_ENA */
+#define ARIZONA_SLIMTX7_ENA_SHIFT                     6  /* SLIMTX7_ENA */
+#define ARIZONA_SLIMTX7_ENA_WIDTH                     1  /* SLIMTX7_ENA */
+#define ARIZONA_SLIMTX6_ENA                      0x0020  /* SLIMTX6_ENA */
+#define ARIZONA_SLIMTX6_ENA_MASK                 0x0020  /* SLIMTX6_ENA */
+#define ARIZONA_SLIMTX6_ENA_SHIFT                     5  /* SLIMTX6_ENA */
+#define ARIZONA_SLIMTX6_ENA_WIDTH                     1  /* SLIMTX6_ENA */
+#define ARIZONA_SLIMTX5_ENA                      0x0010  /* SLIMTX5_ENA */
+#define ARIZONA_SLIMTX5_ENA_MASK                 0x0010  /* SLIMTX5_ENA */
+#define ARIZONA_SLIMTX5_ENA_SHIFT                     4  /* SLIMTX5_ENA */
+#define ARIZONA_SLIMTX5_ENA_WIDTH                     1  /* SLIMTX5_ENA */
+#define ARIZONA_SLIMTX4_ENA                      0x0008  /* SLIMTX4_ENA */
+#define ARIZONA_SLIMTX4_ENA_MASK                 0x0008  /* SLIMTX4_ENA */
+#define ARIZONA_SLIMTX4_ENA_SHIFT                     3  /* SLIMTX4_ENA */
+#define ARIZONA_SLIMTX4_ENA_WIDTH                     1  /* SLIMTX4_ENA */
+#define ARIZONA_SLIMTX3_ENA                      0x0004  /* SLIMTX3_ENA */
+#define ARIZONA_SLIMTX3_ENA_MASK                 0x0004  /* SLIMTX3_ENA */
+#define ARIZONA_SLIMTX3_ENA_SHIFT                     2  /* SLIMTX3_ENA */
+#define ARIZONA_SLIMTX3_ENA_WIDTH                     1  /* SLIMTX3_ENA */
+#define ARIZONA_SLIMTX2_ENA                      0x0002  /* SLIMTX2_ENA */
+#define ARIZONA_SLIMTX2_ENA_MASK                 0x0002  /* SLIMTX2_ENA */
+#define ARIZONA_SLIMTX2_ENA_SHIFT                     1  /* SLIMTX2_ENA */
+#define ARIZONA_SLIMTX2_ENA_WIDTH                     1  /* SLIMTX2_ENA */
+#define ARIZONA_SLIMTX1_ENA                      0x0001  /* SLIMTX1_ENA */
+#define ARIZONA_SLIMTX1_ENA_MASK                 0x0001  /* SLIMTX1_ENA */
+#define ARIZONA_SLIMTX1_ENA_SHIFT                     0  /* SLIMTX1_ENA */
+#define ARIZONA_SLIMTX1_ENA_WIDTH                     1  /* SLIMTX1_ENA */
+
+/*
+ * R1527 (0x5F7) - SLIMbus RX Port Status
+ */
+#define ARIZONA_SLIMRX8_PORT_STS                 0x0080  /* SLIMRX8_PORT_STS */
+#define ARIZONA_SLIMRX8_PORT_STS_MASK            0x0080  /* SLIMRX8_PORT_STS */
+#define ARIZONA_SLIMRX8_PORT_STS_SHIFT                7  /* SLIMRX8_PORT_STS */
+#define ARIZONA_SLIMRX8_PORT_STS_WIDTH                1  /* SLIMRX8_PORT_STS */
+#define ARIZONA_SLIMRX7_PORT_STS                 0x0040  /* SLIMRX7_PORT_STS */
+#define ARIZONA_SLIMRX7_PORT_STS_MASK            0x0040  /* SLIMRX7_PORT_STS */
+#define ARIZONA_SLIMRX7_PORT_STS_SHIFT                6  /* SLIMRX7_PORT_STS */
+#define ARIZONA_SLIMRX7_PORT_STS_WIDTH                1  /* SLIMRX7_PORT_STS */
+#define ARIZONA_SLIMRX6_PORT_STS                 0x0020  /* SLIMRX6_PORT_STS */
+#define ARIZONA_SLIMRX6_PORT_STS_MASK            0x0020  /* SLIMRX6_PORT_STS */
+#define ARIZONA_SLIMRX6_PORT_STS_SHIFT                5  /* SLIMRX6_PORT_STS */
+#define ARIZONA_SLIMRX6_PORT_STS_WIDTH                1  /* SLIMRX6_PORT_STS */
+#define ARIZONA_SLIMRX5_PORT_STS                 0x0010  /* SLIMRX5_PORT_STS */
+#define ARIZONA_SLIMRX5_PORT_STS_MASK            0x0010  /* SLIMRX5_PORT_STS */
+#define ARIZONA_SLIMRX5_PORT_STS_SHIFT                4  /* SLIMRX5_PORT_STS */
+#define ARIZONA_SLIMRX5_PORT_STS_WIDTH                1  /* SLIMRX5_PORT_STS */
+#define ARIZONA_SLIMRX4_PORT_STS                 0x0008  /* SLIMRX4_PORT_STS */
+#define ARIZONA_SLIMRX4_PORT_STS_MASK            0x0008  /* SLIMRX4_PORT_STS */
+#define ARIZONA_SLIMRX4_PORT_STS_SHIFT                3  /* SLIMRX4_PORT_STS */
+#define ARIZONA_SLIMRX4_PORT_STS_WIDTH                1  /* SLIMRX4_PORT_STS */
+#define ARIZONA_SLIMRX3_PORT_STS                 0x0004  /* SLIMRX3_PORT_STS */
+#define ARIZONA_SLIMRX3_PORT_STS_MASK            0x0004  /* SLIMRX3_PORT_STS */
+#define ARIZONA_SLIMRX3_PORT_STS_SHIFT                2  /* SLIMRX3_PORT_STS */
+#define ARIZONA_SLIMRX3_PORT_STS_WIDTH                1  /* SLIMRX3_PORT_STS */
+#define ARIZONA_SLIMRX2_PORT_STS                 0x0002  /* SLIMRX2_PORT_STS */
+#define ARIZONA_SLIMRX2_PORT_STS_MASK            0x0002  /* SLIMRX2_PORT_STS */
+#define ARIZONA_SLIMRX2_PORT_STS_SHIFT                1  /* SLIMRX2_PORT_STS */
+#define ARIZONA_SLIMRX2_PORT_STS_WIDTH                1  /* SLIMRX2_PORT_STS */
+#define ARIZONA_SLIMRX1_PORT_STS                 0x0001  /* SLIMRX1_PORT_STS */
+#define ARIZONA_SLIMRX1_PORT_STS_MASK            0x0001  /* SLIMRX1_PORT_STS */
+#define ARIZONA_SLIMRX1_PORT_STS_SHIFT                0  /* SLIMRX1_PORT_STS */
+#define ARIZONA_SLIMRX1_PORT_STS_WIDTH                1  /* SLIMRX1_PORT_STS */
+
+/*
+ * R1528 (0x5F8) - SLIMbus TX Port Status
+ */
+#define ARIZONA_SLIMTX8_PORT_STS                 0x0080  /* SLIMTX8_PORT_STS */
+#define ARIZONA_SLIMTX8_PORT_STS_MASK            0x0080  /* SLIMTX8_PORT_STS */
+#define ARIZONA_SLIMTX8_PORT_STS_SHIFT                7  /* SLIMTX8_PORT_STS */
+#define ARIZONA_SLIMTX8_PORT_STS_WIDTH                1  /* SLIMTX8_PORT_STS */
+#define ARIZONA_SLIMTX7_PORT_STS                 0x0040  /* SLIMTX7_PORT_STS */
+#define ARIZONA_SLIMTX7_PORT_STS_MASK            0x0040  /* SLIMTX7_PORT_STS */
+#define ARIZONA_SLIMTX7_PORT_STS_SHIFT                6  /* SLIMTX7_PORT_STS */
+#define ARIZONA_SLIMTX7_PORT_STS_WIDTH                1  /* SLIMTX7_PORT_STS */
+#define ARIZONA_SLIMTX6_PORT_STS                 0x0020  /* SLIMTX6_PORT_STS */
+#define ARIZONA_SLIMTX6_PORT_STS_MASK            0x0020  /* SLIMTX6_PORT_STS */
+#define ARIZONA_SLIMTX6_PORT_STS_SHIFT                5  /* SLIMTX6_PORT_STS */
+#define ARIZONA_SLIMTX6_PORT_STS_WIDTH                1  /* SLIMTX6_PORT_STS */
+#define ARIZONA_SLIMTX5_PORT_STS                 0x0010  /* SLIMTX5_PORT_STS */
+#define ARIZONA_SLIMTX5_PORT_STS_MASK            0x0010  /* SLIMTX5_PORT_STS */
+#define ARIZONA_SLIMTX5_PORT_STS_SHIFT                4  /* SLIMTX5_PORT_STS */
+#define ARIZONA_SLIMTX5_PORT_STS_WIDTH                1  /* SLIMTX5_PORT_STS */
+#define ARIZONA_SLIMTX4_PORT_STS                 0x0008  /* SLIMTX4_PORT_STS */
+#define ARIZONA_SLIMTX4_PORT_STS_MASK            0x0008  /* SLIMTX4_PORT_STS */
+#define ARIZONA_SLIMTX4_PORT_STS_SHIFT                3  /* SLIMTX4_PORT_STS */
+#define ARIZONA_SLIMTX4_PORT_STS_WIDTH                1  /* SLIMTX4_PORT_STS */
+#define ARIZONA_SLIMTX3_PORT_STS                 0x0004  /* SLIMTX3_PORT_STS */
+#define ARIZONA_SLIMTX3_PORT_STS_MASK            0x0004  /* SLIMTX3_PORT_STS */
+#define ARIZONA_SLIMTX3_PORT_STS_SHIFT                2  /* SLIMTX3_PORT_STS */
+#define ARIZONA_SLIMTX3_PORT_STS_WIDTH                1  /* SLIMTX3_PORT_STS */
+#define ARIZONA_SLIMTX2_PORT_STS                 0x0002  /* SLIMTX2_PORT_STS */
+#define ARIZONA_SLIMTX2_PORT_STS_MASK            0x0002  /* SLIMTX2_PORT_STS */
+#define ARIZONA_SLIMTX2_PORT_STS_SHIFT                1  /* SLIMTX2_PORT_STS */
+#define ARIZONA_SLIMTX2_PORT_STS_WIDTH                1  /* SLIMTX2_PORT_STS */
+#define ARIZONA_SLIMTX1_PORT_STS                 0x0001  /* SLIMTX1_PORT_STS */
+#define ARIZONA_SLIMTX1_PORT_STS_MASK            0x0001  /* SLIMTX1_PORT_STS */
+#define ARIZONA_SLIMTX1_PORT_STS_SHIFT                0  /* SLIMTX1_PORT_STS */
+#define ARIZONA_SLIMTX1_PORT_STS_WIDTH                1  /* SLIMTX1_PORT_STS */
+
+/*
+ * R3087 (0xC0F) - IRQ CTRL 1
+ */
+#define ARIZONA_IRQ_POL                          0x0400  /* IRQ_POL */
+#define ARIZONA_IRQ_POL_MASK                     0x0400  /* IRQ_POL */
+#define ARIZONA_IRQ_POL_SHIFT                        10  /* IRQ_POL */
+#define ARIZONA_IRQ_POL_WIDTH                         1  /* IRQ_POL */
+#define ARIZONA_IRQ_OP_CFG                       0x0200  /* IRQ_OP_CFG */
+#define ARIZONA_IRQ_OP_CFG_MASK                  0x0200  /* IRQ_OP_CFG */
+#define ARIZONA_IRQ_OP_CFG_SHIFT                      9  /* IRQ_OP_CFG */
+#define ARIZONA_IRQ_OP_CFG_WIDTH                      1  /* IRQ_OP_CFG */
+
+/*
+ * R3088 (0xC10) - GPIO Debounce Config
+ */
+#define ARIZONA_GP_DBTIME_MASK                   0xF000  /* GP_DBTIME - [15:12] */
+#define ARIZONA_GP_DBTIME_SHIFT                      12  /* GP_DBTIME - [15:12] */
+#define ARIZONA_GP_DBTIME_WIDTH                       4  /* GP_DBTIME - [15:12] */
+
+/*
+ * R3104 (0xC20) - Misc Pad Ctrl 1
+ */
+#define ARIZONA_LDO1ENA_PD                       0x8000  /* LDO1ENA_PD */
+#define ARIZONA_LDO1ENA_PD_MASK                  0x8000  /* LDO1ENA_PD */
+#define ARIZONA_LDO1ENA_PD_SHIFT                     15  /* LDO1ENA_PD */
+#define ARIZONA_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
+#define ARIZONA_MCLK2_PD                         0x2000  /* MCLK2_PD */
+#define ARIZONA_MCLK2_PD_MASK                    0x2000  /* MCLK2_PD */
+#define ARIZONA_MCLK2_PD_SHIFT                       13  /* MCLK2_PD */
+#define ARIZONA_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
+#define ARIZONA_RSTB_PU                          0x0002  /* RSTB_PU */
+#define ARIZONA_RSTB_PU_MASK                     0x0002  /* RSTB_PU */
+#define ARIZONA_RSTB_PU_SHIFT                         1  /* RSTB_PU */
+#define ARIZONA_RSTB_PU_WIDTH                         1  /* RSTB_PU */
+
+/*
+ * R3105 (0xC21) - Misc Pad Ctrl 2
+ */
+#define ARIZONA_MCLK1_PD                         0x1000  /* MCLK1_PD */
+#define ARIZONA_MCLK1_PD_MASK                    0x1000  /* MCLK1_PD */
+#define ARIZONA_MCLK1_PD_SHIFT                       12  /* MCLK1_PD */
+#define ARIZONA_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
+#define ARIZONA_MICD_PD                          0x0100  /* MICD_PD */
+#define ARIZONA_MICD_PD_MASK                     0x0100  /* MICD_PD */
+#define ARIZONA_MICD_PD_SHIFT                         8  /* MICD_PD */
+#define ARIZONA_MICD_PD_WIDTH                         1  /* MICD_PD */
+#define ARIZONA_ADDR_PD                          0x0001  /* ADDR_PD */
+#define ARIZONA_ADDR_PD_MASK                     0x0001  /* ADDR_PD */
+#define ARIZONA_ADDR_PD_SHIFT                         0  /* ADDR_PD */
+#define ARIZONA_ADDR_PD_WIDTH                         1  /* ADDR_PD */
+
+/*
+ * R3106 (0xC22) - Misc Pad Ctrl 3
+ */
+#define ARIZONA_DMICDAT4_PD                      0x0008  /* DMICDAT4_PD */
+#define ARIZONA_DMICDAT4_PD_MASK                 0x0008  /* DMICDAT4_PD */
+#define ARIZONA_DMICDAT4_PD_SHIFT                     3  /* DMICDAT4_PD */
+#define ARIZONA_DMICDAT4_PD_WIDTH                     1  /* DMICDAT4_PD */
+#define ARIZONA_DMICDAT3_PD                      0x0004  /* DMICDAT3_PD */
+#define ARIZONA_DMICDAT3_PD_MASK                 0x0004  /* DMICDAT3_PD */
+#define ARIZONA_DMICDAT3_PD_SHIFT                     2  /* DMICDAT3_PD */
+#define ARIZONA_DMICDAT3_PD_WIDTH                     1  /* DMICDAT3_PD */
+#define ARIZONA_DMICDAT2_PD                      0x0002  /* DMICDAT2_PD */
+#define ARIZONA_DMICDAT2_PD_MASK                 0x0002  /* DMICDAT2_PD */
+#define ARIZONA_DMICDAT2_PD_SHIFT                     1  /* DMICDAT2_PD */
+#define ARIZONA_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
+#define ARIZONA_DMICDAT1_PD                      0x0001  /* DMICDAT1_PD */
+#define ARIZONA_DMICDAT1_PD_MASK                 0x0001  /* DMICDAT1_PD */
+#define ARIZONA_DMICDAT1_PD_SHIFT                     0  /* DMICDAT1_PD */
+#define ARIZONA_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
+
+/*
+ * R3107 (0xC23) - Misc Pad Ctrl 4
+ */
+#define ARIZONA_AIF1RXLRCLK_PU                   0x0020  /* AIF1RXLRCLK_PU */
+#define ARIZONA_AIF1RXLRCLK_PU_MASK              0x0020  /* AIF1RXLRCLK_PU */
+#define ARIZONA_AIF1RXLRCLK_PU_SHIFT                  5  /* AIF1RXLRCLK_PU */
+#define ARIZONA_AIF1RXLRCLK_PU_WIDTH                  1  /* AIF1RXLRCLK_PU */
+#define ARIZONA_AIF1RXLRCLK_PD                   0x0010  /* AIF1RXLRCLK_PD */
+#define ARIZONA_AIF1RXLRCLK_PD_MASK              0x0010  /* AIF1RXLRCLK_PD */
+#define ARIZONA_AIF1RXLRCLK_PD_SHIFT                  4  /* AIF1RXLRCLK_PD */
+#define ARIZONA_AIF1RXLRCLK_PD_WIDTH                  1  /* AIF1RXLRCLK_PD */
+#define ARIZONA_AIF1BCLK_PU                      0x0008  /* AIF1BCLK_PU */
+#define ARIZONA_AIF1BCLK_PU_MASK                 0x0008  /* AIF1BCLK_PU */
+#define ARIZONA_AIF1BCLK_PU_SHIFT                     3  /* AIF1BCLK_PU */
+#define ARIZONA_AIF1BCLK_PU_WIDTH                     1  /* AIF1BCLK_PU */
+#define ARIZONA_AIF1BCLK_PD                      0x0004  /* AIF1BCLK_PD */
+#define ARIZONA_AIF1BCLK_PD_MASK                 0x0004  /* AIF1BCLK_PD */
+#define ARIZONA_AIF1BCLK_PD_SHIFT                     2  /* AIF1BCLK_PD */
+#define ARIZONA_AIF1BCLK_PD_WIDTH                     1  /* AIF1BCLK_PD */
+#define ARIZONA_AIF1RXDAT_PU                     0x0002  /* AIF1RXDAT_PU */
+#define ARIZONA_AIF1RXDAT_PU_MASK                0x0002  /* AIF1RXDAT_PU */
+#define ARIZONA_AIF1RXDAT_PU_SHIFT                    1  /* AIF1RXDAT_PU */
+#define ARIZONA_AIF1RXDAT_PU_WIDTH                    1  /* AIF1RXDAT_PU */
+#define ARIZONA_AIF1RXDAT_PD                     0x0001  /* AIF1RXDAT_PD */
+#define ARIZONA_AIF1RXDAT_PD_MASK                0x0001  /* AIF1RXDAT_PD */
+#define ARIZONA_AIF1RXDAT_PD_SHIFT                    0  /* AIF1RXDAT_PD */
+#define ARIZONA_AIF1RXDAT_PD_WIDTH                    1  /* AIF1RXDAT_PD */
+
+/*
+ * R3108 (0xC24) - Misc Pad Ctrl 5
+ */
+#define ARIZONA_AIF2RXLRCLK_PU                   0x0020  /* AIF2RXLRCLK_PU */
+#define ARIZONA_AIF2RXLRCLK_PU_MASK              0x0020  /* AIF2RXLRCLK_PU */
+#define ARIZONA_AIF2RXLRCLK_PU_SHIFT                  5  /* AIF2RXLRCLK_PU */
+#define ARIZONA_AIF2RXLRCLK_PU_WIDTH                  1  /* AIF2RXLRCLK_PU */
+#define ARIZONA_AIF2RXLRCLK_PD                   0x0010  /* AIF2RXLRCLK_PD */
+#define ARIZONA_AIF2RXLRCLK_PD_MASK              0x0010  /* AIF2RXLRCLK_PD */
+#define ARIZONA_AIF2RXLRCLK_PD_SHIFT                  4  /* AIF2RXLRCLK_PD */
+#define ARIZONA_AIF2RXLRCLK_PD_WIDTH                  1  /* AIF2RXLRCLK_PD */
+#define ARIZONA_AIF2BCLK_PU                      0x0008  /* AIF2BCLK_PU */
+#define ARIZONA_AIF2BCLK_PU_MASK                 0x0008  /* AIF2BCLK_PU */
+#define ARIZONA_AIF2BCLK_PU_SHIFT                     3  /* AIF2BCLK_PU */
+#define ARIZONA_AIF2BCLK_PU_WIDTH                     1  /* AIF2BCLK_PU */
+#define ARIZONA_AIF2BCLK_PD                      0x0004  /* AIF2BCLK_PD */
+#define ARIZONA_AIF2BCLK_PD_MASK                 0x0004  /* AIF2BCLK_PD */
+#define ARIZONA_AIF2BCLK_PD_SHIFT                     2  /* AIF2BCLK_PD */
+#define ARIZONA_AIF2BCLK_PD_WIDTH                     1  /* AIF2BCLK_PD */
+#define ARIZONA_AIF2RXDAT_PU                     0x0002  /* AIF2RXDAT_PU */
+#define ARIZONA_AIF2RXDAT_PU_MASK                0x0002  /* AIF2RXDAT_PU */
+#define ARIZONA_AIF2RXDAT_PU_SHIFT                    1  /* AIF2RXDAT_PU */
+#define ARIZONA_AIF2RXDAT_PU_WIDTH                    1  /* AIF2RXDAT_PU */
+#define ARIZONA_AIF2RXDAT_PD                     0x0001  /* AIF2RXDAT_PD */
+#define ARIZONA_AIF2RXDAT_PD_MASK                0x0001  /* AIF2RXDAT_PD */
+#define ARIZONA_AIF2RXDAT_PD_SHIFT                    0  /* AIF2RXDAT_PD */
+#define ARIZONA_AIF2RXDAT_PD_WIDTH                    1  /* AIF2RXDAT_PD */
+
+/*
+ * R3109 (0xC25) - Misc Pad Ctrl 6
+ */
+#define ARIZONA_AIF3RXLRCLK_PU                   0x0020  /* AIF3RXLRCLK_PU */
+#define ARIZONA_AIF3RXLRCLK_PU_MASK              0x0020  /* AIF3RXLRCLK_PU */
+#define ARIZONA_AIF3RXLRCLK_PU_SHIFT                  5  /* AIF3RXLRCLK_PU */
+#define ARIZONA_AIF3RXLRCLK_PU_WIDTH                  1  /* AIF3RXLRCLK_PU */
+#define ARIZONA_AIF3RXLRCLK_PD                   0x0010  /* AIF3RXLRCLK_PD */
+#define ARIZONA_AIF3RXLRCLK_PD_MASK              0x0010  /* AIF3RXLRCLK_PD */
+#define ARIZONA_AIF3RXLRCLK_PD_SHIFT                  4  /* AIF3RXLRCLK_PD */
+#define ARIZONA_AIF3RXLRCLK_PD_WIDTH                  1  /* AIF3RXLRCLK_PD */
+#define ARIZONA_AIF3BCLK_PU                      0x0008  /* AIF3BCLK_PU */
+#define ARIZONA_AIF3BCLK_PU_MASK                 0x0008  /* AIF3BCLK_PU */
+#define ARIZONA_AIF3BCLK_PU_SHIFT                     3  /* AIF3BCLK_PU */
+#define ARIZONA_AIF3BCLK_PU_WIDTH                     1  /* AIF3BCLK_PU */
+#define ARIZONA_AIF3BCLK_PD                      0x0004  /* AIF3BCLK_PD */
+#define ARIZONA_AIF3BCLK_PD_MASK                 0x0004  /* AIF3BCLK_PD */
+#define ARIZONA_AIF3BCLK_PD_SHIFT                     2  /* AIF3BCLK_PD */
+#define ARIZONA_AIF3BCLK_PD_WIDTH                     1  /* AIF3BCLK_PD */
+#define ARIZONA_AIF3RXDAT_PU                     0x0002  /* AIF3RXDAT_PU */
+#define ARIZONA_AIF3RXDAT_PU_MASK                0x0002  /* AIF3RXDAT_PU */
+#define ARIZONA_AIF3RXDAT_PU_SHIFT                    1  /* AIF3RXDAT_PU */
+#define ARIZONA_AIF3RXDAT_PU_WIDTH                    1  /* AIF3RXDAT_PU */
+#define ARIZONA_AIF3RXDAT_PD                     0x0001  /* AIF3RXDAT_PD */
+#define ARIZONA_AIF3RXDAT_PD_MASK                0x0001  /* AIF3RXDAT_PD */
+#define ARIZONA_AIF3RXDAT_PD_SHIFT                    0  /* AIF3RXDAT_PD */
+#define ARIZONA_AIF3RXDAT_PD_WIDTH                    1  /* AIF3RXDAT_PD */
+
+/*
+ * R3328 (0xD00) - Interrupt Status 1
+ */
+#define ARIZONA_GP4_EINT1                        0x0008  /* GP4_EINT1 */
+#define ARIZONA_GP4_EINT1_MASK                   0x0008  /* GP4_EINT1 */
+#define ARIZONA_GP4_EINT1_SHIFT                       3  /* GP4_EINT1 */
+#define ARIZONA_GP4_EINT1_WIDTH                       1  /* GP4_EINT1 */
+#define ARIZONA_GP3_EINT1                        0x0004  /* GP3_EINT1 */
+#define ARIZONA_GP3_EINT1_MASK                   0x0004  /* GP3_EINT1 */
+#define ARIZONA_GP3_EINT1_SHIFT                       2  /* GP3_EINT1 */
+#define ARIZONA_GP3_EINT1_WIDTH                       1  /* GP3_EINT1 */
+#define ARIZONA_GP2_EINT1                        0x0002  /* GP2_EINT1 */
+#define ARIZONA_GP2_EINT1_MASK                   0x0002  /* GP2_EINT1 */
+#define ARIZONA_GP2_EINT1_SHIFT                       1  /* GP2_EINT1 */
+#define ARIZONA_GP2_EINT1_WIDTH                       1  /* GP2_EINT1 */
+#define ARIZONA_GP1_EINT1                        0x0001  /* GP1_EINT1 */
+#define ARIZONA_GP1_EINT1_MASK                   0x0001  /* GP1_EINT1 */
+#define ARIZONA_GP1_EINT1_SHIFT                       0  /* GP1_EINT1 */
+#define ARIZONA_GP1_EINT1_WIDTH                       1  /* GP1_EINT1 */
+
+/*
+ * R3329 (0xD01) - Interrupt Status 2
+ */
+#define ARIZONA_DSP4_RAM_RDY_EINT1               0x0800  /* DSP4_RAM_RDY_EINT1 */
+#define ARIZONA_DSP4_RAM_RDY_EINT1_MASK          0x0800  /* DSP4_RAM_RDY_EINT1 */
+#define ARIZONA_DSP4_RAM_RDY_EINT1_SHIFT             11  /* DSP4_RAM_RDY_EINT1 */
+#define ARIZONA_DSP4_RAM_RDY_EINT1_WIDTH              1  /* DSP4_RAM_RDY_EINT1 */
+#define ARIZONA_DSP3_RAM_RDY_EINT1               0x0400  /* DSP3_RAM_RDY_EINT1 */
+#define ARIZONA_DSP3_RAM_RDY_EINT1_MASK          0x0400  /* DSP3_RAM_RDY_EINT1 */
+#define ARIZONA_DSP3_RAM_RDY_EINT1_SHIFT             10  /* DSP3_RAM_RDY_EINT1 */
+#define ARIZONA_DSP3_RAM_RDY_EINT1_WIDTH              1  /* DSP3_RAM_RDY_EINT1 */
+#define ARIZONA_DSP2_RAM_RDY_EINT1               0x0200  /* DSP2_RAM_RDY_EINT1 */
+#define ARIZONA_DSP2_RAM_RDY_EINT1_MASK          0x0200  /* DSP2_RAM_RDY_EINT1 */
+#define ARIZONA_DSP2_RAM_RDY_EINT1_SHIFT              9  /* DSP2_RAM_RDY_EINT1 */
+#define ARIZONA_DSP2_RAM_RDY_EINT1_WIDTH              1  /* DSP2_RAM_RDY_EINT1 */
+#define ARIZONA_DSP1_RAM_RDY_EINT1               0x0100  /* DSP1_RAM_RDY_EINT1 */
+#define ARIZONA_DSP1_RAM_RDY_EINT1_MASK          0x0100  /* DSP1_RAM_RDY_EINT1 */
+#define ARIZONA_DSP1_RAM_RDY_EINT1_SHIFT              8  /* DSP1_RAM_RDY_EINT1 */
+#define ARIZONA_DSP1_RAM_RDY_EINT1_WIDTH              1  /* DSP1_RAM_RDY_EINT1 */
+#define ARIZONA_DSP_IRQ8_EINT1                   0x0080  /* DSP_IRQ8_EINT1 */
+#define ARIZONA_DSP_IRQ8_EINT1_MASK              0x0080  /* DSP_IRQ8_EINT1 */
+#define ARIZONA_DSP_IRQ8_EINT1_SHIFT                  7  /* DSP_IRQ8_EINT1 */
+#define ARIZONA_DSP_IRQ8_EINT1_WIDTH                  1  /* DSP_IRQ8_EINT1 */
+#define ARIZONA_DSP_IRQ7_EINT1                   0x0040  /* DSP_IRQ7_EINT1 */
+#define ARIZONA_DSP_IRQ7_EINT1_MASK              0x0040  /* DSP_IRQ7_EINT1 */
+#define ARIZONA_DSP_IRQ7_EINT1_SHIFT                  6  /* DSP_IRQ7_EINT1 */
+#define ARIZONA_DSP_IRQ7_EINT1_WIDTH                  1  /* DSP_IRQ7_EINT1 */
+#define ARIZONA_DSP_IRQ6_EINT1                   0x0020  /* DSP_IRQ6_EINT1 */
+#define ARIZONA_DSP_IRQ6_EINT1_MASK              0x0020  /* DSP_IRQ6_EINT1 */
+#define ARIZONA_DSP_IRQ6_EINT1_SHIFT                  5  /* DSP_IRQ6_EINT1 */
+#define ARIZONA_DSP_IRQ6_EINT1_WIDTH                  1  /* DSP_IRQ6_EINT1 */
+#define ARIZONA_DSP_IRQ5_EINT1                   0x0010  /* DSP_IRQ5_EINT1 */
+#define ARIZONA_DSP_IRQ5_EINT1_MASK              0x0010  /* DSP_IRQ5_EINT1 */
+#define ARIZONA_DSP_IRQ5_EINT1_SHIFT                  4  /* DSP_IRQ5_EINT1 */
+#define ARIZONA_DSP_IRQ5_EINT1_WIDTH                  1  /* DSP_IRQ5_EINT1 */
+#define ARIZONA_DSP_IRQ4_EINT1                   0x0008  /* DSP_IRQ4_EINT1 */
+#define ARIZONA_DSP_IRQ4_EINT1_MASK              0x0008  /* DSP_IRQ4_EINT1 */
+#define ARIZONA_DSP_IRQ4_EINT1_SHIFT                  3  /* DSP_IRQ4_EINT1 */
+#define ARIZONA_DSP_IRQ4_EINT1_WIDTH                  1  /* DSP_IRQ4_EINT1 */
+#define ARIZONA_DSP_IRQ3_EINT1                   0x0004  /* DSP_IRQ3_EINT1 */
+#define ARIZONA_DSP_IRQ3_EINT1_MASK              0x0004  /* DSP_IRQ3_EINT1 */
+#define ARIZONA_DSP_IRQ3_EINT1_SHIFT                  2  /* DSP_IRQ3_EINT1 */
+#define ARIZONA_DSP_IRQ3_EINT1_WIDTH                  1  /* DSP_IRQ3_EINT1 */
+#define ARIZONA_DSP_IRQ2_EINT1                   0x0002  /* DSP_IRQ2_EINT1 */
+#define ARIZONA_DSP_IRQ2_EINT1_MASK              0x0002  /* DSP_IRQ2_EINT1 */
+#define ARIZONA_DSP_IRQ2_EINT1_SHIFT                  1  /* DSP_IRQ2_EINT1 */
+#define ARIZONA_DSP_IRQ2_EINT1_WIDTH                  1  /* DSP_IRQ2_EINT1 */
+#define ARIZONA_DSP_IRQ1_EINT1                   0x0001  /* DSP_IRQ1_EINT1 */
+#define ARIZONA_DSP_IRQ1_EINT1_MASK              0x0001  /* DSP_IRQ1_EINT1 */
+#define ARIZONA_DSP_IRQ1_EINT1_SHIFT                  0  /* DSP_IRQ1_EINT1 */
+#define ARIZONA_DSP_IRQ1_EINT1_WIDTH                  1  /* DSP_IRQ1_EINT1 */
+
+/*
+ * R3330 (0xD02) - Interrupt Status 3
+ */
+#define ARIZONA_SPK_SHUTDOWN_WARN_EINT1          0x8000  /* SPK_SHUTDOWN_WARN_EINT1 */
+#define ARIZONA_SPK_SHUTDOWN_WARN_EINT1_MASK     0x8000  /* SPK_SHUTDOWN_WARN_EINT1 */
+#define ARIZONA_SPK_SHUTDOWN_WARN_EINT1_SHIFT        15  /* SPK_SHUTDOWN_WARN_EINT1 */
+#define ARIZONA_SPK_SHUTDOWN_WARN_EINT1_WIDTH         1  /* SPK_SHUTDOWN_WARN_EINT1 */
+#define ARIZONA_SPK_SHUTDOWN_EINT1               0x4000  /* SPK_SHUTDOWN_EINT1 */
+#define ARIZONA_SPK_SHUTDOWN_EINT1_MASK          0x4000  /* SPK_SHUTDOWN_EINT1 */
+#define ARIZONA_SPK_SHUTDOWN_EINT1_SHIFT             14  /* SPK_SHUTDOWN_EINT1 */
+#define ARIZONA_SPK_SHUTDOWN_EINT1_WIDTH              1  /* SPK_SHUTDOWN_EINT1 */
+#define ARIZONA_HPDET_EINT1                      0x2000  /* HPDET_EINT1 */
+#define ARIZONA_HPDET_EINT1_MASK                 0x2000  /* HPDET_EINT1 */
+#define ARIZONA_HPDET_EINT1_SHIFT                    13  /* HPDET_EINT1 */
+#define ARIZONA_HPDET_EINT1_WIDTH                     1  /* HPDET_EINT1 */
+#define ARIZONA_MICDET_EINT1                     0x1000  /* MICDET_EINT1 */
+#define ARIZONA_MICDET_EINT1_MASK                0x1000  /* MICDET_EINT1 */
+#define ARIZONA_MICDET_EINT1_SHIFT                   12  /* MICDET_EINT1 */
+#define ARIZONA_MICDET_EINT1_WIDTH                    1  /* MICDET_EINT1 */
+#define ARIZONA_WSEQ_DONE_EINT1                  0x0800  /* WSEQ_DONE_EINT1 */
+#define ARIZONA_WSEQ_DONE_EINT1_MASK             0x0800  /* WSEQ_DONE_EINT1 */
+#define ARIZONA_WSEQ_DONE_EINT1_SHIFT                11  /* WSEQ_DONE_EINT1 */
+#define ARIZONA_WSEQ_DONE_EINT1_WIDTH                 1  /* WSEQ_DONE_EINT1 */
+#define ARIZONA_DRC2_SIG_DET_EINT1               0x0400  /* DRC2_SIG_DET_EINT1 */
+#define ARIZONA_DRC2_SIG_DET_EINT1_MASK          0x0400  /* DRC2_SIG_DET_EINT1 */
+#define ARIZONA_DRC2_SIG_DET_EINT1_SHIFT             10  /* DRC2_SIG_DET_EINT1 */
+#define ARIZONA_DRC2_SIG_DET_EINT1_WIDTH              1  /* DRC2_SIG_DET_EINT1 */
+#define ARIZONA_DRC1_SIG_DET_EINT1               0x0200  /* DRC1_SIG_DET_EINT1 */
+#define ARIZONA_DRC1_SIG_DET_EINT1_MASK          0x0200  /* DRC1_SIG_DET_EINT1 */
+#define ARIZONA_DRC1_SIG_DET_EINT1_SHIFT              9  /* DRC1_SIG_DET_EINT1 */
+#define ARIZONA_DRC1_SIG_DET_EINT1_WIDTH              1  /* DRC1_SIG_DET_EINT1 */
+#define ARIZONA_ASRC2_LOCK_EINT1                 0x0100  /* ASRC2_LOCK_EINT1 */
+#define ARIZONA_ASRC2_LOCK_EINT1_MASK            0x0100  /* ASRC2_LOCK_EINT1 */
+#define ARIZONA_ASRC2_LOCK_EINT1_SHIFT                8  /* ASRC2_LOCK_EINT1 */
+#define ARIZONA_ASRC2_LOCK_EINT1_WIDTH                1  /* ASRC2_LOCK_EINT1 */
+#define ARIZONA_ASRC1_LOCK_EINT1                 0x0080  /* ASRC1_LOCK_EINT1 */
+#define ARIZONA_ASRC1_LOCK_EINT1_MASK            0x0080  /* ASRC1_LOCK_EINT1 */
+#define ARIZONA_ASRC1_LOCK_EINT1_SHIFT                7  /* ASRC1_LOCK_EINT1 */
+#define ARIZONA_ASRC1_LOCK_EINT1_WIDTH                1  /* ASRC1_LOCK_EINT1 */
+#define ARIZONA_UNDERCLOCKED_EINT1               0x0040  /* UNDERCLOCKED_EINT1 */
+#define ARIZONA_UNDERCLOCKED_EINT1_MASK          0x0040  /* UNDERCLOCKED_EINT1 */
+#define ARIZONA_UNDERCLOCKED_EINT1_SHIFT              6  /* UNDERCLOCKED_EINT1 */
+#define ARIZONA_UNDERCLOCKED_EINT1_WIDTH              1  /* UNDERCLOCKED_EINT1 */
+#define ARIZONA_OVERCLOCKED_EINT1                0x0020  /* OVERCLOCKED_EINT1 */
+#define ARIZONA_OVERCLOCKED_EINT1_MASK           0x0020  /* OVERCLOCKED_EINT1 */
+#define ARIZONA_OVERCLOCKED_EINT1_SHIFT               5  /* OVERCLOCKED_EINT1 */
+#define ARIZONA_OVERCLOCKED_EINT1_WIDTH               1  /* OVERCLOCKED_EINT1 */
+#define ARIZONA_FLL2_LOCK_EINT1                  0x0008  /* FLL2_LOCK_EINT1 */
+#define ARIZONA_FLL2_LOCK_EINT1_MASK             0x0008  /* FLL2_LOCK_EINT1 */
+#define ARIZONA_FLL2_LOCK_EINT1_SHIFT                 3  /* FLL2_LOCK_EINT1 */
+#define ARIZONA_FLL2_LOCK_EINT1_WIDTH                 1  /* FLL2_LOCK_EINT1 */
+#define ARIZONA_FLL1_LOCK_EINT1                  0x0004  /* FLL1_LOCK_EINT1 */
+#define ARIZONA_FLL1_LOCK_EINT1_MASK             0x0004  /* FLL1_LOCK_EINT1 */
+#define ARIZONA_FLL1_LOCK_EINT1_SHIFT                 2  /* FLL1_LOCK_EINT1 */
+#define ARIZONA_FLL1_LOCK_EINT1_WIDTH                 1  /* FLL1_LOCK_EINT1 */
+#define ARIZONA_CLKGEN_ERR_EINT1                 0x0002  /* CLKGEN_ERR_EINT1 */
+#define ARIZONA_CLKGEN_ERR_EINT1_MASK            0x0002  /* CLKGEN_ERR_EINT1 */
+#define ARIZONA_CLKGEN_ERR_EINT1_SHIFT                1  /* CLKGEN_ERR_EINT1 */
+#define ARIZONA_CLKGEN_ERR_EINT1_WIDTH                1  /* CLKGEN_ERR_EINT1 */
+#define ARIZONA_CLKGEN_ERR_ASYNC_EINT1           0x0001  /* CLKGEN_ERR_ASYNC_EINT1 */
+#define ARIZONA_CLKGEN_ERR_ASYNC_EINT1_MASK      0x0001  /* CLKGEN_ERR_ASYNC_EINT1 */
+#define ARIZONA_CLKGEN_ERR_ASYNC_EINT1_SHIFT          0  /* CLKGEN_ERR_ASYNC_EINT1 */
+#define ARIZONA_CLKGEN_ERR_ASYNC_EINT1_WIDTH          1  /* CLKGEN_ERR_ASYNC_EINT1 */
+
+/*
+ * R3331 (0xD03) - Interrupt Status 4
+ */
+#define ARIZONA_ASRC_CFG_ERR_EINT1               0x8000  /* ASRC_CFG_ERR_EINT1 */
+#define ARIZONA_ASRC_CFG_ERR_EINT1_MASK          0x8000  /* ASRC_CFG_ERR_EINT1 */
+#define ARIZONA_ASRC_CFG_ERR_EINT1_SHIFT             15  /* ASRC_CFG_ERR_EINT1 */
+#define ARIZONA_ASRC_CFG_ERR_EINT1_WIDTH              1  /* ASRC_CFG_ERR_EINT1 */
+#define ARIZONA_AIF3_ERR_EINT1                   0x4000  /* AIF3_ERR_EINT1 */
+#define ARIZONA_AIF3_ERR_EINT1_MASK              0x4000  /* AIF3_ERR_EINT1 */
+#define ARIZONA_AIF3_ERR_EINT1_SHIFT                 14  /* AIF3_ERR_EINT1 */
+#define ARIZONA_AIF3_ERR_EINT1_WIDTH                  1  /* AIF3_ERR_EINT1 */
+#define ARIZONA_AIF2_ERR_EINT1                   0x2000  /* AIF2_ERR_EINT1 */
+#define ARIZONA_AIF2_ERR_EINT1_MASK              0x2000  /* AIF2_ERR_EINT1 */
+#define ARIZONA_AIF2_ERR_EINT1_SHIFT                 13  /* AIF2_ERR_EINT1 */
+#define ARIZONA_AIF2_ERR_EINT1_WIDTH                  1  /* AIF2_ERR_EINT1 */
+#define ARIZONA_AIF1_ERR_EINT1                   0x1000  /* AIF1_ERR_EINT1 */
+#define ARIZONA_AIF1_ERR_EINT1_MASK              0x1000  /* AIF1_ERR_EINT1 */
+#define ARIZONA_AIF1_ERR_EINT1_SHIFT                 12  /* AIF1_ERR_EINT1 */
+#define ARIZONA_AIF1_ERR_EINT1_WIDTH                  1  /* AIF1_ERR_EINT1 */
+#define ARIZONA_CTRLIF_ERR_EINT1                 0x0800  /* CTRLIF_ERR_EINT1 */
+#define ARIZONA_CTRLIF_ERR_EINT1_MASK            0x0800  /* CTRLIF_ERR_EINT1 */
+#define ARIZONA_CTRLIF_ERR_EINT1_SHIFT               11  /* CTRLIF_ERR_EINT1 */
+#define ARIZONA_CTRLIF_ERR_EINT1_WIDTH                1  /* CTRLIF_ERR_EINT1 */
+#define ARIZONA_MIXER_DROPPED_SAMPLE_EINT1       0x0400  /* MIXER_DROPPED_SAMPLE_EINT1 */
+#define ARIZONA_MIXER_DROPPED_SAMPLE_EINT1_MASK  0x0400  /* MIXER_DROPPED_SAMPLE_EINT1 */
+#define ARIZONA_MIXER_DROPPED_SAMPLE_EINT1_SHIFT     10  /* MIXER_DROPPED_SAMPLE_EINT1 */
+#define ARIZONA_MIXER_DROPPED_SAMPLE_EINT1_WIDTH      1  /* MIXER_DROPPED_SAMPLE_EINT1 */
+#define ARIZONA_ASYNC_CLK_ENA_LOW_EINT1          0x0200  /* ASYNC_CLK_ENA_LOW_EINT1 */
+#define ARIZONA_ASYNC_CLK_ENA_LOW_EINT1_MASK     0x0200  /* ASYNC_CLK_ENA_LOW_EINT1 */
+#define ARIZONA_ASYNC_CLK_ENA_LOW_EINT1_SHIFT         9  /* ASYNC_CLK_ENA_LOW_EINT1 */
+#define ARIZONA_ASYNC_CLK_ENA_LOW_EINT1_WIDTH         1  /* ASYNC_CLK_ENA_LOW_EINT1 */
+#define ARIZONA_SYSCLK_ENA_LOW_EINT1             0x0100  /* SYSCLK_ENA_LOW_EINT1 */
+#define ARIZONA_SYSCLK_ENA_LOW_EINT1_MASK        0x0100  /* SYSCLK_ENA_LOW_EINT1 */
+#define ARIZONA_SYSCLK_ENA_LOW_EINT1_SHIFT            8  /* SYSCLK_ENA_LOW_EINT1 */
+#define ARIZONA_SYSCLK_ENA_LOW_EINT1_WIDTH            1  /* SYSCLK_ENA_LOW_EINT1 */
+#define ARIZONA_ISRC1_CFG_ERR_EINT1              0x0080  /* ISRC1_CFG_ERR_EINT1 */
+#define ARIZONA_ISRC1_CFG_ERR_EINT1_MASK         0x0080  /* ISRC1_CFG_ERR_EINT1 */
+#define ARIZONA_ISRC1_CFG_ERR_EINT1_SHIFT             7  /* ISRC1_CFG_ERR_EINT1 */
+#define ARIZONA_ISRC1_CFG_ERR_EINT1_WIDTH             1  /* ISRC1_CFG_ERR_EINT1 */
+#define ARIZONA_ISRC2_CFG_ERR_EINT1              0x0040  /* ISRC2_CFG_ERR_EINT1 */
+#define ARIZONA_ISRC2_CFG_ERR_EINT1_MASK         0x0040  /* ISRC2_CFG_ERR_EINT1 */
+#define ARIZONA_ISRC2_CFG_ERR_EINT1_SHIFT             6  /* ISRC2_CFG_ERR_EINT1 */
+#define ARIZONA_ISRC2_CFG_ERR_EINT1_WIDTH             1  /* ISRC2_CFG_ERR_EINT1 */
+
+/*
+ * R3332 (0xD04) - Interrupt Status 5
+ */
+#define ARIZONA_BOOT_DONE_EINT1                  0x0100  /* BOOT_DONE_EINT1 */
+#define ARIZONA_BOOT_DONE_EINT1_MASK             0x0100  /* BOOT_DONE_EINT1 */
+#define ARIZONA_BOOT_DONE_EINT1_SHIFT                 8  /* BOOT_DONE_EINT1 */
+#define ARIZONA_BOOT_DONE_EINT1_WIDTH                 1  /* BOOT_DONE_EINT1 */
+#define ARIZONA_DCS_DAC_DONE_EINT1               0x0080  /* DCS_DAC_DONE_EINT1 */
+#define ARIZONA_DCS_DAC_DONE_EINT1_MASK          0x0080  /* DCS_DAC_DONE_EINT1 */
+#define ARIZONA_DCS_DAC_DONE_EINT1_SHIFT              7  /* DCS_DAC_DONE_EINT1 */
+#define ARIZONA_DCS_DAC_DONE_EINT1_WIDTH              1  /* DCS_DAC_DONE_EINT1 */
+#define ARIZONA_DCS_HP_DONE_EINT1                0x0040  /* DCS_HP_DONE_EINT1 */
+#define ARIZONA_DCS_HP_DONE_EINT1_MASK           0x0040  /* DCS_HP_DONE_EINT1 */
+#define ARIZONA_DCS_HP_DONE_EINT1_SHIFT               6  /* DCS_HP_DONE_EINT1 */
+#define ARIZONA_DCS_HP_DONE_EINT1_WIDTH               1  /* DCS_HP_DONE_EINT1 */
+#define ARIZONA_FLL2_CLOCK_OK_EINT1              0x0002  /* FLL2_CLOCK_OK_EINT1 */
+#define ARIZONA_FLL2_CLOCK_OK_EINT1_MASK         0x0002  /* FLL2_CLOCK_OK_EINT1 */
+#define ARIZONA_FLL2_CLOCK_OK_EINT1_SHIFT             1  /* FLL2_CLOCK_OK_EINT1 */
+#define ARIZONA_FLL2_CLOCK_OK_EINT1_WIDTH             1  /* FLL2_CLOCK_OK_EINT1 */
+#define ARIZONA_FLL1_CLOCK_OK_EINT1              0x0001  /* FLL1_CLOCK_OK_EINT1 */
+#define ARIZONA_FLL1_CLOCK_OK_EINT1_MASK         0x0001  /* FLL1_CLOCK_OK_EINT1 */
+#define ARIZONA_FLL1_CLOCK_OK_EINT1_SHIFT             0  /* FLL1_CLOCK_OK_EINT1 */
+#define ARIZONA_FLL1_CLOCK_OK_EINT1_WIDTH             1  /* FLL1_CLOCK_OK_EINT1 */
+
+/*
+ * R3336 (0xD08) - Interrupt Status 1 Mask
+ */
+#define ARIZONA_IM_GP4_EINT1                     0x0008  /* IM_GP4_EINT1 */
+#define ARIZONA_IM_GP4_EINT1_MASK                0x0008  /* IM_GP4_EINT1 */
+#define ARIZONA_IM_GP4_EINT1_SHIFT                    3  /* IM_GP4_EINT1 */
+#define ARIZONA_IM_GP4_EINT1_WIDTH                    1  /* IM_GP4_EINT1 */
+#define ARIZONA_IM_GP3_EINT1                     0x0004  /* IM_GP3_EINT1 */
+#define ARIZONA_IM_GP3_EINT1_MASK                0x0004  /* IM_GP3_EINT1 */
+#define ARIZONA_IM_GP3_EINT1_SHIFT                    2  /* IM_GP3_EINT1 */
+#define ARIZONA_IM_GP3_EINT1_WIDTH                    1  /* IM_GP3_EINT1 */
+#define ARIZONA_IM_GP2_EINT1                     0x0002  /* IM_GP2_EINT1 */
+#define ARIZONA_IM_GP2_EINT1_MASK                0x0002  /* IM_GP2_EINT1 */
+#define ARIZONA_IM_GP2_EINT1_SHIFT                    1  /* IM_GP2_EINT1 */
+#define ARIZONA_IM_GP2_EINT1_WIDTH                    1  /* IM_GP2_EINT1 */
+#define ARIZONA_IM_GP1_EINT1                     0x0001  /* IM_GP1_EINT1 */
+#define ARIZONA_IM_GP1_EINT1_MASK                0x0001  /* IM_GP1_EINT1 */
+#define ARIZONA_IM_GP1_EINT1_SHIFT                    0  /* IM_GP1_EINT1 */
+#define ARIZONA_IM_GP1_EINT1_WIDTH                    1  /* IM_GP1_EINT1 */
+
+/*
+ * R3337 (0xD09) - Interrupt Status 2 Mask
+ */
+#define ARIZONA_IM_DSP1_RAM_RDY_EINT1            0x0100  /* IM_DSP1_RAM_RDY_EINT1 */
+#define ARIZONA_IM_DSP1_RAM_RDY_EINT1_MASK       0x0100  /* IM_DSP1_RAM_RDY_EINT1 */
+#define ARIZONA_IM_DSP1_RAM_RDY_EINT1_SHIFT           8  /* IM_DSP1_RAM_RDY_EINT1 */
+#define ARIZONA_IM_DSP1_RAM_RDY_EINT1_WIDTH           1  /* IM_DSP1_RAM_RDY_EINT1 */
+#define ARIZONA_IM_DSP_IRQ2_EINT1                0x0002  /* IM_DSP_IRQ2_EINT1 */
+#define ARIZONA_IM_DSP_IRQ2_EINT1_MASK           0x0002  /* IM_DSP_IRQ2_EINT1 */
+#define ARIZONA_IM_DSP_IRQ2_EINT1_SHIFT               1  /* IM_DSP_IRQ2_EINT1 */
+#define ARIZONA_IM_DSP_IRQ2_EINT1_WIDTH               1  /* IM_DSP_IRQ2_EINT1 */
+#define ARIZONA_IM_DSP_IRQ1_EINT1                0x0001  /* IM_DSP_IRQ1_EINT1 */
+#define ARIZONA_IM_DSP_IRQ1_EINT1_MASK           0x0001  /* IM_DSP_IRQ1_EINT1 */
+#define ARIZONA_IM_DSP_IRQ1_EINT1_SHIFT               0  /* IM_DSP_IRQ1_EINT1 */
+#define ARIZONA_IM_DSP_IRQ1_EINT1_WIDTH               1  /* IM_DSP_IRQ1_EINT1 */
+
+/*
+ * R3338 (0xD0A) - Interrupt Status 3 Mask
+ */
+#define ARIZONA_IM_SPK_SHUTDOWN_WARN_EINT1       0x8000  /* IM_SPK_SHUTDOWN_WARN_EINT1 */
+#define ARIZONA_IM_SPK_SHUTDOWN_WARN_EINT1_MASK  0x8000  /* IM_SPK_SHUTDOWN_WARN_EINT1 */
+#define ARIZONA_IM_SPK_SHUTDOWN_WARN_EINT1_SHIFT     15  /* IM_SPK_SHUTDOWN_WARN_EINT1 */
+#define ARIZONA_IM_SPK_SHUTDOWN_WARN_EINT1_WIDTH      1  /* IM_SPK_SHUTDOWN_WARN_EINT1 */
+#define ARIZONA_IM_SPK_SHUTDOWN_EINT1            0x4000  /* IM_SPK_SHUTDOWN_EINT1 */
+#define ARIZONA_IM_SPK_SHUTDOWN_EINT1_MASK       0x4000  /* IM_SPK_SHUTDOWN_EINT1 */
+#define ARIZONA_IM_SPK_SHUTDOWN_EINT1_SHIFT          14  /* IM_SPK_SHUTDOWN_EINT1 */
+#define ARIZONA_IM_SPK_SHUTDOWN_EINT1_WIDTH           1  /* IM_SPK_SHUTDOWN_EINT1 */
+#define ARIZONA_IM_HPDET_EINT1                   0x2000  /* IM_HPDET_EINT1 */
+#define ARIZONA_IM_HPDET_EINT1_MASK              0x2000  /* IM_HPDET_EINT1 */
+#define ARIZONA_IM_HPDET_EINT1_SHIFT                 13  /* IM_HPDET_EINT1 */
+#define ARIZONA_IM_HPDET_EINT1_WIDTH                  1  /* IM_HPDET_EINT1 */
+#define ARIZONA_IM_MICDET_EINT1                  0x1000  /* IM_MICDET_EINT1 */
+#define ARIZONA_IM_MICDET_EINT1_MASK             0x1000  /* IM_MICDET_EINT1 */
+#define ARIZONA_IM_MICDET_EINT1_SHIFT                12  /* IM_MICDET_EINT1 */
+#define ARIZONA_IM_MICDET_EINT1_WIDTH                 1  /* IM_MICDET_EINT1 */
+#define ARIZONA_IM_WSEQ_DONE_EINT1               0x0800  /* IM_WSEQ_DONE_EINT1 */
+#define ARIZONA_IM_WSEQ_DONE_EINT1_MASK          0x0800  /* IM_WSEQ_DONE_EINT1 */
+#define ARIZONA_IM_WSEQ_DONE_EINT1_SHIFT             11  /* IM_WSEQ_DONE_EINT1 */
+#define ARIZONA_IM_WSEQ_DONE_EINT1_WIDTH              1  /* IM_WSEQ_DONE_EINT1 */
+#define ARIZONA_IM_DRC2_SIG_DET_EINT1            0x0400  /* IM_DRC2_SIG_DET_EINT1 */
+#define ARIZONA_IM_DRC2_SIG_DET_EINT1_MASK       0x0400  /* IM_DRC2_SIG_DET_EINT1 */
+#define ARIZONA_IM_DRC2_SIG_DET_EINT1_SHIFT          10  /* IM_DRC2_SIG_DET_EINT1 */
+#define ARIZONA_IM_DRC2_SIG_DET_EINT1_WIDTH           1  /* IM_DRC2_SIG_DET_EINT1 */
+#define ARIZONA_IM_DRC1_SIG_DET_EINT1            0x0200  /* IM_DRC1_SIG_DET_EINT1 */
+#define ARIZONA_IM_DRC1_SIG_DET_EINT1_MASK       0x0200  /* IM_DRC1_SIG_DET_EINT1 */
+#define ARIZONA_IM_DRC1_SIG_DET_EINT1_SHIFT           9  /* IM_DRC1_SIG_DET_EINT1 */
+#define ARIZONA_IM_DRC1_SIG_DET_EINT1_WIDTH           1  /* IM_DRC1_SIG_DET_EINT1 */
+#define ARIZONA_IM_ASRC2_LOCK_EINT1              0x0100  /* IM_ASRC2_LOCK_EINT1 */
+#define ARIZONA_IM_ASRC2_LOCK_EINT1_MASK         0x0100  /* IM_ASRC2_LOCK_EINT1 */
+#define ARIZONA_IM_ASRC2_LOCK_EINT1_SHIFT             8  /* IM_ASRC2_LOCK_EINT1 */
+#define ARIZONA_IM_ASRC2_LOCK_EINT1_WIDTH             1  /* IM_ASRC2_LOCK_EINT1 */
+#define ARIZONA_IM_ASRC1_LOCK_EINT1              0x0080  /* IM_ASRC1_LOCK_EINT1 */
+#define ARIZONA_IM_ASRC1_LOCK_EINT1_MASK         0x0080  /* IM_ASRC1_LOCK_EINT1 */
+#define ARIZONA_IM_ASRC1_LOCK_EINT1_SHIFT             7  /* IM_ASRC1_LOCK_EINT1 */
+#define ARIZONA_IM_ASRC1_LOCK_EINT1_WIDTH             1  /* IM_ASRC1_LOCK_EINT1 */
+#define ARIZONA_IM_UNDERCLOCKED_EINT1            0x0040  /* IM_UNDERCLOCKED_EINT1 */
+#define ARIZONA_IM_UNDERCLOCKED_EINT1_MASK       0x0040  /* IM_UNDERCLOCKED_EINT1 */
+#define ARIZONA_IM_UNDERCLOCKED_EINT1_SHIFT           6  /* IM_UNDERCLOCKED_EINT1 */
+#define ARIZONA_IM_UNDERCLOCKED_EINT1_WIDTH           1  /* IM_UNDERCLOCKED_EINT1 */
+#define ARIZONA_IM_OVERCLOCKED_EINT1             0x0020  /* IM_OVERCLOCKED_EINT1 */
+#define ARIZONA_IM_OVERCLOCKED_EINT1_MASK        0x0020  /* IM_OVERCLOCKED_EINT1 */
+#define ARIZONA_IM_OVERCLOCKED_EINT1_SHIFT            5  /* IM_OVERCLOCKED_EINT1 */
+#define ARIZONA_IM_OVERCLOCKED_EINT1_WIDTH            1  /* IM_OVERCLOCKED_EINT1 */
+#define ARIZONA_IM_FLL2_LOCK_EINT1               0x0008  /* IM_FLL2_LOCK_EINT1 */
+#define ARIZONA_IM_FLL2_LOCK_EINT1_MASK          0x0008  /* IM_FLL2_LOCK_EINT1 */
+#define ARIZONA_IM_FLL2_LOCK_EINT1_SHIFT              3  /* IM_FLL2_LOCK_EINT1 */
+#define ARIZONA_IM_FLL2_LOCK_EINT1_WIDTH              1  /* IM_FLL2_LOCK_EINT1 */
+#define ARIZONA_IM_FLL1_LOCK_EINT1               0x0004  /* IM_FLL1_LOCK_EINT1 */
+#define ARIZONA_IM_FLL1_LOCK_EINT1_MASK          0x0004  /* IM_FLL1_LOCK_EINT1 */
+#define ARIZONA_IM_FLL1_LOCK_EINT1_SHIFT              2  /* IM_FLL1_LOCK_EINT1 */
+#define ARIZONA_IM_FLL1_LOCK_EINT1_WIDTH              1  /* IM_FLL1_LOCK_EINT1 */
+#define ARIZONA_IM_CLKGEN_ERR_EINT1              0x0002  /* IM_CLKGEN_ERR_EINT1 */
+#define ARIZONA_IM_CLKGEN_ERR_EINT1_MASK         0x0002  /* IM_CLKGEN_ERR_EINT1 */
+#define ARIZONA_IM_CLKGEN_ERR_EINT1_SHIFT             1  /* IM_CLKGEN_ERR_EINT1 */
+#define ARIZONA_IM_CLKGEN_ERR_EINT1_WIDTH             1  /* IM_CLKGEN_ERR_EINT1 */
+#define ARIZONA_IM_CLKGEN_ERR_ASYNC_EINT1        0x0001  /* IM_CLKGEN_ERR_ASYNC_EINT1 */
+#define ARIZONA_IM_CLKGEN_ERR_ASYNC_EINT1_MASK   0x0001  /* IM_CLKGEN_ERR_ASYNC_EINT1 */
+#define ARIZONA_IM_CLKGEN_ERR_ASYNC_EINT1_SHIFT       0  /* IM_CLKGEN_ERR_ASYNC_EINT1 */
+#define ARIZONA_IM_CLKGEN_ERR_ASYNC_EINT1_WIDTH       1  /* IM_CLKGEN_ERR_ASYNC_EINT1 */
+
+/*
+ * R3339 (0xD0B) - Interrupt Status 4 Mask
+ */
+#define ARIZONA_IM_ASRC_CFG_ERR_EINT1            0x8000  /* IM_ASRC_CFG_ERR_EINT1 */
+#define ARIZONA_IM_ASRC_CFG_ERR_EINT1_MASK       0x8000  /* IM_ASRC_CFG_ERR_EINT1 */
+#define ARIZONA_IM_ASRC_CFG_ERR_EINT1_SHIFT          15  /* IM_ASRC_CFG_ERR_EINT1 */
+#define ARIZONA_IM_ASRC_CFG_ERR_EINT1_WIDTH           1  /* IM_ASRC_CFG_ERR_EINT1 */
+#define ARIZONA_IM_AIF3_ERR_EINT1                0x4000  /* IM_AIF3_ERR_EINT1 */
+#define ARIZONA_IM_AIF3_ERR_EINT1_MASK           0x4000  /* IM_AIF3_ERR_EINT1 */
+#define ARIZONA_IM_AIF3_ERR_EINT1_SHIFT              14  /* IM_AIF3_ERR_EINT1 */
+#define ARIZONA_IM_AIF3_ERR_EINT1_WIDTH               1  /* IM_AIF3_ERR_EINT1 */
+#define ARIZONA_IM_AIF2_ERR_EINT1                0x2000  /* IM_AIF2_ERR_EINT1 */
+#define ARIZONA_IM_AIF2_ERR_EINT1_MASK           0x2000  /* IM_AIF2_ERR_EINT1 */
+#define ARIZONA_IM_AIF2_ERR_EINT1_SHIFT              13  /* IM_AIF2_ERR_EINT1 */
+#define ARIZONA_IM_AIF2_ERR_EINT1_WIDTH               1  /* IM_AIF2_ERR_EINT1 */
+#define ARIZONA_IM_AIF1_ERR_EINT1                0x1000  /* IM_AIF1_ERR_EINT1 */
+#define ARIZONA_IM_AIF1_ERR_EINT1_MASK           0x1000  /* IM_AIF1_ERR_EINT1 */
+#define ARIZONA_IM_AIF1_ERR_EINT1_SHIFT              12  /* IM_AIF1_ERR_EINT1 */
+#define ARIZONA_IM_AIF1_ERR_EINT1_WIDTH               1  /* IM_AIF1_ERR_EINT1 */
+#define ARIZONA_IM_CTRLIF_ERR_EINT1              0x0800  /* IM_CTRLIF_ERR_EINT1 */
+#define ARIZONA_IM_CTRLIF_ERR_EINT1_MASK         0x0800  /* IM_CTRLIF_ERR_EINT1 */
+#define ARIZONA_IM_CTRLIF_ERR_EINT1_SHIFT            11  /* IM_CTRLIF_ERR_EINT1 */
+#define ARIZONA_IM_CTRLIF_ERR_EINT1_WIDTH             1  /* IM_CTRLIF_ERR_EINT1 */
+#define ARIZONA_IM_MIXER_DROPPED_SAMPLE_EINT1    0x0400  /* IM_MIXER_DROPPED_SAMPLE_EINT1 */
+#define ARIZONA_IM_MIXER_DROPPED_SAMPLE_EINT1_MASK 0x0400  /* IM_MIXER_DROPPED_SAMPLE_EINT1 */
+#define ARIZONA_IM_MIXER_DROPPED_SAMPLE_EINT1_SHIFT     10  /* IM_MIXER_DROPPED_SAMPLE_EINT1 */
+#define ARIZONA_IM_MIXER_DROPPED_SAMPLE_EINT1_WIDTH      1  /* IM_MIXER_DROPPED_SAMPLE_EINT1 */
+#define ARIZONA_IM_ASYNC_CLK_ENA_LOW_EINT1       0x0200  /* IM_ASYNC_CLK_ENA_LOW_EINT1 */
+#define ARIZONA_IM_ASYNC_CLK_ENA_LOW_EINT1_MASK  0x0200  /* IM_ASYNC_CLK_ENA_LOW_EINT1 */
+#define ARIZONA_IM_ASYNC_CLK_ENA_LOW_EINT1_SHIFT      9  /* IM_ASYNC_CLK_ENA_LOW_EINT1 */
+#define ARIZONA_IM_ASYNC_CLK_ENA_LOW_EINT1_WIDTH      1  /* IM_ASYNC_CLK_ENA_LOW_EINT1 */
+#define ARIZONA_IM_SYSCLK_ENA_LOW_EINT1          0x0100  /* IM_SYSCLK_ENA_LOW_EINT1 */
+#define ARIZONA_IM_SYSCLK_ENA_LOW_EINT1_MASK     0x0100  /* IM_SYSCLK_ENA_LOW_EINT1 */
+#define ARIZONA_IM_SYSCLK_ENA_LOW_EINT1_SHIFT         8  /* IM_SYSCLK_ENA_LOW_EINT1 */
+#define ARIZONA_IM_SYSCLK_ENA_LOW_EINT1_WIDTH         1  /* IM_SYSCLK_ENA_LOW_EINT1 */
+#define ARIZONA_IM_ISRC1_CFG_ERR_EINT1           0x0080  /* IM_ISRC1_CFG_ERR_EINT1 */
+#define ARIZONA_IM_ISRC1_CFG_ERR_EINT1_MASK      0x0080  /* IM_ISRC1_CFG_ERR_EINT1 */
+#define ARIZONA_IM_ISRC1_CFG_ERR_EINT1_SHIFT          7  /* IM_ISRC1_CFG_ERR_EINT1 */
+#define ARIZONA_IM_ISRC1_CFG_ERR_EINT1_WIDTH          1  /* IM_ISRC1_CFG_ERR_EINT1 */
+#define ARIZONA_IM_ISRC2_CFG_ERR_EINT1           0x0040  /* IM_ISRC2_CFG_ERR_EINT1 */
+#define ARIZONA_IM_ISRC2_CFG_ERR_EINT1_MASK      0x0040  /* IM_ISRC2_CFG_ERR_EINT1 */
+#define ARIZONA_IM_ISRC2_CFG_ERR_EINT1_SHIFT          6  /* IM_ISRC2_CFG_ERR_EINT1 */
+#define ARIZONA_IM_ISRC2_CFG_ERR_EINT1_WIDTH          1  /* IM_ISRC2_CFG_ERR_EINT1 */
+
+/*
+ * R3340 (0xD0C) - Interrupt Status 5 Mask
+ */
+#define ARIZONA_IM_BOOT_DONE_EINT1               0x0100  /* IM_BOOT_DONE_EINT1 */
+#define ARIZONA_IM_BOOT_DONE_EINT1_MASK          0x0100  /* IM_BOOT_DONE_EINT1 */
+#define ARIZONA_IM_BOOT_DONE_EINT1_SHIFT              8  /* IM_BOOT_DONE_EINT1 */
+#define ARIZONA_IM_BOOT_DONE_EINT1_WIDTH              1  /* IM_BOOT_DONE_EINT1 */
+#define ARIZONA_IM_DCS_DAC_DONE_EINT1            0x0080  /* IM_DCS_DAC_DONE_EINT1 */
+#define ARIZONA_IM_DCS_DAC_DONE_EINT1_MASK       0x0080  /* IM_DCS_DAC_DONE_EINT1 */
+#define ARIZONA_IM_DCS_DAC_DONE_EINT1_SHIFT           7  /* IM_DCS_DAC_DONE_EINT1 */
+#define ARIZONA_IM_DCS_DAC_DONE_EINT1_WIDTH           1  /* IM_DCS_DAC_DONE_EINT1 */
+#define ARIZONA_IM_DCS_HP_DONE_EINT1             0x0040  /* IM_DCS_HP_DONE_EINT1 */
+#define ARIZONA_IM_DCS_HP_DONE_EINT1_MASK        0x0040  /* IM_DCS_HP_DONE_EINT1 */
+#define ARIZONA_IM_DCS_HP_DONE_EINT1_SHIFT            6  /* IM_DCS_HP_DONE_EINT1 */
+#define ARIZONA_IM_DCS_HP_DONE_EINT1_WIDTH            1  /* IM_DCS_HP_DONE_EINT1 */
+#define ARIZONA_IM_FLL2_CLOCK_OK_EINT1           0x0002  /* IM_FLL2_CLOCK_OK_EINT1 */
+#define ARIZONA_IM_FLL2_CLOCK_OK_EINT1_MASK      0x0002  /* IM_FLL2_CLOCK_OK_EINT1 */
+#define ARIZONA_IM_FLL2_CLOCK_OK_EINT1_SHIFT          1  /* IM_FLL2_CLOCK_OK_EINT1 */
+#define ARIZONA_IM_FLL2_CLOCK_OK_EINT1_WIDTH          1  /* IM_FLL2_CLOCK_OK_EINT1 */
+#define ARIZONA_IM_FLL1_CLOCK_OK_EINT1           0x0001  /* IM_FLL1_CLOCK_OK_EINT1 */
+#define ARIZONA_IM_FLL1_CLOCK_OK_EINT1_MASK      0x0001  /* IM_FLL1_CLOCK_OK_EINT1 */
+#define ARIZONA_IM_FLL1_CLOCK_OK_EINT1_SHIFT          0  /* IM_FLL1_CLOCK_OK_EINT1 */
+#define ARIZONA_IM_FLL1_CLOCK_OK_EINT1_WIDTH          1  /* IM_FLL1_CLOCK_OK_EINT1 */
+
+/*
+ * R3343 (0xD0F) - Interrupt Control
+ */
+#define ARIZONA_IM_IRQ1                          0x0001  /* IM_IRQ1 */
+#define ARIZONA_IM_IRQ1_MASK                     0x0001  /* IM_IRQ1 */
+#define ARIZONA_IM_IRQ1_SHIFT                         0  /* IM_IRQ1 */
+#define ARIZONA_IM_IRQ1_WIDTH                         1  /* IM_IRQ1 */
+
+/*
+ * R3344 (0xD10) - IRQ2 Status 1
+ */
+#define ARIZONA_GP4_EINT2                        0x0008  /* GP4_EINT2 */
+#define ARIZONA_GP4_EINT2_MASK                   0x0008  /* GP4_EINT2 */
+#define ARIZONA_GP4_EINT2_SHIFT                       3  /* GP4_EINT2 */
+#define ARIZONA_GP4_EINT2_WIDTH                       1  /* GP4_EINT2 */
+#define ARIZONA_GP3_EINT2                        0x0004  /* GP3_EINT2 */
+#define ARIZONA_GP3_EINT2_MASK                   0x0004  /* GP3_EINT2 */
+#define ARIZONA_GP3_EINT2_SHIFT                       2  /* GP3_EINT2 */
+#define ARIZONA_GP3_EINT2_WIDTH                       1  /* GP3_EINT2 */
+#define ARIZONA_GP2_EINT2                        0x0002  /* GP2_EINT2 */
+#define ARIZONA_GP2_EINT2_MASK                   0x0002  /* GP2_EINT2 */
+#define ARIZONA_GP2_EINT2_SHIFT                       1  /* GP2_EINT2 */
+#define ARIZONA_GP2_EINT2_WIDTH                       1  /* GP2_EINT2 */
+#define ARIZONA_GP1_EINT2                        0x0001  /* GP1_EINT2 */
+#define ARIZONA_GP1_EINT2_MASK                   0x0001  /* GP1_EINT2 */
+#define ARIZONA_GP1_EINT2_SHIFT                       0  /* GP1_EINT2 */
+#define ARIZONA_GP1_EINT2_WIDTH                       1  /* GP1_EINT2 */
+
+/*
+ * R3345 (0xD11) - IRQ2 Status 2
+ */
+#define ARIZONA_DSP1_RAM_RDY_EINT2               0x0100  /* DSP1_RAM_RDY_EINT2 */
+#define ARIZONA_DSP1_RAM_RDY_EINT2_MASK          0x0100  /* DSP1_RAM_RDY_EINT2 */
+#define ARIZONA_DSP1_RAM_RDY_EINT2_SHIFT              8  /* DSP1_RAM_RDY_EINT2 */
+#define ARIZONA_DSP1_RAM_RDY_EINT2_WIDTH              1  /* DSP1_RAM_RDY_EINT2 */
+#define ARIZONA_DSP_IRQ2_EINT2                   0x0002  /* DSP_IRQ2_EINT2 */
+#define ARIZONA_DSP_IRQ2_EINT2_MASK              0x0002  /* DSP_IRQ2_EINT2 */
+#define ARIZONA_DSP_IRQ2_EINT2_SHIFT                  1  /* DSP_IRQ2_EINT2 */
+#define ARIZONA_DSP_IRQ2_EINT2_WIDTH                  1  /* DSP_IRQ2_EINT2 */
+#define ARIZONA_DSP_IRQ1_EINT2                   0x0001  /* DSP_IRQ1_EINT2 */
+#define ARIZONA_DSP_IRQ1_EINT2_MASK              0x0001  /* DSP_IRQ1_EINT2 */
+#define ARIZONA_DSP_IRQ1_EINT2_SHIFT                  0  /* DSP_IRQ1_EINT2 */
+#define ARIZONA_DSP_IRQ1_EINT2_WIDTH                  1  /* DSP_IRQ1_EINT2 */
+
+/*
+ * R3346 (0xD12) - IRQ2 Status 3
+ */
+#define ARIZONA_SPK_SHUTDOWN_WARN_EINT2          0x8000  /* SPK_SHUTDOWN_WARN_EINT2 */
+#define ARIZONA_SPK_SHUTDOWN_WARN_EINT2_MASK     0x8000  /* SPK_SHUTDOWN_WARN_EINT2 */
+#define ARIZONA_SPK_SHUTDOWN_WARN_EINT2_SHIFT        15  /* SPK_SHUTDOWN_WARN_EINT2 */
+#define ARIZONA_SPK_SHUTDOWN_WARN_EINT2_WIDTH         1  /* SPK_SHUTDOWN_WARN_EINT2 */
+#define ARIZONA_SPK_SHUTDOWN_EINT2               0x4000  /* SPK_SHUTDOWN_EINT2 */
+#define ARIZONA_SPK_SHUTDOWN_EINT2_MASK          0x4000  /* SPK_SHUTDOWN_EINT2 */
+#define ARIZONA_SPK_SHUTDOWN_EINT2_SHIFT             14  /* SPK_SHUTDOWN_EINT2 */
+#define ARIZONA_SPK_SHUTDOWN_EINT2_WIDTH              1  /* SPK_SHUTDOWN_EINT2 */
+#define ARIZONA_HPDET_EINT2                      0x2000  /* HPDET_EINT2 */
+#define ARIZONA_HPDET_EINT2_MASK                 0x2000  /* HPDET_EINT2 */
+#define ARIZONA_HPDET_EINT2_SHIFT                    13  /* HPDET_EINT2 */
+#define ARIZONA_HPDET_EINT2_WIDTH                     1  /* HPDET_EINT2 */
+#define ARIZONA_MICDET_EINT2                     0x1000  /* MICDET_EINT2 */
+#define ARIZONA_MICDET_EINT2_MASK                0x1000  /* MICDET_EINT2 */
+#define ARIZONA_MICDET_EINT2_SHIFT                   12  /* MICDET_EINT2 */
+#define ARIZONA_MICDET_EINT2_WIDTH                    1  /* MICDET_EINT2 */
+#define ARIZONA_WSEQ_DONE_EINT2                  0x0800  /* WSEQ_DONE_EINT2 */
+#define ARIZONA_WSEQ_DONE_EINT2_MASK             0x0800  /* WSEQ_DONE_EINT2 */
+#define ARIZONA_WSEQ_DONE_EINT2_SHIFT                11  /* WSEQ_DONE_EINT2 */
+#define ARIZONA_WSEQ_DONE_EINT2_WIDTH                 1  /* WSEQ_DONE_EINT2 */
+#define ARIZONA_DRC2_SIG_DET_EINT2               0x0400  /* DRC2_SIG_DET_EINT2 */
+#define ARIZONA_DRC2_SIG_DET_EINT2_MASK          0x0400  /* DRC2_SIG_DET_EINT2 */
+#define ARIZONA_DRC2_SIG_DET_EINT2_SHIFT             10  /* DRC2_SIG_DET_EINT2 */
+#define ARIZONA_DRC2_SIG_DET_EINT2_WIDTH              1  /* DRC2_SIG_DET_EINT2 */
+#define ARIZONA_DRC1_SIG_DET_EINT2               0x0200  /* DRC1_SIG_DET_EINT2 */
+#define ARIZONA_DRC1_SIG_DET_EINT2_MASK          0x0200  /* DRC1_SIG_DET_EINT2 */
+#define ARIZONA_DRC1_SIG_DET_EINT2_SHIFT              9  /* DRC1_SIG_DET_EINT2 */
+#define ARIZONA_DRC1_SIG_DET_EINT2_WIDTH              1  /* DRC1_SIG_DET_EINT2 */
+#define ARIZONA_ASRC2_LOCK_EINT2                 0x0100  /* ASRC2_LOCK_EINT2 */
+#define ARIZONA_ASRC2_LOCK_EINT2_MASK            0x0100  /* ASRC2_LOCK_EINT2 */
+#define ARIZONA_ASRC2_LOCK_EINT2_SHIFT                8  /* ASRC2_LOCK_EINT2 */
+#define ARIZONA_ASRC2_LOCK_EINT2_WIDTH                1  /* ASRC2_LOCK_EINT2 */
+#define ARIZONA_ASRC1_LOCK_EINT2                 0x0080  /* ASRC1_LOCK_EINT2 */
+#define ARIZONA_ASRC1_LOCK_EINT2_MASK            0x0080  /* ASRC1_LOCK_EINT2 */
+#define ARIZONA_ASRC1_LOCK_EINT2_SHIFT                7  /* ASRC1_LOCK_EINT2 */
+#define ARIZONA_ASRC1_LOCK_EINT2_WIDTH                1  /* ASRC1_LOCK_EINT2 */
+#define ARIZONA_UNDERCLOCKED_EINT2               0x0040  /* UNDERCLOCKED_EINT2 */
+#define ARIZONA_UNDERCLOCKED_EINT2_MASK          0x0040  /* UNDERCLOCKED_EINT2 */
+#define ARIZONA_UNDERCLOCKED_EINT2_SHIFT              6  /* UNDERCLOCKED_EINT2 */
+#define ARIZONA_UNDERCLOCKED_EINT2_WIDTH              1  /* UNDERCLOCKED_EINT2 */
+#define ARIZONA_OVERCLOCKED_EINT2                0x0020  /* OVERCLOCKED_EINT2 */
+#define ARIZONA_OVERCLOCKED_EINT2_MASK           0x0020  /* OVERCLOCKED_EINT2 */
+#define ARIZONA_OVERCLOCKED_EINT2_SHIFT               5  /* OVERCLOCKED_EINT2 */
+#define ARIZONA_OVERCLOCKED_EINT2_WIDTH               1  /* OVERCLOCKED_EINT2 */
+#define ARIZONA_FLL2_LOCK_EINT2                  0x0008  /* FLL2_LOCK_EINT2 */
+#define ARIZONA_FLL2_LOCK_EINT2_MASK             0x0008  /* FLL2_LOCK_EINT2 */
+#define ARIZONA_FLL2_LOCK_EINT2_SHIFT                 3  /* FLL2_LOCK_EINT2 */
+#define ARIZONA_FLL2_LOCK_EINT2_WIDTH                 1  /* FLL2_LOCK_EINT2 */
+#define ARIZONA_FLL1_LOCK_EINT2                  0x0004  /* FLL1_LOCK_EINT2 */
+#define ARIZONA_FLL1_LOCK_EINT2_MASK             0x0004  /* FLL1_LOCK_EINT2 */
+#define ARIZONA_FLL1_LOCK_EINT2_SHIFT                 2  /* FLL1_LOCK_EINT2 */
+#define ARIZONA_FLL1_LOCK_EINT2_WIDTH                 1  /* FLL1_LOCK_EINT2 */
+#define ARIZONA_CLKGEN_ERR_EINT2                 0x0002  /* CLKGEN_ERR_EINT2 */
+#define ARIZONA_CLKGEN_ERR_EINT2_MASK            0x0002  /* CLKGEN_ERR_EINT2 */
+#define ARIZONA_CLKGEN_ERR_EINT2_SHIFT                1  /* CLKGEN_ERR_EINT2 */
+#define ARIZONA_CLKGEN_ERR_EINT2_WIDTH                1  /* CLKGEN_ERR_EINT2 */
+#define ARIZONA_CLKGEN_ERR_ASYNC_EINT2           0x0001  /* CLKGEN_ERR_ASYNC_EINT2 */
+#define ARIZONA_CLKGEN_ERR_ASYNC_EINT2_MASK      0x0001  /* CLKGEN_ERR_ASYNC_EINT2 */
+#define ARIZONA_CLKGEN_ERR_ASYNC_EINT2_SHIFT          0  /* CLKGEN_ERR_ASYNC_EINT2 */
+#define ARIZONA_CLKGEN_ERR_ASYNC_EINT2_WIDTH          1  /* CLKGEN_ERR_ASYNC_EINT2 */
+
+/*
+ * R3347 (0xD13) - IRQ2 Status 4
+ */
+#define ARIZONA_ASRC_CFG_ERR_EINT2               0x8000  /* ASRC_CFG_ERR_EINT2 */
+#define ARIZONA_ASRC_CFG_ERR_EINT2_MASK          0x8000  /* ASRC_CFG_ERR_EINT2 */
+#define ARIZONA_ASRC_CFG_ERR_EINT2_SHIFT             15  /* ASRC_CFG_ERR_EINT2 */
+#define ARIZONA_ASRC_CFG_ERR_EINT2_WIDTH              1  /* ASRC_CFG_ERR_EINT2 */
+#define ARIZONA_AIF3_ERR_EINT2                   0x4000  /* AIF3_ERR_EINT2 */
+#define ARIZONA_AIF3_ERR_EINT2_MASK              0x4000  /* AIF3_ERR_EINT2 */
+#define ARIZONA_AIF3_ERR_EINT2_SHIFT                 14  /* AIF3_ERR_EINT2 */
+#define ARIZONA_AIF3_ERR_EINT2_WIDTH                  1  /* AIF3_ERR_EINT2 */
+#define ARIZONA_AIF2_ERR_EINT2                   0x2000  /* AIF2_ERR_EINT2 */
+#define ARIZONA_AIF2_ERR_EINT2_MASK              0x2000  /* AIF2_ERR_EINT2 */
+#define ARIZONA_AIF2_ERR_EINT2_SHIFT                 13  /* AIF2_ERR_EINT2 */
+#define ARIZONA_AIF2_ERR_EINT2_WIDTH                  1  /* AIF2_ERR_EINT2 */
+#define ARIZONA_AIF1_ERR_EINT2                   0x1000  /* AIF1_ERR_EINT2 */
+#define ARIZONA_AIF1_ERR_EINT2_MASK              0x1000  /* AIF1_ERR_EINT2 */
+#define ARIZONA_AIF1_ERR_EINT2_SHIFT                 12  /* AIF1_ERR_EINT2 */
+#define ARIZONA_AIF1_ERR_EINT2_WIDTH                  1  /* AIF1_ERR_EINT2 */
+#define ARIZONA_CTRLIF_ERR_EINT2                 0x0800  /* CTRLIF_ERR_EINT2 */
+#define ARIZONA_CTRLIF_ERR_EINT2_MASK            0x0800  /* CTRLIF_ERR_EINT2 */
+#define ARIZONA_CTRLIF_ERR_EINT2_SHIFT               11  /* CTRLIF_ERR_EINT2 */
+#define ARIZONA_CTRLIF_ERR_EINT2_WIDTH                1  /* CTRLIF_ERR_EINT2 */
+#define ARIZONA_MIXER_DROPPED_SAMPLE_EINT2       0x0400  /* MIXER_DROPPED_SAMPLE_EINT2 */
+#define ARIZONA_MIXER_DROPPED_SAMPLE_EINT2_MASK  0x0400  /* MIXER_DROPPED_SAMPLE_EINT2 */
+#define ARIZONA_MIXER_DROPPED_SAMPLE_EINT2_SHIFT     10  /* MIXER_DROPPED_SAMPLE_EINT2 */
+#define ARIZONA_MIXER_DROPPED_SAMPLE_EINT2_WIDTH      1  /* MIXER_DROPPED_SAMPLE_EINT2 */
+#define ARIZONA_ASYNC_CLK_ENA_LOW_EINT2          0x0200  /* ASYNC_CLK_ENA_LOW_EINT2 */
+#define ARIZONA_ASYNC_CLK_ENA_LOW_EINT2_MASK     0x0200  /* ASYNC_CLK_ENA_LOW_EINT2 */
+#define ARIZONA_ASYNC_CLK_ENA_LOW_EINT2_SHIFT         9  /* ASYNC_CLK_ENA_LOW_EINT2 */
+#define ARIZONA_ASYNC_CLK_ENA_LOW_EINT2_WIDTH         1  /* ASYNC_CLK_ENA_LOW_EINT2 */
+#define ARIZONA_SYSCLK_ENA_LOW_EINT2             0x0100  /* SYSCLK_ENA_LOW_EINT2 */
+#define ARIZONA_SYSCLK_ENA_LOW_EINT2_MASK        0x0100  /* SYSCLK_ENA_LOW_EINT2 */
+#define ARIZONA_SYSCLK_ENA_LOW_EINT2_SHIFT            8  /* SYSCLK_ENA_LOW_EINT2 */
+#define ARIZONA_SYSCLK_ENA_LOW_EINT2_WIDTH            1  /* SYSCLK_ENA_LOW_EINT2 */
+#define ARIZONA_ISRC1_CFG_ERR_EINT2              0x0080  /* ISRC1_CFG_ERR_EINT2 */
+#define ARIZONA_ISRC1_CFG_ERR_EINT2_MASK         0x0080  /* ISRC1_CFG_ERR_EINT2 */
+#define ARIZONA_ISRC1_CFG_ERR_EINT2_SHIFT             7  /* ISRC1_CFG_ERR_EINT2 */
+#define ARIZONA_ISRC1_CFG_ERR_EINT2_WIDTH             1  /* ISRC1_CFG_ERR_EINT2 */
+#define ARIZONA_ISRC2_CFG_ERR_EINT2              0x0040  /* ISRC2_CFG_ERR_EINT2 */
+#define ARIZONA_ISRC2_CFG_ERR_EINT2_MASK         0x0040  /* ISRC2_CFG_ERR_EINT2 */
+#define ARIZONA_ISRC2_CFG_ERR_EINT2_SHIFT             6  /* ISRC2_CFG_ERR_EINT2 */
+#define ARIZONA_ISRC2_CFG_ERR_EINT2_WIDTH             1  /* ISRC2_CFG_ERR_EINT2 */
+
+/*
+ * R3348 (0xD14) - IRQ2 Status 5
+ */
+#define ARIZONA_BOOT_DONE_EINT2                  0x0100  /* BOOT_DONE_EINT2 */
+#define ARIZONA_BOOT_DONE_EINT2_MASK             0x0100  /* BOOT_DONE_EINT2 */
+#define ARIZONA_BOOT_DONE_EINT2_SHIFT                 8  /* BOOT_DONE_EINT2 */
+#define ARIZONA_BOOT_DONE_EINT2_WIDTH                 1  /* BOOT_DONE_EINT2 */
+#define ARIZONA_DCS_DAC_DONE_EINT2               0x0080  /* DCS_DAC_DONE_EINT2 */
+#define ARIZONA_DCS_DAC_DONE_EINT2_MASK          0x0080  /* DCS_DAC_DONE_EINT2 */
+#define ARIZONA_DCS_DAC_DONE_EINT2_SHIFT              7  /* DCS_DAC_DONE_EINT2 */
+#define ARIZONA_DCS_DAC_DONE_EINT2_WIDTH              1  /* DCS_DAC_DONE_EINT2 */
+#define ARIZONA_DCS_HP_DONE_EINT2                0x0040  /* DCS_HP_DONE_EINT2 */
+#define ARIZONA_DCS_HP_DONE_EINT2_MASK           0x0040  /* DCS_HP_DONE_EINT2 */
+#define ARIZONA_DCS_HP_DONE_EINT2_SHIFT               6  /* DCS_HP_DONE_EINT2 */
+#define ARIZONA_DCS_HP_DONE_EINT2_WIDTH               1  /* DCS_HP_DONE_EINT2 */
+#define ARIZONA_FLL2_CLOCK_OK_EINT2              0x0002  /* FLL2_CLOCK_OK_EINT2 */
+#define ARIZONA_FLL2_CLOCK_OK_EINT2_MASK         0x0002  /* FLL2_CLOCK_OK_EINT2 */
+#define ARIZONA_FLL2_CLOCK_OK_EINT2_SHIFT             1  /* FLL2_CLOCK_OK_EINT2 */
+#define ARIZONA_FLL2_CLOCK_OK_EINT2_WIDTH             1  /* FLL2_CLOCK_OK_EINT2 */
+#define ARIZONA_FLL1_CLOCK_OK_EINT2              0x0001  /* FLL1_CLOCK_OK_EINT2 */
+#define ARIZONA_FLL1_CLOCK_OK_EINT2_MASK         0x0001  /* FLL1_CLOCK_OK_EINT2 */
+#define ARIZONA_FLL1_CLOCK_OK_EINT2_SHIFT             0  /* FLL1_CLOCK_OK_EINT2 */
+#define ARIZONA_FLL1_CLOCK_OK_EINT2_WIDTH             1  /* FLL1_CLOCK_OK_EINT2 */
+
+/*
+ * R3352 (0xD18) - IRQ2 Status 1 Mask
+ */
+#define ARIZONA_IM_GP4_EINT2                     0x0008  /* IM_GP4_EINT2 */
+#define ARIZONA_IM_GP4_EINT2_MASK                0x0008  /* IM_GP4_EINT2 */
+#define ARIZONA_IM_GP4_EINT2_SHIFT                    3  /* IM_GP4_EINT2 */
+#define ARIZONA_IM_GP4_EINT2_WIDTH                    1  /* IM_GP4_EINT2 */
+#define ARIZONA_IM_GP3_EINT2                     0x0004  /* IM_GP3_EINT2 */
+#define ARIZONA_IM_GP3_EINT2_MASK                0x0004  /* IM_GP3_EINT2 */
+#define ARIZONA_IM_GP3_EINT2_SHIFT                    2  /* IM_GP3_EINT2 */
+#define ARIZONA_IM_GP3_EINT2_WIDTH                    1  /* IM_GP3_EINT2 */
+#define ARIZONA_IM_GP2_EINT2                     0x0002  /* IM_GP2_EINT2 */
+#define ARIZONA_IM_GP2_EINT2_MASK                0x0002  /* IM_GP2_EINT2 */
+#define ARIZONA_IM_GP2_EINT2_SHIFT                    1  /* IM_GP2_EINT2 */
+#define ARIZONA_IM_GP2_EINT2_WIDTH                    1  /* IM_GP2_EINT2 */
+#define ARIZONA_IM_GP1_EINT2                     0x0001  /* IM_GP1_EINT2 */
+#define ARIZONA_IM_GP1_EINT2_MASK                0x0001  /* IM_GP1_EINT2 */
+#define ARIZONA_IM_GP1_EINT2_SHIFT                    0  /* IM_GP1_EINT2 */
+#define ARIZONA_IM_GP1_EINT2_WIDTH                    1  /* IM_GP1_EINT2 */
+
+/*
+ * R3353 (0xD19) - IRQ2 Status 2 Mask
+ */
+#define ARIZONA_IM_DSP1_RAM_RDY_EINT2            0x0100  /* IM_DSP1_RAM_RDY_EINT2 */
+#define ARIZONA_IM_DSP1_RAM_RDY_EINT2_MASK       0x0100  /* IM_DSP1_RAM_RDY_EINT2 */
+#define ARIZONA_IM_DSP1_RAM_RDY_EINT2_SHIFT           8  /* IM_DSP1_RAM_RDY_EINT2 */
+#define ARIZONA_IM_DSP1_RAM_RDY_EINT2_WIDTH           1  /* IM_DSP1_RAM_RDY_EINT2 */
+#define ARIZONA_IM_DSP_IRQ2_EINT2                0x0002  /* IM_DSP_IRQ2_EINT2 */
+#define ARIZONA_IM_DSP_IRQ2_EINT2_MASK           0x0002  /* IM_DSP_IRQ2_EINT2 */
+#define ARIZONA_IM_DSP_IRQ2_EINT2_SHIFT               1  /* IM_DSP_IRQ2_EINT2 */
+#define ARIZONA_IM_DSP_IRQ2_EINT2_WIDTH               1  /* IM_DSP_IRQ2_EINT2 */
+#define ARIZONA_IM_DSP_IRQ1_EINT2                0x0001  /* IM_DSP_IRQ1_EINT2 */
+#define ARIZONA_IM_DSP_IRQ1_EINT2_MASK           0x0001  /* IM_DSP_IRQ1_EINT2 */
+#define ARIZONA_IM_DSP_IRQ1_EINT2_SHIFT               0  /* IM_DSP_IRQ1_EINT2 */
+#define ARIZONA_IM_DSP_IRQ1_EINT2_WIDTH               1  /* IM_DSP_IRQ1_EINT2 */
+
+/*
+ * R3354 (0xD1A) - IRQ2 Status 3 Mask
+ */
+#define ARIZONA_IM_SPK_SHUTDOWN_WARN_EINT2       0x8000  /* IM_SPK_SHUTDOWN_WARN_EINT2 */
+#define ARIZONA_IM_SPK_SHUTDOWN_WARN_EINT2_MASK  0x8000  /* IM_SPK_SHUTDOWN_WARN_EINT2 */
+#define ARIZONA_IM_SPK_SHUTDOWN_WARN_EINT2_SHIFT     15  /* IM_SPK_SHUTDOWN_WARN_EINT2 */
+#define ARIZONA_IM_SPK_SHUTDOWN_WARN_EINT2_WIDTH      1  /* IM_SPK_SHUTDOWN_WARN_EINT2 */
+#define ARIZONA_IM_SPK_SHUTDOWN_EINT2            0x4000  /* IM_SPK_SHUTDOWN_EINT2 */
+#define ARIZONA_IM_SPK_SHUTDOWN_EINT2_MASK       0x4000  /* IM_SPK_SHUTDOWN_EINT2 */
+#define ARIZONA_IM_SPK_SHUTDOWN_EINT2_SHIFT          14  /* IM_SPK_SHUTDOWN_EINT2 */
+#define ARIZONA_IM_SPK_SHUTDOWN_EINT2_WIDTH           1  /* IM_SPK_SHUTDOWN_EINT2 */
+#define ARIZONA_IM_HPDET_EINT2                   0x2000  /* IM_HPDET_EINT2 */
+#define ARIZONA_IM_HPDET_EINT2_MASK              0x2000  /* IM_HPDET_EINT2 */
+#define ARIZONA_IM_HPDET_EINT2_SHIFT                 13  /* IM_HPDET_EINT2 */
+#define ARIZONA_IM_HPDET_EINT2_WIDTH                  1  /* IM_HPDET_EINT2 */
+#define ARIZONA_IM_MICDET_EINT2                  0x1000  /* IM_MICDET_EINT2 */
+#define ARIZONA_IM_MICDET_EINT2_MASK             0x1000  /* IM_MICDET_EINT2 */
+#define ARIZONA_IM_MICDET_EINT2_SHIFT                12  /* IM_MICDET_EINT2 */
+#define ARIZONA_IM_MICDET_EINT2_WIDTH                 1  /* IM_MICDET_EINT2 */
+#define ARIZONA_IM_WSEQ_DONE_EINT2               0x0800  /* IM_WSEQ_DONE_EINT2 */
+#define ARIZONA_IM_WSEQ_DONE_EINT2_MASK          0x0800  /* IM_WSEQ_DONE_EINT2 */
+#define ARIZONA_IM_WSEQ_DONE_EINT2_SHIFT             11  /* IM_WSEQ_DONE_EINT2 */
+#define ARIZONA_IM_WSEQ_DONE_EINT2_WIDTH              1  /* IM_WSEQ_DONE_EINT2 */
+#define ARIZONA_IM_DRC2_SIG_DET_EINT2            0x0400  /* IM_DRC2_SIG_DET_EINT2 */
+#define ARIZONA_IM_DRC2_SIG_DET_EINT2_MASK       0x0400  /* IM_DRC2_SIG_DET_EINT2 */
+#define ARIZONA_IM_DRC2_SIG_DET_EINT2_SHIFT          10  /* IM_DRC2_SIG_DET_EINT2 */
+#define ARIZONA_IM_DRC2_SIG_DET_EINT2_WIDTH           1  /* IM_DRC2_SIG_DET_EINT2 */
+#define ARIZONA_IM_DRC1_SIG_DET_EINT2            0x0200  /* IM_DRC1_SIG_DET_EINT2 */
+#define ARIZONA_IM_DRC1_SIG_DET_EINT2_MASK       0x0200  /* IM_DRC1_SIG_DET_EINT2 */
+#define ARIZONA_IM_DRC1_SIG_DET_EINT2_SHIFT           9  /* IM_DRC1_SIG_DET_EINT2 */
+#define ARIZONA_IM_DRC1_SIG_DET_EINT2_WIDTH           1  /* IM_DRC1_SIG_DET_EINT2 */
+#define ARIZONA_IM_ASRC2_LOCK_EINT2              0x0100  /* IM_ASRC2_LOCK_EINT2 */
+#define ARIZONA_IM_ASRC2_LOCK_EINT2_MASK         0x0100  /* IM_ASRC2_LOCK_EINT2 */
+#define ARIZONA_IM_ASRC2_LOCK_EINT2_SHIFT             8  /* IM_ASRC2_LOCK_EINT2 */
+#define ARIZONA_IM_ASRC2_LOCK_EINT2_WIDTH             1  /* IM_ASRC2_LOCK_EINT2 */
+#define ARIZONA_IM_ASRC1_LOCK_EINT2              0x0080  /* IM_ASRC1_LOCK_EINT2 */
+#define ARIZONA_IM_ASRC1_LOCK_EINT2_MASK         0x0080  /* IM_ASRC1_LOCK_EINT2 */
+#define ARIZONA_IM_ASRC1_LOCK_EINT2_SHIFT             7  /* IM_ASRC1_LOCK_EINT2 */
+#define ARIZONA_IM_ASRC1_LOCK_EINT2_WIDTH             1  /* IM_ASRC1_LOCK_EINT2 */
+#define ARIZONA_IM_UNDERCLOCKED_EINT2            0x0040  /* IM_UNDERCLOCKED_EINT2 */
+#define ARIZONA_IM_UNDERCLOCKED_EINT2_MASK       0x0040  /* IM_UNDERCLOCKED_EINT2 */
+#define ARIZONA_IM_UNDERCLOCKED_EINT2_SHIFT           6  /* IM_UNDERCLOCKED_EINT2 */
+#define ARIZONA_IM_UNDERCLOCKED_EINT2_WIDTH           1  /* IM_UNDERCLOCKED_EINT2 */
+#define ARIZONA_IM_OVERCLOCKED_EINT2             0x0020  /* IM_OVERCLOCKED_EINT2 */
+#define ARIZONA_IM_OVERCLOCKED_EINT2_MASK        0x0020  /* IM_OVERCLOCKED_EINT2 */
+#define ARIZONA_IM_OVERCLOCKED_EINT2_SHIFT            5  /* IM_OVERCLOCKED_EINT2 */
+#define ARIZONA_IM_OVERCLOCKED_EINT2_WIDTH            1  /* IM_OVERCLOCKED_EINT2 */
+#define ARIZONA_IM_FLL2_LOCK_EINT2               0x0008  /* IM_FLL2_LOCK_EINT2 */
+#define ARIZONA_IM_FLL2_LOCK_EINT2_MASK          0x0008  /* IM_FLL2_LOCK_EINT2 */
+#define ARIZONA_IM_FLL2_LOCK_EINT2_SHIFT              3  /* IM_FLL2_LOCK_EINT2 */
+#define ARIZONA_IM_FLL2_LOCK_EINT2_WIDTH              1  /* IM_FLL2_LOCK_EINT2 */
+#define ARIZONA_IM_FLL1_LOCK_EINT2               0x0004  /* IM_FLL1_LOCK_EINT2 */
+#define ARIZONA_IM_FLL1_LOCK_EINT2_MASK          0x0004  /* IM_FLL1_LOCK_EINT2 */
+#define ARIZONA_IM_FLL1_LOCK_EINT2_SHIFT              2  /* IM_FLL1_LOCK_EINT2 */
+#define ARIZONA_IM_FLL1_LOCK_EINT2_WIDTH              1  /* IM_FLL1_LOCK_EINT2 */
+#define ARIZONA_IM_CLKGEN_ERR_EINT2              0x0002  /* IM_CLKGEN_ERR_EINT2 */
+#define ARIZONA_IM_CLKGEN_ERR_EINT2_MASK         0x0002  /* IM_CLKGEN_ERR_EINT2 */
+#define ARIZONA_IM_CLKGEN_ERR_EINT2_SHIFT             1  /* IM_CLKGEN_ERR_EINT2 */
+#define ARIZONA_IM_CLKGEN_ERR_EINT2_WIDTH             1  /* IM_CLKGEN_ERR_EINT2 */
+#define ARIZONA_IM_CLKGEN_ERR_ASYNC_EINT2        0x0001  /* IM_CLKGEN_ERR_ASYNC_EINT2 */
+#define ARIZONA_IM_CLKGEN_ERR_ASYNC_EINT2_MASK   0x0001  /* IM_CLKGEN_ERR_ASYNC_EINT2 */
+#define ARIZONA_IM_CLKGEN_ERR_ASYNC_EINT2_SHIFT       0  /* IM_CLKGEN_ERR_ASYNC_EINT2 */
+#define ARIZONA_IM_CLKGEN_ERR_ASYNC_EINT2_WIDTH       1  /* IM_CLKGEN_ERR_ASYNC_EINT2 */
+
+/*
+ * R3355 (0xD1B) - IRQ2 Status 4 Mask
+ */
+#define ARIZONA_IM_ASRC_CFG_ERR_EINT2            0x8000  /* IM_ASRC_CFG_ERR_EINT2 */
+#define ARIZONA_IM_ASRC_CFG_ERR_EINT2_MASK       0x8000  /* IM_ASRC_CFG_ERR_EINT2 */
+#define ARIZONA_IM_ASRC_CFG_ERR_EINT2_SHIFT          15  /* IM_ASRC_CFG_ERR_EINT2 */
+#define ARIZONA_IM_ASRC_CFG_ERR_EINT2_WIDTH           1  /* IM_ASRC_CFG_ERR_EINT2 */
+#define ARIZONA_IM_AIF3_ERR_EINT2                0x4000  /* IM_AIF3_ERR_EINT2 */
+#define ARIZONA_IM_AIF3_ERR_EINT2_MASK           0x4000  /* IM_AIF3_ERR_EINT2 */
+#define ARIZONA_IM_AIF3_ERR_EINT2_SHIFT              14  /* IM_AIF3_ERR_EINT2 */
+#define ARIZONA_IM_AIF3_ERR_EINT2_WIDTH               1  /* IM_AIF3_ERR_EINT2 */
+#define ARIZONA_IM_AIF2_ERR_EINT2                0x2000  /* IM_AIF2_ERR_EINT2 */
+#define ARIZONA_IM_AIF2_ERR_EINT2_MASK           0x2000  /* IM_AIF2_ERR_EINT2 */
+#define ARIZONA_IM_AIF2_ERR_EINT2_SHIFT              13  /* IM_AIF2_ERR_EINT2 */
+#define ARIZONA_IM_AIF2_ERR_EINT2_WIDTH               1  /* IM_AIF2_ERR_EINT2 */
+#define ARIZONA_IM_AIF1_ERR_EINT2                0x1000  /* IM_AIF1_ERR_EINT2 */
+#define ARIZONA_IM_AIF1_ERR_EINT2_MASK           0x1000  /* IM_AIF1_ERR_EINT2 */
+#define ARIZONA_IM_AIF1_ERR_EINT2_SHIFT              12  /* IM_AIF1_ERR_EINT2 */
+#define ARIZONA_IM_AIF1_ERR_EINT2_WIDTH               1  /* IM_AIF1_ERR_EINT2 */
+#define ARIZONA_IM_CTRLIF_ERR_EINT2              0x0800  /* IM_CTRLIF_ERR_EINT2 */
+#define ARIZONA_IM_CTRLIF_ERR_EINT2_MASK         0x0800  /* IM_CTRLIF_ERR_EINT2 */
+#define ARIZONA_IM_CTRLIF_ERR_EINT2_SHIFT            11  /* IM_CTRLIF_ERR_EINT2 */
+#define ARIZONA_IM_CTRLIF_ERR_EINT2_WIDTH             1  /* IM_CTRLIF_ERR_EINT2 */
+#define ARIZONA_IM_MIXER_DROPPED_SAMPLE_EINT2    0x0400  /* IM_MIXER_DROPPED_SAMPLE_EINT2 */
+#define ARIZONA_IM_MIXER_DROPPED_SAMPLE_EINT2_MASK 0x0400  /* IM_MIXER_DROPPED_SAMPLE_EINT2 */
+#define ARIZONA_IM_MIXER_DROPPED_SAMPLE_EINT2_SHIFT     10  /* IM_MIXER_DROPPED_SAMPLE_EINT2 */
+#define ARIZONA_IM_MIXER_DROPPED_SAMPLE_EINT2_WIDTH      1  /* IM_MIXER_DROPPED_SAMPLE_EINT2 */
+#define ARIZONA_IM_ASYNC_CLK_ENA_LOW_EINT2       0x0200  /* IM_ASYNC_CLK_ENA_LOW_EINT2 */
+#define ARIZONA_IM_ASYNC_CLK_ENA_LOW_EINT2_MASK  0x0200  /* IM_ASYNC_CLK_ENA_LOW_EINT2 */
+#define ARIZONA_IM_ASYNC_CLK_ENA_LOW_EINT2_SHIFT      9  /* IM_ASYNC_CLK_ENA_LOW_EINT2 */
+#define ARIZONA_IM_ASYNC_CLK_ENA_LOW_EINT2_WIDTH      1  /* IM_ASYNC_CLK_ENA_LOW_EINT2 */
+#define ARIZONA_IM_SYSCLK_ENA_LOW_EINT2          0x0100  /* IM_SYSCLK_ENA_LOW_EINT2 */
+#define ARIZONA_IM_SYSCLK_ENA_LOW_EINT2_MASK     0x0100  /* IM_SYSCLK_ENA_LOW_EINT2 */
+#define ARIZONA_IM_SYSCLK_ENA_LOW_EINT2_SHIFT         8  /* IM_SYSCLK_ENA_LOW_EINT2 */
+#define ARIZONA_IM_SYSCLK_ENA_LOW_EINT2_WIDTH         1  /* IM_SYSCLK_ENA_LOW_EINT2 */
+#define ARIZONA_IM_ISRC1_CFG_ERR_EINT2           0x0080  /* IM_ISRC1_CFG_ERR_EINT2 */
+#define ARIZONA_IM_ISRC1_CFG_ERR_EINT2_MASK      0x0080  /* IM_ISRC1_CFG_ERR_EINT2 */
+#define ARIZONA_IM_ISRC1_CFG_ERR_EINT2_SHIFT          7  /* IM_ISRC1_CFG_ERR_EINT2 */
+#define ARIZONA_IM_ISRC1_CFG_ERR_EINT2_WIDTH          1  /* IM_ISRC1_CFG_ERR_EINT2 */
+#define ARIZONA_IM_ISRC2_CFG_ERR_EINT2           0x0040  /* IM_ISRC2_CFG_ERR_EINT2 */
+#define ARIZONA_IM_ISRC2_CFG_ERR_EINT2_MASK      0x0040  /* IM_ISRC2_CFG_ERR_EINT2 */
+#define ARIZONA_IM_ISRC2_CFG_ERR_EINT2_SHIFT          6  /* IM_ISRC2_CFG_ERR_EINT2 */
+#define ARIZONA_IM_ISRC2_CFG_ERR_EINT2_WIDTH          1  /* IM_ISRC2_CFG_ERR_EINT2 */
+
+/*
+ * R3356 (0xD1C) - IRQ2 Status 5 Mask
+ */
+
+#define ARIZONA_IM_BOOT_DONE_EINT2               0x0100  /* IM_BOOT_DONE_EINT2 */
+#define ARIZONA_IM_BOOT_DONE_EINT2_MASK          0x0100  /* IM_BOOT_DONE_EINT2 */
+#define ARIZONA_IM_BOOT_DONE_EINT2_SHIFT              8  /* IM_BOOT_DONE_EINT2 */
+#define ARIZONA_IM_BOOT_DONE_EINT2_WIDTH              1  /* IM_BOOT_DONE_EINT2 */
+#define ARIZONA_IM_DCS_DAC_DONE_EINT2            0x0080  /* IM_DCS_DAC_DONE_EINT2 */
+#define ARIZONA_IM_DCS_DAC_DONE_EINT2_MASK       0x0080  /* IM_DCS_DAC_DONE_EINT2 */
+#define ARIZONA_IM_DCS_DAC_DONE_EINT2_SHIFT           7  /* IM_DCS_DAC_DONE_EINT2 */
+#define ARIZONA_IM_DCS_DAC_DONE_EINT2_WIDTH           1  /* IM_DCS_DAC_DONE_EINT2 */
+#define ARIZONA_IM_DCS_HP_DONE_EINT2             0x0040  /* IM_DCS_HP_DONE_EINT2 */
+#define ARIZONA_IM_DCS_HP_DONE_EINT2_MASK        0x0040  /* IM_DCS_HP_DONE_EINT2 */
+#define ARIZONA_IM_DCS_HP_DONE_EINT2_SHIFT            6  /* IM_DCS_HP_DONE_EINT2 */
+#define ARIZONA_IM_DCS_HP_DONE_EINT2_WIDTH            1  /* IM_DCS_HP_DONE_EINT2 */
+#define ARIZONA_IM_FLL2_CLOCK_OK_EINT2           0x0002  /* IM_FLL2_CLOCK_OK_EINT2 */
+#define ARIZONA_IM_FLL2_CLOCK_OK_EINT2_MASK      0x0002  /* IM_FLL2_CLOCK_OK_EINT2 */
+#define ARIZONA_IM_FLL2_CLOCK_OK_EINT2_SHIFT          1  /* IM_FLL2_CLOCK_OK_EINT2 */
+#define ARIZONA_IM_FLL2_CLOCK_OK_EINT2_WIDTH          1  /* IM_FLL2_CLOCK_OK_EINT2 */
+#define ARIZONA_IM_FLL1_CLOCK_OK_EINT2           0x0001  /* IM_FLL1_CLOCK_OK_EINT2 */
+#define ARIZONA_IM_FLL1_CLOCK_OK_EINT2_MASK      0x0001  /* IM_FLL1_CLOCK_OK_EINT2 */
+#define ARIZONA_IM_FLL1_CLOCK_OK_EINT2_SHIFT          0  /* IM_FLL1_CLOCK_OK_EINT2 */
+#define ARIZONA_IM_FLL1_CLOCK_OK_EINT2_WIDTH          1  /* IM_FLL1_CLOCK_OK_EINT2 */
+
+/*
+ * R3359 (0xD1F) - IRQ2 Control
+ */
+#define ARIZONA_IM_IRQ2                          0x0001  /* IM_IRQ2 */
+#define ARIZONA_IM_IRQ2_MASK                     0x0001  /* IM_IRQ2 */
+#define ARIZONA_IM_IRQ2_SHIFT                         0  /* IM_IRQ2 */
+#define ARIZONA_IM_IRQ2_WIDTH                         1  /* IM_IRQ2 */
+
+/*
+ * R3360 (0xD20) - Interrupt Raw Status 2
+ */
+#define ARIZONA_DSP1_RAM_RDY_STS                 0x0100  /* DSP1_RAM_RDY_STS */
+#define ARIZONA_DSP1_RAM_RDY_STS_MASK            0x0100  /* DSP1_RAM_RDY_STS */
+#define ARIZONA_DSP1_RAM_RDY_STS_SHIFT                8  /* DSP1_RAM_RDY_STS */
+#define ARIZONA_DSP1_RAM_RDY_STS_WIDTH                1  /* DSP1_RAM_RDY_STS */
+#define ARIZONA_DSP_IRQ2_STS                     0x0002  /* DSP_IRQ2_STS */
+#define ARIZONA_DSP_IRQ2_STS_MASK                0x0002  /* DSP_IRQ2_STS */
+#define ARIZONA_DSP_IRQ2_STS_SHIFT                    1  /* DSP_IRQ2_STS */
+#define ARIZONA_DSP_IRQ2_STS_WIDTH                    1  /* DSP_IRQ2_STS */
+#define ARIZONA_DSP_IRQ1_STS                     0x0001  /* DSP_IRQ1_STS */
+#define ARIZONA_DSP_IRQ1_STS_MASK                0x0001  /* DSP_IRQ1_STS */
+#define ARIZONA_DSP_IRQ1_STS_SHIFT                    0  /* DSP_IRQ1_STS */
+#define ARIZONA_DSP_IRQ1_STS_WIDTH                    1  /* DSP_IRQ1_STS */
+
+/*
+ * R3361 (0xD21) - Interrupt Raw Status 3
+ */
+#define ARIZONA_SPK_SHUTDOWN_WARN_STS            0x8000  /* SPK_SHUTDOWN_WARN_STS */
+#define ARIZONA_SPK_SHUTDOWN_WARN_STS_MASK       0x8000  /* SPK_SHUTDOWN_WARN_STS */
+#define ARIZONA_SPK_SHUTDOWN_WARN_STS_SHIFT          15  /* SPK_SHUTDOWN_WARN_STS */
+#define ARIZONA_SPK_SHUTDOWN_WARN_STS_WIDTH           1  /* SPK_SHUTDOWN_WARN_STS */
+#define ARIZONA_SPK_SHUTDOWN_STS                 0x4000  /* SPK_SHUTDOWN_STS */
+#define ARIZONA_SPK_SHUTDOWN_STS_MASK            0x4000  /* SPK_SHUTDOWN_STS */
+#define ARIZONA_SPK_SHUTDOWN_STS_SHIFT               14  /* SPK_SHUTDOWN_STS */
+#define ARIZONA_SPK_SHUTDOWN_STS_WIDTH                1  /* SPK_SHUTDOWN_STS */
+#define ARIZONA_HPDET_STS                        0x2000  /* HPDET_STS */
+#define ARIZONA_HPDET_STS_MASK                   0x2000  /* HPDET_STS */
+#define ARIZONA_HPDET_STS_SHIFT                      13  /* HPDET_STS */
+#define ARIZONA_HPDET_STS_WIDTH                       1  /* HPDET_STS */
+#define ARIZONA_MICDET_STS                       0x1000  /* MICDET_STS */
+#define ARIZONA_MICDET_STS_MASK                  0x1000  /* MICDET_STS */
+#define ARIZONA_MICDET_STS_SHIFT                     12  /* MICDET_STS */
+#define ARIZONA_MICDET_STS_WIDTH                      1  /* MICDET_STS */
+#define ARIZONA_WSEQ_DONE_STS                    0x0800  /* WSEQ_DONE_STS */
+#define ARIZONA_WSEQ_DONE_STS_MASK               0x0800  /* WSEQ_DONE_STS */
+#define ARIZONA_WSEQ_DONE_STS_SHIFT                  11  /* WSEQ_DONE_STS */
+#define ARIZONA_WSEQ_DONE_STS_WIDTH                   1  /* WSEQ_DONE_STS */
+#define ARIZONA_DRC2_SIG_DET_STS                 0x0400  /* DRC2_SIG_DET_STS */
+#define ARIZONA_DRC2_SIG_DET_STS_MASK            0x0400  /* DRC2_SIG_DET_STS */
+#define ARIZONA_DRC2_SIG_DET_STS_SHIFT               10  /* DRC2_SIG_DET_STS */
+#define ARIZONA_DRC2_SIG_DET_STS_WIDTH                1  /* DRC2_SIG_DET_STS */
+#define ARIZONA_DRC1_SIG_DET_STS                 0x0200  /* DRC1_SIG_DET_STS */
+#define ARIZONA_DRC1_SIG_DET_STS_MASK            0x0200  /* DRC1_SIG_DET_STS */
+#define ARIZONA_DRC1_SIG_DET_STS_SHIFT                9  /* DRC1_SIG_DET_STS */
+#define ARIZONA_DRC1_SIG_DET_STS_WIDTH                1  /* DRC1_SIG_DET_STS */
+#define ARIZONA_ASRC2_LOCK_STS                   0x0100  /* ASRC2_LOCK_STS */
+#define ARIZONA_ASRC2_LOCK_STS_MASK              0x0100  /* ASRC2_LOCK_STS */
+#define ARIZONA_ASRC2_LOCK_STS_SHIFT                  8  /* ASRC2_LOCK_STS */
+#define ARIZONA_ASRC2_LOCK_STS_WIDTH                  1  /* ASRC2_LOCK_STS */
+#define ARIZONA_ASRC1_LOCK_STS                   0x0080  /* ASRC1_LOCK_STS */
+#define ARIZONA_ASRC1_LOCK_STS_MASK              0x0080  /* ASRC1_LOCK_STS */
+#define ARIZONA_ASRC1_LOCK_STS_SHIFT                  7  /* ASRC1_LOCK_STS */
+#define ARIZONA_ASRC1_LOCK_STS_WIDTH                  1  /* ASRC1_LOCK_STS */
+#define ARIZONA_UNDERCLOCKED_STS                 0x0040  /* UNDERCLOCKED_STS */
+#define ARIZONA_UNDERCLOCKED_STS_MASK            0x0040  /* UNDERCLOCKED_STS */
+#define ARIZONA_UNDERCLOCKED_STS_SHIFT                6  /* UNDERCLOCKED_STS */
+#define ARIZONA_UNDERCLOCKED_STS_WIDTH                1  /* UNDERCLOCKED_STS */
+#define ARIZONA_OVERCLOCKED_STS                  0x0020  /* OVERCLOCKED_STS */
+#define ARIZONA_OVERCLOCKED_STS_MASK             0x0020  /* OVERCLOCKED_STS */
+#define ARIZONA_OVERCLOCKED_STS_SHIFT                 5  /* OVERCLOCKED_STS */
+#define ARIZONA_OVERCLOCKED_STS_WIDTH                 1  /* OVERCLOCKED_STS */
+#define ARIZONA_FLL2_LOCK_STS                    0x0008  /* FLL2_LOCK_STS */
+#define ARIZONA_FLL2_LOCK_STS_MASK               0x0008  /* FLL2_LOCK_STS */
+#define ARIZONA_FLL2_LOCK_STS_SHIFT                   3  /* FLL2_LOCK_STS */
+#define ARIZONA_FLL2_LOCK_STS_WIDTH                   1  /* FLL2_LOCK_STS */
+#define ARIZONA_FLL1_LOCK_STS                    0x0004  /* FLL1_LOCK_STS */
+#define ARIZONA_FLL1_LOCK_STS_MASK               0x0004  /* FLL1_LOCK_STS */
+#define ARIZONA_FLL1_LOCK_STS_SHIFT                   2  /* FLL1_LOCK_STS */
+#define ARIZONA_FLL1_LOCK_STS_WIDTH                   1  /* FLL1_LOCK_STS */
+#define ARIZONA_CLKGEN_ERR_STS                   0x0002  /* CLKGEN_ERR_STS */
+#define ARIZONA_CLKGEN_ERR_STS_MASK              0x0002  /* CLKGEN_ERR_STS */
+#define ARIZONA_CLKGEN_ERR_STS_SHIFT                  1  /* CLKGEN_ERR_STS */
+#define ARIZONA_CLKGEN_ERR_STS_WIDTH                  1  /* CLKGEN_ERR_STS */
+#define ARIZONA_CLKGEN_ERR_ASYNC_STS             0x0001  /* CLKGEN_ERR_ASYNC_STS */
+#define ARIZONA_CLKGEN_ERR_ASYNC_STS_MASK        0x0001  /* CLKGEN_ERR_ASYNC_STS */
+#define ARIZONA_CLKGEN_ERR_ASYNC_STS_SHIFT            0  /* CLKGEN_ERR_ASYNC_STS */
+#define ARIZONA_CLKGEN_ERR_ASYNC_STS_WIDTH            1  /* CLKGEN_ERR_ASYNC_STS */
+
+/*
+ * R3362 (0xD22) - Interrupt Raw Status 4
+ */
+#define ARIZONA_ASRC_CFG_ERR_STS                 0x8000  /* ASRC_CFG_ERR_STS */
+#define ARIZONA_ASRC_CFG_ERR_STS_MASK            0x8000  /* ASRC_CFG_ERR_STS */
+#define ARIZONA_ASRC_CFG_ERR_STS_SHIFT               15  /* ASRC_CFG_ERR_STS */
+#define ARIZONA_ASRC_CFG_ERR_STS_WIDTH                1  /* ASRC_CFG_ERR_STS */
+#define ARIZONA_AIF3_ERR_STS                     0x4000  /* AIF3_ERR_STS */
+#define ARIZONA_AIF3_ERR_STS_MASK                0x4000  /* AIF3_ERR_STS */
+#define ARIZONA_AIF3_ERR_STS_SHIFT                   14  /* AIF3_ERR_STS */
+#define ARIZONA_AIF3_ERR_STS_WIDTH                    1  /* AIF3_ERR_STS */
+#define ARIZONA_AIF2_ERR_STS                     0x2000  /* AIF2_ERR_STS */
+#define ARIZONA_AIF2_ERR_STS_MASK                0x2000  /* AIF2_ERR_STS */
+#define ARIZONA_AIF2_ERR_STS_SHIFT                   13  /* AIF2_ERR_STS */
+#define ARIZONA_AIF2_ERR_STS_WIDTH                    1  /* AIF2_ERR_STS */
+#define ARIZONA_AIF1_ERR_STS                     0x1000  /* AIF1_ERR_STS */
+#define ARIZONA_AIF1_ERR_STS_MASK                0x1000  /* AIF1_ERR_STS */
+#define ARIZONA_AIF1_ERR_STS_SHIFT                   12  /* AIF1_ERR_STS */
+#define ARIZONA_AIF1_ERR_STS_WIDTH                    1  /* AIF1_ERR_STS */
+#define ARIZONA_CTRLIF_ERR_STS                   0x0800  /* CTRLIF_ERR_STS */
+#define ARIZONA_CTRLIF_ERR_STS_MASK              0x0800  /* CTRLIF_ERR_STS */
+#define ARIZONA_CTRLIF_ERR_STS_SHIFT                 11  /* CTRLIF_ERR_STS */
+#define ARIZONA_CTRLIF_ERR_STS_WIDTH                  1  /* CTRLIF_ERR_STS */
+#define ARIZONA_MIXER_DROPPED_SAMPLE_STS         0x0400  /* MIXER_DROPPED_SAMPLE_STS */
+#define ARIZONA_MIXER_DROPPED_SAMPLE_STS_MASK    0x0400  /* MIXER_DROPPED_SAMPLE_STS */
+#define ARIZONA_MIXER_DROPPED_SAMPLE_STS_SHIFT       10  /* MIXER_DROPPED_SAMPLE_STS */
+#define ARIZONA_MIXER_DROPPED_SAMPLE_STS_WIDTH        1  /* MIXER_DROPPED_SAMPLE_STS */
+#define ARIZONA_ASYNC_CLK_ENA_LOW_STS            0x0200  /* ASYNC_CLK_ENA_LOW_STS */
+#define ARIZONA_ASYNC_CLK_ENA_LOW_STS_MASK       0x0200  /* ASYNC_CLK_ENA_LOW_STS */
+#define ARIZONA_ASYNC_CLK_ENA_LOW_STS_SHIFT           9  /* ASYNC_CLK_ENA_LOW_STS */
+#define ARIZONA_ASYNC_CLK_ENA_LOW_STS_WIDTH           1  /* ASYNC_CLK_ENA_LOW_STS */
+#define ARIZONA_SYSCLK_ENA_LOW_STS               0x0100  /* SYSCLK_ENA_LOW_STS */
+#define ARIZONA_SYSCLK_ENA_LOW_STS_MASK          0x0100  /* SYSCLK_ENA_LOW_STS */
+#define ARIZONA_SYSCLK_ENA_LOW_STS_SHIFT              8  /* SYSCLK_ENA_LOW_STS */
+#define ARIZONA_SYSCLK_ENA_LOW_STS_WIDTH              1  /* SYSCLK_ENA_LOW_STS */
+#define ARIZONA_ISRC1_CFG_ERR_STS                0x0080  /* ISRC1_CFG_ERR_STS */
+#define ARIZONA_ISRC1_CFG_ERR_STS_MASK           0x0080  /* ISRC1_CFG_ERR_STS */
+#define ARIZONA_ISRC1_CFG_ERR_STS_SHIFT               7  /* ISRC1_CFG_ERR_STS */
+#define ARIZONA_ISRC1_CFG_ERR_STS_WIDTH               1  /* ISRC1_CFG_ERR_STS */
+#define ARIZONA_ISRC2_CFG_ERR_STS                0x0040  /* ISRC2_CFG_ERR_STS */
+#define ARIZONA_ISRC2_CFG_ERR_STS_MASK           0x0040  /* ISRC2_CFG_ERR_STS */
+#define ARIZONA_ISRC2_CFG_ERR_STS_SHIFT               6  /* ISRC2_CFG_ERR_STS */
+#define ARIZONA_ISRC2_CFG_ERR_STS_WIDTH               1  /* ISRC2_CFG_ERR_STS */
+
+/*
+ * R3363 (0xD23) - Interrupt Raw Status 5
+ */
+#define ARIZONA_BOOT_DONE_STS                    0x0100  /* BOOT_DONE_STS */
+#define ARIZONA_BOOT_DONE_STS_MASK               0x0100  /* BOOT_DONE_STS */
+#define ARIZONA_BOOT_DONE_STS_SHIFT                   8  /* BOOT_DONE_STS */
+#define ARIZONA_BOOT_DONE_STS_WIDTH                   1  /* BOOT_DONE_STS */
+#define ARIZONA_DCS_DAC_DONE_STS                 0x0080  /* DCS_DAC_DONE_STS */
+#define ARIZONA_DCS_DAC_DONE_STS_MASK            0x0080  /* DCS_DAC_DONE_STS */
+#define ARIZONA_DCS_DAC_DONE_STS_SHIFT                7  /* DCS_DAC_DONE_STS */
+#define ARIZONA_DCS_DAC_DONE_STS_WIDTH                1  /* DCS_DAC_DONE_STS */
+#define ARIZONA_DCS_HP_DONE_STS                  0x0040  /* DCS_HP_DONE_STS */
+#define ARIZONA_DCS_HP_DONE_STS_MASK             0x0040  /* DCS_HP_DONE_STS */
+#define ARIZONA_DCS_HP_DONE_STS_SHIFT                 6  /* DCS_HP_DONE_STS */
+#define ARIZONA_DCS_HP_DONE_STS_WIDTH                 1  /* DCS_HP_DONE_STS */
+#define ARIZONA_FLL2_CLOCK_OK_STS                0x0002  /* FLL2_CLOCK_OK_STS */
+#define ARIZONA_FLL2_CLOCK_OK_STS_MASK           0x0002  /* FLL2_CLOCK_OK_STS */
+#define ARIZONA_FLL2_CLOCK_OK_STS_SHIFT               1  /* FLL2_CLOCK_OK_STS */
+#define ARIZONA_FLL2_CLOCK_OK_STS_WIDTH               1  /* FLL2_CLOCK_OK_STS */
+#define ARIZONA_FLL1_CLOCK_OK_STS                0x0001  /* FLL1_CLOCK_OK_STS */
+#define ARIZONA_FLL1_CLOCK_OK_STS_MASK           0x0001  /* FLL1_CLOCK_OK_STS */
+#define ARIZONA_FLL1_CLOCK_OK_STS_SHIFT               0  /* FLL1_CLOCK_OK_STS */
+#define ARIZONA_FLL1_CLOCK_OK_STS_WIDTH               1  /* FLL1_CLOCK_OK_STS */
+
+/*
+ * R3364 (0xD24) - Interrupt Raw Status 6
+ */
+#define ARIZONA_PWM_OVERCLOCKED_STS              0x2000  /* PWM_OVERCLOCKED_STS */
+#define ARIZONA_PWM_OVERCLOCKED_STS_MASK         0x2000  /* PWM_OVERCLOCKED_STS */
+#define ARIZONA_PWM_OVERCLOCKED_STS_SHIFT            13  /* PWM_OVERCLOCKED_STS */
+#define ARIZONA_PWM_OVERCLOCKED_STS_WIDTH             1  /* PWM_OVERCLOCKED_STS */
+#define ARIZONA_FX_CORE_OVERCLOCKED_STS          0x1000  /* FX_CORE_OVERCLOCKED_STS */
+#define ARIZONA_FX_CORE_OVERCLOCKED_STS_MASK     0x1000  /* FX_CORE_OVERCLOCKED_STS */
+#define ARIZONA_FX_CORE_OVERCLOCKED_STS_SHIFT        12  /* FX_CORE_OVERCLOCKED_STS */
+#define ARIZONA_FX_CORE_OVERCLOCKED_STS_WIDTH         1  /* FX_CORE_OVERCLOCKED_STS */
+#define ARIZONA_DAC_SYS_OVERCLOCKED_STS          0x0400  /* DAC_SYS_OVERCLOCKED_STS */
+#define ARIZONA_DAC_SYS_OVERCLOCKED_STS_MASK     0x0400  /* DAC_SYS_OVERCLOCKED_STS */
+#define ARIZONA_DAC_SYS_OVERCLOCKED_STS_SHIFT        10  /* DAC_SYS_OVERCLOCKED_STS */
+#define ARIZONA_DAC_SYS_OVERCLOCKED_STS_WIDTH         1  /* DAC_SYS_OVERCLOCKED_STS */
+#define ARIZONA_DAC_WARP_OVERCLOCKED_STS         0x0200  /* DAC_WARP_OVERCLOCKED_STS */
+#define ARIZONA_DAC_WARP_OVERCLOCKED_STS_MASK    0x0200  /* DAC_WARP_OVERCLOCKED_STS */
+#define ARIZONA_DAC_WARP_OVERCLOCKED_STS_SHIFT        9  /* DAC_WARP_OVERCLOCKED_STS */
+#define ARIZONA_DAC_WARP_OVERCLOCKED_STS_WIDTH        1  /* DAC_WARP_OVERCLOCKED_STS */
+#define ARIZONA_ADC_OVERCLOCKED_STS              0x0100  /* ADC_OVERCLOCKED_STS */
+#define ARIZONA_ADC_OVERCLOCKED_STS_MASK         0x0100  /* ADC_OVERCLOCKED_STS */
+#define ARIZONA_ADC_OVERCLOCKED_STS_SHIFT             8  /* ADC_OVERCLOCKED_STS */
+#define ARIZONA_ADC_OVERCLOCKED_STS_WIDTH             1  /* ADC_OVERCLOCKED_STS */
+#define ARIZONA_MIXER_OVERCLOCKED_STS            0x0080  /* MIXER_OVERCLOCKED_STS */
+#define ARIZONA_MIXER_OVERCLOCKED_STS_MASK       0x0080  /* MIXER_OVERCLOCKED_STS */
+#define ARIZONA_MIXER_OVERCLOCKED_STS_SHIFT           7  /* MIXER_OVERCLOCKED_STS */
+#define ARIZONA_MIXER_OVERCLOCKED_STS_WIDTH           1  /* MIXER_OVERCLOCKED_STS */
+#define ARIZONA_AIF3_ASYNC_OVERCLOCKED_STS       0x0040  /* AIF3_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF3_ASYNC_OVERCLOCKED_STS_MASK  0x0040  /* AIF3_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF3_ASYNC_OVERCLOCKED_STS_SHIFT      6  /* AIF3_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF3_ASYNC_OVERCLOCKED_STS_WIDTH      1  /* AIF3_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF2_ASYNC_OVERCLOCKED_STS       0x0020  /* AIF2_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF2_ASYNC_OVERCLOCKED_STS_MASK  0x0020  /* AIF2_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF2_ASYNC_OVERCLOCKED_STS_SHIFT      5  /* AIF2_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF2_ASYNC_OVERCLOCKED_STS_WIDTH      1  /* AIF2_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF1_ASYNC_OVERCLOCKED_STS       0x0010  /* AIF1_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF1_ASYNC_OVERCLOCKED_STS_MASK  0x0010  /* AIF1_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF1_ASYNC_OVERCLOCKED_STS_SHIFT      4  /* AIF1_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF1_ASYNC_OVERCLOCKED_STS_WIDTH      1  /* AIF1_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF3_SYNC_OVERCLOCKED_STS        0x0008  /* AIF3_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF3_SYNC_OVERCLOCKED_STS_MASK   0x0008  /* AIF3_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF3_SYNC_OVERCLOCKED_STS_SHIFT       3  /* AIF3_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF3_SYNC_OVERCLOCKED_STS_WIDTH       1  /* AIF3_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF2_SYNC_OVERCLOCKED_STS        0x0004  /* AIF2_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF2_SYNC_OVERCLOCKED_STS_MASK   0x0004  /* AIF2_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF2_SYNC_OVERCLOCKED_STS_SHIFT       2  /* AIF2_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF2_SYNC_OVERCLOCKED_STS_WIDTH       1  /* AIF2_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF1_SYNC_OVERCLOCKED_STS        0x0002  /* AIF1_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF1_SYNC_OVERCLOCKED_STS_MASK   0x0002  /* AIF1_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF1_SYNC_OVERCLOCKED_STS_SHIFT       1  /* AIF1_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_AIF1_SYNC_OVERCLOCKED_STS_WIDTH       1  /* AIF1_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_PAD_CTRL_OVERCLOCKED_STS         0x0001  /* PAD_CTRL_OVERCLOCKED_STS */
+#define ARIZONA_PAD_CTRL_OVERCLOCKED_STS_MASK    0x0001  /* PAD_CTRL_OVERCLOCKED_STS */
+#define ARIZONA_PAD_CTRL_OVERCLOCKED_STS_SHIFT        0  /* PAD_CTRL_OVERCLOCKED_STS */
+#define ARIZONA_PAD_CTRL_OVERCLOCKED_STS_WIDTH        1  /* PAD_CTRL_OVERCLOCKED_STS */
+
+/*
+ * R3365 (0xD25) - Interrupt Raw Status 7
+ */
+#define ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS   0x8000  /* SLIMBUS_SUBSYS_OVERCLOCKED_STS */
+#define ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS_MASK 0x8000  /* SLIMBUS_SUBSYS_OVERCLOCKED_STS */
+#define ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS_SHIFT     15  /* SLIMBUS_SUBSYS_OVERCLOCKED_STS */
+#define ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS_WIDTH      1  /* SLIMBUS_SUBSYS_OVERCLOCKED_STS */
+#define ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS    0x4000  /* SLIMBUS_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS_MASK 0x4000  /* SLIMBUS_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS_SHIFT     14  /* SLIMBUS_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS_WIDTH      1  /* SLIMBUS_ASYNC_OVERCLOCKED_STS */
+#define ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS     0x2000  /* SLIMBUS_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS_MASK 0x2000  /* SLIMBUS_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS_SHIFT     13  /* SLIMBUS_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS_WIDTH      1  /* SLIMBUS_SYNC_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS   0x1000  /* ASRC_ASYNC_SYS_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS_MASK 0x1000  /* ASRC_ASYNC_SYS_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS_SHIFT     12  /* ASRC_ASYNC_SYS_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS_WIDTH      1  /* ASRC_ASYNC_SYS_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS  0x0800  /* ASRC_ASYNC_WARP_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS_MASK 0x0800  /* ASRC_ASYNC_WARP_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS_SHIFT     11  /* ASRC_ASYNC_WARP_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS_WIDTH      1  /* ASRC_ASYNC_WARP_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS    0x0400  /* ASRC_SYNC_SYS_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS_MASK 0x0400  /* ASRC_SYNC_SYS_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS_SHIFT     10  /* ASRC_SYNC_SYS_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS_WIDTH      1  /* ASRC_SYNC_SYS_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS   0x0200  /* ASRC_SYNC_WARP_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS_MASK 0x0200  /* ASRC_SYNC_WARP_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS_SHIFT      9  /* ASRC_SYNC_WARP_OVERCLOCKED_STS */
+#define ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS_WIDTH      1  /* ASRC_SYNC_WARP_OVERCLOCKED_STS */
+#define ARIZONA_ADSP2_1_OVERCLOCKED_STS          0x0008  /* ADSP2_1_OVERCLOCKED_STS */
+#define ARIZONA_ADSP2_1_OVERCLOCKED_STS_MASK     0x0008  /* ADSP2_1_OVERCLOCKED_STS */
+#define ARIZONA_ADSP2_1_OVERCLOCKED_STS_SHIFT         3  /* ADSP2_1_OVERCLOCKED_STS */
+#define ARIZONA_ADSP2_1_OVERCLOCKED_STS_WIDTH         1  /* ADSP2_1_OVERCLOCKED_STS */
+#define ARIZONA_ISRC2_OVERCLOCKED_STS            0x0002  /* ISRC2_OVERCLOCKED_STS */
+#define ARIZONA_ISRC2_OVERCLOCKED_STS_MASK       0x0002  /* ISRC2_OVERCLOCKED_STS */
+#define ARIZONA_ISRC2_OVERCLOCKED_STS_SHIFT           1  /* ISRC2_OVERCLOCKED_STS */
+#define ARIZONA_ISRC2_OVERCLOCKED_STS_WIDTH           1  /* ISRC2_OVERCLOCKED_STS */
+#define ARIZONA_ISRC1_OVERCLOCKED_STS            0x0001  /* ISRC1_OVERCLOCKED_STS */
+#define ARIZONA_ISRC1_OVERCLOCKED_STS_MASK       0x0001  /* ISRC1_OVERCLOCKED_STS */
+#define ARIZONA_ISRC1_OVERCLOCKED_STS_SHIFT           0  /* ISRC1_OVERCLOCKED_STS */
+#define ARIZONA_ISRC1_OVERCLOCKED_STS_WIDTH           1  /* ISRC1_OVERCLOCKED_STS */
+
+/*
+ * R3366 (0xD26) - Interrupt Raw Status 8
+ */
+#define ARIZONA_AIF3_UNDERCLOCKED_STS            0x0400  /* AIF3_UNDERCLOCKED_STS */
+#define ARIZONA_AIF3_UNDERCLOCKED_STS_MASK       0x0400  /* AIF3_UNDERCLOCKED_STS */
+#define ARIZONA_AIF3_UNDERCLOCKED_STS_SHIFT          10  /* AIF3_UNDERCLOCKED_STS */
+#define ARIZONA_AIF3_UNDERCLOCKED_STS_WIDTH           1  /* AIF3_UNDERCLOCKED_STS */
+#define ARIZONA_AIF2_UNDERCLOCKED_STS            0x0200  /* AIF2_UNDERCLOCKED_STS */
+#define ARIZONA_AIF2_UNDERCLOCKED_STS_MASK       0x0200  /* AIF2_UNDERCLOCKED_STS */
+#define ARIZONA_AIF2_UNDERCLOCKED_STS_SHIFT           9  /* AIF2_UNDERCLOCKED_STS */
+#define ARIZONA_AIF2_UNDERCLOCKED_STS_WIDTH           1  /* AIF2_UNDERCLOCKED_STS */
+#define ARIZONA_AIF1_UNDERCLOCKED_STS            0x0100  /* AIF1_UNDERCLOCKED_STS */
+#define ARIZONA_AIF1_UNDERCLOCKED_STS_MASK       0x0100  /* AIF1_UNDERCLOCKED_STS */
+#define ARIZONA_AIF1_UNDERCLOCKED_STS_SHIFT           8  /* AIF1_UNDERCLOCKED_STS */
+#define ARIZONA_AIF1_UNDERCLOCKED_STS_WIDTH           1  /* AIF1_UNDERCLOCKED_STS */
+#define ARIZONA_ISRC2_UNDERCLOCKED_STS           0x0040  /* ISRC2_UNDERCLOCKED_STS */
+#define ARIZONA_ISRC2_UNDERCLOCKED_STS_MASK      0x0040  /* ISRC2_UNDERCLOCKED_STS */
+#define ARIZONA_ISRC2_UNDERCLOCKED_STS_SHIFT          6  /* ISRC2_UNDERCLOCKED_STS */
+#define ARIZONA_ISRC2_UNDERCLOCKED_STS_WIDTH          1  /* ISRC2_UNDERCLOCKED_STS */
+#define ARIZONA_ISRC1_UNDERCLOCKED_STS           0x0020  /* ISRC1_UNDERCLOCKED_STS */
+#define ARIZONA_ISRC1_UNDERCLOCKED_STS_MASK      0x0020  /* ISRC1_UNDERCLOCKED_STS */
+#define ARIZONA_ISRC1_UNDERCLOCKED_STS_SHIFT          5  /* ISRC1_UNDERCLOCKED_STS */
+#define ARIZONA_ISRC1_UNDERCLOCKED_STS_WIDTH          1  /* ISRC1_UNDERCLOCKED_STS */
+#define ARIZONA_FX_UNDERCLOCKED_STS              0x0010  /* FX_UNDERCLOCKED_STS */
+#define ARIZONA_FX_UNDERCLOCKED_STS_MASK         0x0010  /* FX_UNDERCLOCKED_STS */
+#define ARIZONA_FX_UNDERCLOCKED_STS_SHIFT             4  /* FX_UNDERCLOCKED_STS */
+#define ARIZONA_FX_UNDERCLOCKED_STS_WIDTH             1  /* FX_UNDERCLOCKED_STS */
+#define ARIZONA_ASRC_UNDERCLOCKED_STS            0x0008  /* ASRC_UNDERCLOCKED_STS */
+#define ARIZONA_ASRC_UNDERCLOCKED_STS_MASK       0x0008  /* ASRC_UNDERCLOCKED_STS */
+#define ARIZONA_ASRC_UNDERCLOCKED_STS_SHIFT           3  /* ASRC_UNDERCLOCKED_STS */
+#define ARIZONA_ASRC_UNDERCLOCKED_STS_WIDTH           1  /* ASRC_UNDERCLOCKED_STS */
+#define ARIZONA_DAC_UNDERCLOCKED_STS             0x0004  /* DAC_UNDERCLOCKED_STS */
+#define ARIZONA_DAC_UNDERCLOCKED_STS_MASK        0x0004  /* DAC_UNDERCLOCKED_STS */
+#define ARIZONA_DAC_UNDERCLOCKED_STS_SHIFT            2  /* DAC_UNDERCLOCKED_STS */
+#define ARIZONA_DAC_UNDERCLOCKED_STS_WIDTH            1  /* DAC_UNDERCLOCKED_STS */
+#define ARIZONA_ADC_UNDERCLOCKED_STS             0x0002  /* ADC_UNDERCLOCKED_STS */
+#define ARIZONA_ADC_UNDERCLOCKED_STS_MASK        0x0002  /* ADC_UNDERCLOCKED_STS */
+#define ARIZONA_ADC_UNDERCLOCKED_STS_SHIFT            1  /* ADC_UNDERCLOCKED_STS */
+#define ARIZONA_ADC_UNDERCLOCKED_STS_WIDTH            1  /* ADC_UNDERCLOCKED_STS */
+#define ARIZONA_MIXER_UNDERCLOCKED_STS           0x0001  /* MIXER_UNDERCLOCKED_STS */
+#define ARIZONA_MIXER_UNDERCLOCKED_STS_MASK      0x0001  /* MIXER_UNDERCLOCKED_STS */
+#define ARIZONA_MIXER_UNDERCLOCKED_STS_SHIFT          0  /* MIXER_UNDERCLOCKED_STS */
+#define ARIZONA_MIXER_UNDERCLOCKED_STS_WIDTH          1  /* MIXER_UNDERCLOCKED_STS */
+
+/*
+ * R3392 (0xD40) - IRQ Pin Status
+ */
+#define ARIZONA_IRQ2_STS                         0x0002  /* IRQ2_STS */
+#define ARIZONA_IRQ2_STS_MASK                    0x0002  /* IRQ2_STS */
+#define ARIZONA_IRQ2_STS_SHIFT                        1  /* IRQ2_STS */
+#define ARIZONA_IRQ2_STS_WIDTH                        1  /* IRQ2_STS */
+#define ARIZONA_IRQ1_STS                         0x0001  /* IRQ1_STS */
+#define ARIZONA_IRQ1_STS_MASK                    0x0001  /* IRQ1_STS */
+#define ARIZONA_IRQ1_STS_SHIFT                        0  /* IRQ1_STS */
+#define ARIZONA_IRQ1_STS_WIDTH                        1  /* IRQ1_STS */
+
+/*
+ * R3393 (0xD41) - ADSP2 IRQ0
+ */
+#define ARIZONA_DSP_IRQ2                         0x0002  /* DSP_IRQ2 */
+#define ARIZONA_DSP_IRQ2_MASK                    0x0002  /* DSP_IRQ2 */
+#define ARIZONA_DSP_IRQ2_SHIFT                        1  /* DSP_IRQ2 */
+#define ARIZONA_DSP_IRQ2_WIDTH                        1  /* DSP_IRQ2 */
+#define ARIZONA_DSP_IRQ1                         0x0001  /* DSP_IRQ1 */
+#define ARIZONA_DSP_IRQ1_MASK                    0x0001  /* DSP_IRQ1 */
+#define ARIZONA_DSP_IRQ1_SHIFT                        0  /* DSP_IRQ1 */
+#define ARIZONA_DSP_IRQ1_WIDTH                        1  /* DSP_IRQ1 */
+
+/*
+ * R3408 (0xD50) - AOD wkup and trig
+ */
+#define ARIZONA_GP5_FALL_TRIG_STS                0x0020  /* GP5_FALL_TRIG_STS */
+#define ARIZONA_GP5_FALL_TRIG_STS_MASK           0x0020  /* GP5_FALL_TRIG_STS */
+#define ARIZONA_GP5_FALL_TRIG_STS_SHIFT               5  /* GP5_FALL_TRIG_STS */
+#define ARIZONA_GP5_FALL_TRIG_STS_WIDTH               1  /* GP5_FALL_TRIG_STS */
+#define ARIZONA_GP5_RISE_TRIG_STS                0x0010  /* GP5_RISE_TRIG_STS */
+#define ARIZONA_GP5_RISE_TRIG_STS_MASK           0x0010  /* GP5_RISE_TRIG_STS */
+#define ARIZONA_GP5_RISE_TRIG_STS_SHIFT               4  /* GP5_RISE_TRIG_STS */
+#define ARIZONA_GP5_RISE_TRIG_STS_WIDTH               1  /* GP5_RISE_TRIG_STS */
+#define ARIZONA_JD1_FALL_TRIG_STS                0x0008  /* JD1_FALL_TRIG_STS */
+#define ARIZONA_JD1_FALL_TRIG_STS_MASK           0x0008  /* JD1_FALL_TRIG_STS */
+#define ARIZONA_JD1_FALL_TRIG_STS_SHIFT               3  /* JD1_FALL_TRIG_STS */
+#define ARIZONA_JD1_FALL_TRIG_STS_WIDTH               1  /* JD1_FALL_TRIG_STS */
+#define ARIZONA_JD1_RISE_TRIG_STS                0x0004  /* JD1_RISE_TRIG_STS */
+#define ARIZONA_JD1_RISE_TRIG_STS_MASK           0x0004  /* JD1_RISE_TRIG_STS */
+#define ARIZONA_JD1_RISE_TRIG_STS_SHIFT               2  /* JD1_RISE_TRIG_STS */
+#define ARIZONA_JD1_RISE_TRIG_STS_WIDTH               1  /* JD1_RISE_TRIG_STS */
+#define ARIZONA_JD2_FALL_TRIG_STS                0x0002  /* JD2_FALL_TRIG_STS */
+#define ARIZONA_JD2_FALL_TRIG_STS_MASK           0x0002  /* JD2_FALL_TRIG_STS */
+#define ARIZONA_JD2_FALL_TRIG_STS_SHIFT               1  /* JD2_FALL_TRIG_STS */
+#define ARIZONA_JD2_FALL_TRIG_STS_WIDTH               1  /* JD2_FALL_TRIG_STS */
+#define ARIZONA_JD2_RISE_TRIG_STS                0x0001  /* JD2_RISE_TRIG_STS */
+#define ARIZONA_JD2_RISE_TRIG_STS_MASK           0x0001  /* JD2_RISE_TRIG_STS */
+#define ARIZONA_JD2_RISE_TRIG_STS_SHIFT               0  /* JD2_RISE_TRIG_STS */
+#define ARIZONA_JD2_RISE_TRIG_STS_WIDTH               1  /* JD2_RISE_TRIG_STS */
+
+/*
+ * R3409 (0xD51) - AOD IRQ1
+ */
+#define ARIZONA_GP5_FALL_EINT1                   0x0020  /* GP5_FALL_EINT1 */
+#define ARIZONA_GP5_FALL_EINT1_MASK              0x0020  /* GP5_FALL_EINT1 */
+#define ARIZONA_GP5_FALL_EINT1_SHIFT                  5  /* GP5_FALL_EINT1 */
+#define ARIZONA_GP5_FALL_EINT1_WIDTH                  1  /* GP5_FALL_EINT1 */
+#define ARIZONA_GP5_RISE_EINT1                   0x0010  /* GP5_RISE_EINT1 */
+#define ARIZONA_GP5_RISE_EINT1_MASK              0x0010  /* GP5_RISE_EINT1 */
+#define ARIZONA_GP5_RISE_EINT1_SHIFT                  4  /* GP5_RISE_EINT1 */
+#define ARIZONA_GP5_RISE_EINT1_WIDTH                  1  /* GP5_RISE_EINT1 */
+#define ARIZONA_JD1_FALL_EINT1                   0x0008  /* JD1_FALL_EINT1 */
+#define ARIZONA_JD1_FALL_EINT1_MASK              0x0008  /* JD1_FALL_EINT1 */
+#define ARIZONA_JD1_FALL_EINT1_SHIFT                  3  /* JD1_FALL_EINT1 */
+#define ARIZONA_JD1_FALL_EINT1_WIDTH                  1  /* JD1_FALL_EINT1 */
+#define ARIZONA_JD1_RISE_EINT1                   0x0004  /* JD1_RISE_EINT1 */
+#define ARIZONA_JD1_RISE_EINT1_MASK              0x0004  /* JD1_RISE_EINT1 */
+#define ARIZONA_JD1_RISE_EINT1_SHIFT                  2  /* JD1_RISE_EINT1 */
+#define ARIZONA_JD1_RISE_EINT1_WIDTH                  1  /* JD1_RISE_EINT1 */
+#define ARIZONA_JD2_FALL_EINT1                   0x0002  /* JD2_FALL_EINT1 */
+#define ARIZONA_JD2_FALL_EINT1_MASK              0x0002  /* JD2_FALL_EINT1 */
+#define ARIZONA_JD2_FALL_EINT1_SHIFT                  1  /* JD2_FALL_EINT1 */
+#define ARIZONA_JD2_FALL_EINT1_WIDTH                  1  /* JD2_FALL_EINT1 */
+#define ARIZONA_JD2_RISE_EINT1                   0x0001  /* JD2_RISE_EINT1 */
+#define ARIZONA_JD2_RISE_EINT1_MASK              0x0001  /* JD2_RISE_EINT1 */
+#define ARIZONA_JD2_RISE_EINT1_SHIFT                  0  /* JD2_RISE_EINT1 */
+#define ARIZONA_JD2_RISE_EINT1_WIDTH                  1  /* JD2_RISE_EINT1 */
+
+/*
+ * R3410 (0xD52) - AOD IRQ2
+ */
+#define ARIZONA_GP5_FALL_EINT2                   0x0020  /* GP5_FALL_EINT2 */
+#define ARIZONA_GP5_FALL_EINT2_MASK              0x0020  /* GP5_FALL_EINT2 */
+#define ARIZONA_GP5_FALL_EINT2_SHIFT                  5  /* GP5_FALL_EINT2 */
+#define ARIZONA_GP5_FALL_EINT2_WIDTH                  1  /* GP5_FALL_EINT2 */
+#define ARIZONA_GP5_RISE_EINT2                   0x0010  /* GP5_RISE_EINT2 */
+#define ARIZONA_GP5_RISE_EINT2_MASK              0x0010  /* GP5_RISE_EINT2 */
+#define ARIZONA_GP5_RISE_EINT2_SHIFT                  4  /* GP5_RISE_EINT2 */
+#define ARIZONA_GP5_RISE_EINT2_WIDTH                  1  /* GP5_RISE_EINT2 */
+#define ARIZONA_JD1_FALL_EINT2                   0x0008  /* JD1_FALL_EINT2 */
+#define ARIZONA_JD1_FALL_EINT2_MASK              0x0008  /* JD1_FALL_EINT2 */
+#define ARIZONA_JD1_FALL_EINT2_SHIFT                  3  /* JD1_FALL_EINT2 */
+#define ARIZONA_JD1_FALL_EINT2_WIDTH                  1  /* JD1_FALL_EINT2 */
+#define ARIZONA_JD1_RISE_EINT2                   0x0004  /* JD1_RISE_EINT2 */
+#define ARIZONA_JD1_RISE_EINT2_MASK              0x0004  /* JD1_RISE_EINT2 */
+#define ARIZONA_JD1_RISE_EINT2_SHIFT                  2  /* JD1_RISE_EINT2 */
+#define ARIZONA_JD1_RISE_EINT2_WIDTH                  1  /* JD1_RISE_EINT2 */
+#define ARIZONA_JD2_FALL_EINT2                   0x0002  /* JD2_FALL_EINT2 */
+#define ARIZONA_JD2_FALL_EINT2_MASK              0x0002  /* JD2_FALL_EINT2 */
+#define ARIZONA_JD2_FALL_EINT2_SHIFT                  1  /* JD2_FALL_EINT2 */
+#define ARIZONA_JD2_FALL_EINT2_WIDTH                  1  /* JD2_FALL_EINT2 */
+#define ARIZONA_JD2_RISE_EINT2                   0x0001  /* JD2_RISE_EINT2 */
+#define ARIZONA_JD2_RISE_EINT2_MASK              0x0001  /* JD2_RISE_EINT2 */
+#define ARIZONA_JD2_RISE_EINT2_SHIFT                  0  /* JD2_RISE_EINT2 */
+#define ARIZONA_JD2_RISE_EINT2_WIDTH                  1  /* JD2_RISE_EINT2 */
+
+/*
+ * R3411 (0xD53) - AOD IRQ Mask IRQ1
+ */
+#define ARIZONA_IM_GP5_FALL_EINT1                0x0020  /* IM_GP5_FALL_EINT1 */
+#define ARIZONA_IM_GP5_FALL_EINT1_MASK           0x0020  /* IM_GP5_FALL_EINT1 */
+#define ARIZONA_IM_GP5_FALL_EINT1_SHIFT               5  /* IM_GP5_FALL_EINT1 */
+#define ARIZONA_IM_GP5_FALL_EINT1_WIDTH               1  /* IM_GP5_FALL_EINT1 */
+#define ARIZONA_IM_GP5_RISE_EINT1                0x0010  /* IM_GP5_RISE_EINT1 */
+#define ARIZONA_IM_GP5_RISE_EINT1_MASK           0x0010  /* IM_GP5_RISE_EINT1 */
+#define ARIZONA_IM_GP5_RISE_EINT1_SHIFT               4  /* IM_GP5_RISE_EINT1 */
+#define ARIZONA_IM_GP5_RISE_EINT1_WIDTH               1  /* IM_GP5_RISE_EINT1 */
+#define ARIZONA_IM_JD1_FALL_EINT1                0x0008  /* IM_JD1_FALL_EINT1 */
+#define ARIZONA_IM_JD1_FALL_EINT1_MASK           0x0008  /* IM_JD1_FALL_EINT1 */
+#define ARIZONA_IM_JD1_FALL_EINT1_SHIFT               3  /* IM_JD1_FALL_EINT1 */
+#define ARIZONA_IM_JD1_FALL_EINT1_WIDTH               1  /* IM_JD1_FALL_EINT1 */
+#define ARIZONA_IM_JD1_RISE_EINT1                0x0004  /* IM_JD1_RISE_EINT1 */
+#define ARIZONA_IM_JD1_RISE_EINT1_MASK           0x0004  /* IM_JD1_RISE_EINT1 */
+#define ARIZONA_IM_JD1_RISE_EINT1_SHIFT               2  /* IM_JD1_RISE_EINT1 */
+#define ARIZONA_IM_JD1_RISE_EINT1_WIDTH               1  /* IM_JD1_RISE_EINT1 */
+#define ARIZONA_IM_JD2_FALL_EINT1                0x0002  /* IM_JD2_FALL_EINT1 */
+#define ARIZONA_IM_JD2_FALL_EINT1_MASK           0x0002  /* IM_JD2_FALL_EINT1 */
+#define ARIZONA_IM_JD2_FALL_EINT1_SHIFT               1  /* IM_JD2_FALL_EINT1 */
+#define ARIZONA_IM_JD2_FALL_EINT1_WIDTH               1  /* IM_JD2_FALL_EINT1 */
+#define ARIZONA_IM_JD2_RISE_EINT1                0x0001  /* IM_JD2_RISE_EINT1 */
+#define ARIZONA_IM_JD2_RISE_EINT1_MASK           0x0001  /* IM_JD2_RISE_EINT1 */
+#define ARIZONA_IM_JD2_RISE_EINT1_SHIFT               0  /* IM_JD2_RISE_EINT1 */
+#define ARIZONA_IM_JD2_RISE_EINT1_WIDTH               1  /* IM_JD2_RISE_EINT1 */
+
+/*
+ * R3412 (0xD54) - AOD IRQ Mask IRQ2
+ */
+#define ARIZONA_IM_GP5_FALL_EINT2                0x0020  /* IM_GP5_FALL_EINT2 */
+#define ARIZONA_IM_GP5_FALL_EINT2_MASK           0x0020  /* IM_GP5_FALL_EINT2 */
+#define ARIZONA_IM_GP5_FALL_EINT2_SHIFT               5  /* IM_GP5_FALL_EINT2 */
+#define ARIZONA_IM_GP5_FALL_EINT2_WIDTH               1  /* IM_GP5_FALL_EINT2 */
+#define ARIZONA_IM_GP5_RISE_EINT2                0x0010  /* IM_GP5_RISE_EINT2 */
+#define ARIZONA_IM_GP5_RISE_EINT2_MASK           0x0010  /* IM_GP5_RISE_EINT2 */
+#define ARIZONA_IM_GP5_RISE_EINT2_SHIFT               4  /* IM_GP5_RISE_EINT2 */
+#define ARIZONA_IM_GP5_RISE_EINT2_WIDTH               1  /* IM_GP5_RISE_EINT2 */
+#define ARIZONA_IM_JD1_FALL_EINT2                0x0008  /* IM_JD1_FALL_EINT2 */
+#define ARIZONA_IM_JD1_FALL_EINT2_MASK           0x0008  /* IM_JD1_FALL_EINT2 */
+#define ARIZONA_IM_JD1_FALL_EINT2_SHIFT               3  /* IM_JD1_FALL_EINT2 */
+#define ARIZONA_IM_JD1_FALL_EINT2_WIDTH               1  /* IM_JD1_FALL_EINT2 */
+#define ARIZONA_IM_JD1_RISE_EINT2                0x0004  /* IM_JD1_RISE_EINT2 */
+#define ARIZONA_IM_JD1_RISE_EINT2_MASK           0x0004  /* IM_JD1_RISE_EINT2 */
+#define ARIZONA_IM_JD1_RISE_EINT2_SHIFT               2  /* IM_JD1_RISE_EINT2 */
+#define ARIZONA_IM_JD1_RISE_EINT2_WIDTH               1  /* IM_JD1_RISE_EINT2 */
+#define ARIZONA_IM_JD2_FALL_EINT2                0x0002  /* IM_JD2_FALL_EINT2 */
+#define ARIZONA_IM_JD2_FALL_EINT2_MASK           0x0002  /* IM_JD2_FALL_EINT2 */
+#define ARIZONA_IM_JD2_FALL_EINT2_SHIFT               1  /* IM_JD2_FALL_EINT2 */
+#define ARIZONA_IM_JD2_FALL_EINT2_WIDTH               1  /* IM_JD2_FALL_EINT2 */
+#define ARIZONA_IM_JD2_RISE_EINT2                0x0001  /* IM_JD2_RISE_EINT2 */
+#define ARIZONA_IM_JD2_RISE_EINT2_MASK           0x0001  /* IM_JD2_RISE_EINT2 */
+#define ARIZONA_IM_JD2_RISE_EINT2_SHIFT               0  /* IM_JD2_RISE_EINT2 */
+#define ARIZONA_IM_JD2_RISE_EINT2_WIDTH               1  /* IM_JD2_RISE_EINT2 */
+
+/*
+ * R3413 (0xD55) - AOD IRQ Raw Status
+ */
+#define ARIZONA_GP5_STS                          0x0004  /* GP5_STS */
+#define ARIZONA_GP5_STS_MASK                     0x0004  /* GP5_STS */
+#define ARIZONA_GP5_STS_SHIFT                         2  /* GP5_STS */
+#define ARIZONA_GP5_STS_WIDTH                         1  /* GP5_STS */
+#define ARIZONA_JD2_STS                          0x0002  /* JD2_STS */
+#define ARIZONA_JD2_STS_MASK                     0x0002  /* JD2_STS */
+#define ARIZONA_JD2_STS_SHIFT                         1  /* JD2_STS */
+#define ARIZONA_JD2_STS_WIDTH                         1  /* JD2_STS */
+#define ARIZONA_JD1_STS                          0x0001  /* JD1_STS */
+#define ARIZONA_JD1_STS_MASK                     0x0001  /* JD1_STS */
+#define ARIZONA_JD1_STS_SHIFT                         0  /* JD1_STS */
+#define ARIZONA_JD1_STS_WIDTH                         1  /* JD1_STS */
+
+/*
+ * R3414 (0xD56) - Jack detect debounce
+ */
+#define ARIZONA_JD2_DB                           0x0002  /* JD2_DB */
+#define ARIZONA_JD2_DB_MASK                      0x0002  /* JD2_DB */
+#define ARIZONA_JD2_DB_SHIFT                          1  /* JD2_DB */
+#define ARIZONA_JD2_DB_WIDTH                          1  /* JD2_DB */
+#define ARIZONA_JD1_DB                           0x0001  /* JD1_DB */
+#define ARIZONA_JD1_DB_MASK                      0x0001  /* JD1_DB */
+#define ARIZONA_JD1_DB_SHIFT                          0  /* JD1_DB */
+#define ARIZONA_JD1_DB_WIDTH                          1  /* JD1_DB */
+
+/*
+ * R3584 (0xE00) - FX_Ctrl1
+ */
+#define ARIZONA_FX_RATE_MASK                     0x7800  /* FX_RATE - [14:11] */
+#define ARIZONA_FX_RATE_SHIFT                        11  /* FX_RATE - [14:11] */
+#define ARIZONA_FX_RATE_WIDTH                         4  /* FX_RATE - [14:11] */
+
+/*
+ * R3585 (0xE01) - FX_Ctrl2
+ */
+#define ARIZONA_FX_STS_MASK                      0xFFF0  /* FX_STS - [15:4] */
+#define ARIZONA_FX_STS_SHIFT                          4  /* FX_STS - [15:4] */
+#define ARIZONA_FX_STS_WIDTH                         12  /* FX_STS - [15:4] */
+
+/*
+ * R3600 (0xE10) - EQ1_1
+ */
+#define ARIZONA_EQ1_B1_GAIN_MASK                 0xF800  /* EQ1_B1_GAIN - [15:11] */
+#define ARIZONA_EQ1_B1_GAIN_SHIFT                    11  /* EQ1_B1_GAIN - [15:11] */
+#define ARIZONA_EQ1_B1_GAIN_WIDTH                     5  /* EQ1_B1_GAIN - [15:11] */
+#define ARIZONA_EQ1_B2_GAIN_MASK                 0x07C0  /* EQ1_B2_GAIN - [10:6] */
+#define ARIZONA_EQ1_B2_GAIN_SHIFT                     6  /* EQ1_B2_GAIN - [10:6] */
+#define ARIZONA_EQ1_B2_GAIN_WIDTH                     5  /* EQ1_B2_GAIN - [10:6] */
+#define ARIZONA_EQ1_B3_GAIN_MASK                 0x003E  /* EQ1_B3_GAIN - [5:1] */
+#define ARIZONA_EQ1_B3_GAIN_SHIFT                     1  /* EQ1_B3_GAIN - [5:1] */
+#define ARIZONA_EQ1_B3_GAIN_WIDTH                     5  /* EQ1_B3_GAIN - [5:1] */
+#define ARIZONA_EQ1_ENA                          0x0001  /* EQ1_ENA */
+#define ARIZONA_EQ1_ENA_MASK                     0x0001  /* EQ1_ENA */
+#define ARIZONA_EQ1_ENA_SHIFT                         0  /* EQ1_ENA */
+#define ARIZONA_EQ1_ENA_WIDTH                         1  /* EQ1_ENA */
+
+/*
+ * R3601 (0xE11) - EQ1_2
+ */
+#define ARIZONA_EQ1_B4_GAIN_MASK                 0xF800  /* EQ1_B4_GAIN - [15:11] */
+#define ARIZONA_EQ1_B4_GAIN_SHIFT                    11  /* EQ1_B4_GAIN - [15:11] */
+#define ARIZONA_EQ1_B4_GAIN_WIDTH                     5  /* EQ1_B4_GAIN - [15:11] */
+#define ARIZONA_EQ1_B5_GAIN_MASK                 0x07C0  /* EQ1_B5_GAIN - [10:6] */
+#define ARIZONA_EQ1_B5_GAIN_SHIFT                     6  /* EQ1_B5_GAIN - [10:6] */
+#define ARIZONA_EQ1_B5_GAIN_WIDTH                     5  /* EQ1_B5_GAIN - [10:6] */
+#define ARIZONA_EQ1_B1_MODE                      0x0001  /* EQ1_B1_MODE */
+#define ARIZONA_EQ1_B1_MODE_MASK                 0x0001  /* EQ1_B1_MODE */
+#define ARIZONA_EQ1_B1_MODE_SHIFT                     0  /* EQ1_B1_MODE */
+#define ARIZONA_EQ1_B1_MODE_WIDTH                     1  /* EQ1_B1_MODE */
+
+/*
+ * R3602 (0xE12) - EQ1_3
+ */
+#define ARIZONA_EQ1_B1_A_MASK                    0xFFFF  /* EQ1_B1_A - [15:0] */
+#define ARIZONA_EQ1_B1_A_SHIFT                        0  /* EQ1_B1_A - [15:0] */
+#define ARIZONA_EQ1_B1_A_WIDTH                       16  /* EQ1_B1_A - [15:0] */
+
+/*
+ * R3603 (0xE13) - EQ1_4
+ */
+#define ARIZONA_EQ1_B1_B_MASK                    0xFFFF  /* EQ1_B1_B - [15:0] */
+#define ARIZONA_EQ1_B1_B_SHIFT                        0  /* EQ1_B1_B - [15:0] */
+#define ARIZONA_EQ1_B1_B_WIDTH                       16  /* EQ1_B1_B - [15:0] */
+
+/*
+ * R3604 (0xE14) - EQ1_5
+ */
+#define ARIZONA_EQ1_B1_PG_MASK                   0xFFFF  /* EQ1_B1_PG - [15:0] */
+#define ARIZONA_EQ1_B1_PG_SHIFT                       0  /* EQ1_B1_PG - [15:0] */
+#define ARIZONA_EQ1_B1_PG_WIDTH                      16  /* EQ1_B1_PG - [15:0] */
+
+/*
+ * R3605 (0xE15) - EQ1_6
+ */
+#define ARIZONA_EQ1_B2_A_MASK                    0xFFFF  /* EQ1_B2_A - [15:0] */
+#define ARIZONA_EQ1_B2_A_SHIFT                        0  /* EQ1_B2_A - [15:0] */
+#define ARIZONA_EQ1_B2_A_WIDTH                       16  /* EQ1_B2_A - [15:0] */
+
+/*
+ * R3606 (0xE16) - EQ1_7
+ */
+#define ARIZONA_EQ1_B2_B_MASK                    0xFFFF  /* EQ1_B2_B - [15:0] */
+#define ARIZONA_EQ1_B2_B_SHIFT                        0  /* EQ1_B2_B - [15:0] */
+#define ARIZONA_EQ1_B2_B_WIDTH                       16  /* EQ1_B2_B - [15:0] */
+
+/*
+ * R3607 (0xE17) - EQ1_8
+ */
+#define ARIZONA_EQ1_B2_C_MASK                    0xFFFF  /* EQ1_B2_C - [15:0] */
+#define ARIZONA_EQ1_B2_C_SHIFT                        0  /* EQ1_B2_C - [15:0] */
+#define ARIZONA_EQ1_B2_C_WIDTH                       16  /* EQ1_B2_C - [15:0] */
+
+/*
+ * R3608 (0xE18) - EQ1_9
+ */
+#define ARIZONA_EQ1_B2_PG_MASK                   0xFFFF  /* EQ1_B2_PG - [15:0] */
+#define ARIZONA_EQ1_B2_PG_SHIFT                       0  /* EQ1_B2_PG - [15:0] */
+#define ARIZONA_EQ1_B2_PG_WIDTH                      16  /* EQ1_B2_PG - [15:0] */
+
+/*
+ * R3609 (0xE19) - EQ1_10
+ */
+#define ARIZONA_EQ1_B3_A_MASK                    0xFFFF  /* EQ1_B3_A - [15:0] */
+#define ARIZONA_EQ1_B3_A_SHIFT                        0  /* EQ1_B3_A - [15:0] */
+#define ARIZONA_EQ1_B3_A_WIDTH                       16  /* EQ1_B3_A - [15:0] */
+
+/*
+ * R3610 (0xE1A) - EQ1_11
+ */
+#define ARIZONA_EQ1_B3_B_MASK                    0xFFFF  /* EQ1_B3_B - [15:0] */
+#define ARIZONA_EQ1_B3_B_SHIFT                        0  /* EQ1_B3_B - [15:0] */
+#define ARIZONA_EQ1_B3_B_WIDTH                       16  /* EQ1_B3_B - [15:0] */
+
+/*
+ * R3611 (0xE1B) - EQ1_12
+ */
+#define ARIZONA_EQ1_B3_C_MASK                    0xFFFF  /* EQ1_B3_C - [15:0] */
+#define ARIZONA_EQ1_B3_C_SHIFT                        0  /* EQ1_B3_C - [15:0] */
+#define ARIZONA_EQ1_B3_C_WIDTH                       16  /* EQ1_B3_C - [15:0] */
+
+/*
+ * R3612 (0xE1C) - EQ1_13
+ */
+#define ARIZONA_EQ1_B3_PG_MASK                   0xFFFF  /* EQ1_B3_PG - [15:0] */
+#define ARIZONA_EQ1_B3_PG_SHIFT                       0  /* EQ1_B3_PG - [15:0] */
+#define ARIZONA_EQ1_B3_PG_WIDTH                      16  /* EQ1_B3_PG - [15:0] */
+
+/*
+ * R3613 (0xE1D) - EQ1_14
+ */
+#define ARIZONA_EQ1_B4_A_MASK                    0xFFFF  /* EQ1_B4_A - [15:0] */
+#define ARIZONA_EQ1_B4_A_SHIFT                        0  /* EQ1_B4_A - [15:0] */
+#define ARIZONA_EQ1_B4_A_WIDTH                       16  /* EQ1_B4_A - [15:0] */
+
+/*
+ * R3614 (0xE1E) - EQ1_15
+ */
+#define ARIZONA_EQ1_B4_B_MASK                    0xFFFF  /* EQ1_B4_B - [15:0] */
+#define ARIZONA_EQ1_B4_B_SHIFT                        0  /* EQ1_B4_B - [15:0] */
+#define ARIZONA_EQ1_B4_B_WIDTH                       16  /* EQ1_B4_B - [15:0] */
+
+/*
+ * R3615 (0xE1F) - EQ1_16
+ */
+#define ARIZONA_EQ1_B4_C_MASK                    0xFFFF  /* EQ1_B4_C - [15:0] */
+#define ARIZONA_EQ1_B4_C_SHIFT                        0  /* EQ1_B4_C - [15:0] */
+#define ARIZONA_EQ1_B4_C_WIDTH                       16  /* EQ1_B4_C - [15:0] */
+
+/*
+ * R3616 (0xE20) - EQ1_17
+ */
+#define ARIZONA_EQ1_B4_PG_MASK                   0xFFFF  /* EQ1_B4_PG - [15:0] */
+#define ARIZONA_EQ1_B4_PG_SHIFT                       0  /* EQ1_B4_PG - [15:0] */
+#define ARIZONA_EQ1_B4_PG_WIDTH                      16  /* EQ1_B4_PG - [15:0] */
+
+/*
+ * R3617 (0xE21) - EQ1_18
+ */
+#define ARIZONA_EQ1_B5_A_MASK                    0xFFFF  /* EQ1_B5_A - [15:0] */
+#define ARIZONA_EQ1_B5_A_SHIFT                        0  /* EQ1_B5_A - [15:0] */
+#define ARIZONA_EQ1_B5_A_WIDTH                       16  /* EQ1_B5_A - [15:0] */
+
+/*
+ * R3618 (0xE22) - EQ1_19
+ */
+#define ARIZONA_EQ1_B5_B_MASK                    0xFFFF  /* EQ1_B5_B - [15:0] */
+#define ARIZONA_EQ1_B5_B_SHIFT                        0  /* EQ1_B5_B - [15:0] */
+#define ARIZONA_EQ1_B5_B_WIDTH                       16  /* EQ1_B5_B - [15:0] */
+
+/*
+ * R3619 (0xE23) - EQ1_20
+ */
+#define ARIZONA_EQ1_B5_PG_MASK                   0xFFFF  /* EQ1_B5_PG - [15:0] */
+#define ARIZONA_EQ1_B5_PG_SHIFT                       0  /* EQ1_B5_PG - [15:0] */
+#define ARIZONA_EQ1_B5_PG_WIDTH                      16  /* EQ1_B5_PG - [15:0] */
+
+/*
+ * R3620 (0xE24) - EQ1_21
+ */
+#define ARIZONA_EQ1_B1_C_MASK                    0xFFFF  /* EQ1_B1_C - [15:0] */
+#define ARIZONA_EQ1_B1_C_SHIFT                        0  /* EQ1_B1_C - [15:0] */
+#define ARIZONA_EQ1_B1_C_WIDTH                       16  /* EQ1_B1_C - [15:0] */
+
+/*
+ * R3622 (0xE26) - EQ2_1
+ */
+#define ARIZONA_EQ2_B1_GAIN_MASK                 0xF800  /* EQ2_B1_GAIN - [15:11] */
+#define ARIZONA_EQ2_B1_GAIN_SHIFT                    11  /* EQ2_B1_GAIN - [15:11] */
+#define ARIZONA_EQ2_B1_GAIN_WIDTH                     5  /* EQ2_B1_GAIN - [15:11] */
+#define ARIZONA_EQ2_B2_GAIN_MASK                 0x07C0  /* EQ2_B2_GAIN - [10:6] */
+#define ARIZONA_EQ2_B2_GAIN_SHIFT                     6  /* EQ2_B2_GAIN - [10:6] */
+#define ARIZONA_EQ2_B2_GAIN_WIDTH                     5  /* EQ2_B2_GAIN - [10:6] */
+#define ARIZONA_EQ2_B3_GAIN_MASK                 0x003E  /* EQ2_B3_GAIN - [5:1] */
+#define ARIZONA_EQ2_B3_GAIN_SHIFT                     1  /* EQ2_B3_GAIN - [5:1] */
+#define ARIZONA_EQ2_B3_GAIN_WIDTH                     5  /* EQ2_B3_GAIN - [5:1] */
+#define ARIZONA_EQ2_ENA                          0x0001  /* EQ2_ENA */
+#define ARIZONA_EQ2_ENA_MASK                     0x0001  /* EQ2_ENA */
+#define ARIZONA_EQ2_ENA_SHIFT                         0  /* EQ2_ENA */
+#define ARIZONA_EQ2_ENA_WIDTH                         1  /* EQ2_ENA */
+
+/*
+ * R3623 (0xE27) - EQ2_2
+ */
+#define ARIZONA_EQ2_B4_GAIN_MASK                 0xF800  /* EQ2_B4_GAIN - [15:11] */
+#define ARIZONA_EQ2_B4_GAIN_SHIFT                    11  /* EQ2_B4_GAIN - [15:11] */
+#define ARIZONA_EQ2_B4_GAIN_WIDTH                     5  /* EQ2_B4_GAIN - [15:11] */
+#define ARIZONA_EQ2_B5_GAIN_MASK                 0x07C0  /* EQ2_B5_GAIN - [10:6] */
+#define ARIZONA_EQ2_B5_GAIN_SHIFT                     6  /* EQ2_B5_GAIN - [10:6] */
+#define ARIZONA_EQ2_B5_GAIN_WIDTH                     5  /* EQ2_B5_GAIN - [10:6] */
+#define ARIZONA_EQ2_B1_MODE                      0x0001  /* EQ2_B1_MODE */
+#define ARIZONA_EQ2_B1_MODE_MASK                 0x0001  /* EQ2_B1_MODE */
+#define ARIZONA_EQ2_B1_MODE_SHIFT                     0  /* EQ2_B1_MODE */
+#define ARIZONA_EQ2_B1_MODE_WIDTH                     1  /* EQ2_B1_MODE */
+
+/*
+ * R3624 (0xE28) - EQ2_3
+ */
+#define ARIZONA_EQ2_B1_A_MASK                    0xFFFF  /* EQ2_B1_A - [15:0] */
+#define ARIZONA_EQ2_B1_A_SHIFT                        0  /* EQ2_B1_A - [15:0] */
+#define ARIZONA_EQ2_B1_A_WIDTH                       16  /* EQ2_B1_A - [15:0] */
+
+/*
+ * R3625 (0xE29) - EQ2_4
+ */
+#define ARIZONA_EQ2_B1_B_MASK                    0xFFFF  /* EQ2_B1_B - [15:0] */
+#define ARIZONA_EQ2_B1_B_SHIFT                        0  /* EQ2_B1_B - [15:0] */
+#define ARIZONA_EQ2_B1_B_WIDTH                       16  /* EQ2_B1_B - [15:0] */
+
+/*
+ * R3626 (0xE2A) - EQ2_5
+ */
+#define ARIZONA_EQ2_B1_PG_MASK                   0xFFFF  /* EQ2_B1_PG - [15:0] */
+#define ARIZONA_EQ2_B1_PG_SHIFT                       0  /* EQ2_B1_PG - [15:0] */
+#define ARIZONA_EQ2_B1_PG_WIDTH                      16  /* EQ2_B1_PG - [15:0] */
+
+/*
+ * R3627 (0xE2B) - EQ2_6
+ */
+#define ARIZONA_EQ2_B2_A_MASK                    0xFFFF  /* EQ2_B2_A - [15:0] */
+#define ARIZONA_EQ2_B2_A_SHIFT                        0  /* EQ2_B2_A - [15:0] */
+#define ARIZONA_EQ2_B2_A_WIDTH                       16  /* EQ2_B2_A - [15:0] */
+
+/*
+ * R3628 (0xE2C) - EQ2_7
+ */
+#define ARIZONA_EQ2_B2_B_MASK                    0xFFFF  /* EQ2_B2_B - [15:0] */
+#define ARIZONA_EQ2_B2_B_SHIFT                        0  /* EQ2_B2_B - [15:0] */
+#define ARIZONA_EQ2_B2_B_WIDTH                       16  /* EQ2_B2_B - [15:0] */
+
+/*
+ * R3629 (0xE2D) - EQ2_8
+ */
+#define ARIZONA_EQ2_B2_C_MASK                    0xFFFF  /* EQ2_B2_C - [15:0] */
+#define ARIZONA_EQ2_B2_C_SHIFT                        0  /* EQ2_B2_C - [15:0] */
+#define ARIZONA_EQ2_B2_C_WIDTH                       16  /* EQ2_B2_C - [15:0] */
+
+/*
+ * R3630 (0xE2E) - EQ2_9
+ */
+#define ARIZONA_EQ2_B2_PG_MASK                   0xFFFF  /* EQ2_B2_PG - [15:0] */
+#define ARIZONA_EQ2_B2_PG_SHIFT                       0  /* EQ2_B2_PG - [15:0] */
+#define ARIZONA_EQ2_B2_PG_WIDTH                      16  /* EQ2_B2_PG - [15:0] */
+
+/*
+ * R3631 (0xE2F) - EQ2_10
+ */
+#define ARIZONA_EQ2_B3_A_MASK                    0xFFFF  /* EQ2_B3_A - [15:0] */
+#define ARIZONA_EQ2_B3_A_SHIFT                        0  /* EQ2_B3_A - [15:0] */
+#define ARIZONA_EQ2_B3_A_WIDTH                       16  /* EQ2_B3_A - [15:0] */
+
+/*
+ * R3632 (0xE30) - EQ2_11
+ */
+#define ARIZONA_EQ2_B3_B_MASK                    0xFFFF  /* EQ2_B3_B - [15:0] */
+#define ARIZONA_EQ2_B3_B_SHIFT                        0  /* EQ2_B3_B - [15:0] */
+#define ARIZONA_EQ2_B3_B_WIDTH                       16  /* EQ2_B3_B - [15:0] */
+
+/*
+ * R3633 (0xE31) - EQ2_12
+ */
+#define ARIZONA_EQ2_B3_C_MASK                    0xFFFF  /* EQ2_B3_C - [15:0] */
+#define ARIZONA_EQ2_B3_C_SHIFT                        0  /* EQ2_B3_C - [15:0] */
+#define ARIZONA_EQ2_B3_C_WIDTH                       16  /* EQ2_B3_C - [15:0] */
+
+/*
+ * R3634 (0xE32) - EQ2_13
+ */
+#define ARIZONA_EQ2_B3_PG_MASK                   0xFFFF  /* EQ2_B3_PG - [15:0] */
+#define ARIZONA_EQ2_B3_PG_SHIFT                       0  /* EQ2_B3_PG - [15:0] */
+#define ARIZONA_EQ2_B3_PG_WIDTH                      16  /* EQ2_B3_PG - [15:0] */
+
+/*
+ * R3635 (0xE33) - EQ2_14
+ */
+#define ARIZONA_EQ2_B4_A_MASK                    0xFFFF  /* EQ2_B4_A - [15:0] */
+#define ARIZONA_EQ2_B4_A_SHIFT                        0  /* EQ2_B4_A - [15:0] */
+#define ARIZONA_EQ2_B4_A_WIDTH                       16  /* EQ2_B4_A - [15:0] */
+
+/*
+ * R3636 (0xE34) - EQ2_15
+ */
+#define ARIZONA_EQ2_B4_B_MASK                    0xFFFF  /* EQ2_B4_B - [15:0] */
+#define ARIZONA_EQ2_B4_B_SHIFT                        0  /* EQ2_B4_B - [15:0] */
+#define ARIZONA_EQ2_B4_B_WIDTH                       16  /* EQ2_B4_B - [15:0] */
+
+/*
+ * R3637 (0xE35) - EQ2_16
+ */
+#define ARIZONA_EQ2_B4_C_MASK                    0xFFFF  /* EQ2_B4_C - [15:0] */
+#define ARIZONA_EQ2_B4_C_SHIFT                        0  /* EQ2_B4_C - [15:0] */
+#define ARIZONA_EQ2_B4_C_WIDTH                       16  /* EQ2_B4_C - [15:0] */
+
+/*
+ * R3638 (0xE36) - EQ2_17
+ */
+#define ARIZONA_EQ2_B4_PG_MASK                   0xFFFF  /* EQ2_B4_PG - [15:0] */
+#define ARIZONA_EQ2_B4_PG_SHIFT                       0  /* EQ2_B4_PG - [15:0] */
+#define ARIZONA_EQ2_B4_PG_WIDTH                      16  /* EQ2_B4_PG - [15:0] */
+
+/*
+ * R3639 (0xE37) - EQ2_18
+ */
+#define ARIZONA_EQ2_B5_A_MASK                    0xFFFF  /* EQ2_B5_A - [15:0] */
+#define ARIZONA_EQ2_B5_A_SHIFT                        0  /* EQ2_B5_A - [15:0] */
+#define ARIZONA_EQ2_B5_A_WIDTH                       16  /* EQ2_B5_A - [15:0] */
+
+/*
+ * R3640 (0xE38) - EQ2_19
+ */
+#define ARIZONA_EQ2_B5_B_MASK                    0xFFFF  /* EQ2_B5_B - [15:0] */
+#define ARIZONA_EQ2_B5_B_SHIFT                        0  /* EQ2_B5_B - [15:0] */
+#define ARIZONA_EQ2_B5_B_WIDTH                       16  /* EQ2_B5_B - [15:0] */
+
+/*
+ * R3641 (0xE39) - EQ2_20
+ */
+#define ARIZONA_EQ2_B5_PG_MASK                   0xFFFF  /* EQ2_B5_PG - [15:0] */
+#define ARIZONA_EQ2_B5_PG_SHIFT                       0  /* EQ2_B5_PG - [15:0] */
+#define ARIZONA_EQ2_B5_PG_WIDTH                      16  /* EQ2_B5_PG - [15:0] */
+
+/*
+ * R3642 (0xE3A) - EQ2_21
+ */
+#define ARIZONA_EQ2_B1_C_MASK                    0xFFFF  /* EQ2_B1_C - [15:0] */
+#define ARIZONA_EQ2_B1_C_SHIFT                        0  /* EQ2_B1_C - [15:0] */
+#define ARIZONA_EQ2_B1_C_WIDTH                       16  /* EQ2_B1_C - [15:0] */
+
+/*
+ * R3644 (0xE3C) - EQ3_1
+ */
+#define ARIZONA_EQ3_B1_GAIN_MASK                 0xF800  /* EQ3_B1_GAIN - [15:11] */
+#define ARIZONA_EQ3_B1_GAIN_SHIFT                    11  /* EQ3_B1_GAIN - [15:11] */
+#define ARIZONA_EQ3_B1_GAIN_WIDTH                     5  /* EQ3_B1_GAIN - [15:11] */
+#define ARIZONA_EQ3_B2_GAIN_MASK                 0x07C0  /* EQ3_B2_GAIN - [10:6] */
+#define ARIZONA_EQ3_B2_GAIN_SHIFT                     6  /* EQ3_B2_GAIN - [10:6] */
+#define ARIZONA_EQ3_B2_GAIN_WIDTH                     5  /* EQ3_B2_GAIN - [10:6] */
+#define ARIZONA_EQ3_B3_GAIN_MASK                 0x003E  /* EQ3_B3_GAIN - [5:1] */
+#define ARIZONA_EQ3_B3_GAIN_SHIFT                     1  /* EQ3_B3_GAIN - [5:1] */
+#define ARIZONA_EQ3_B3_GAIN_WIDTH                     5  /* EQ3_B3_GAIN - [5:1] */
+#define ARIZONA_EQ3_ENA                          0x0001  /* EQ3_ENA */
+#define ARIZONA_EQ3_ENA_MASK                     0x0001  /* EQ3_ENA */
+#define ARIZONA_EQ3_ENA_SHIFT                         0  /* EQ3_ENA */
+#define ARIZONA_EQ3_ENA_WIDTH                         1  /* EQ3_ENA */
+
+/*
+ * R3645 (0xE3D) - EQ3_2
+ */
+#define ARIZONA_EQ3_B4_GAIN_MASK                 0xF800  /* EQ3_B4_GAIN - [15:11] */
+#define ARIZONA_EQ3_B4_GAIN_SHIFT                    11  /* EQ3_B4_GAIN - [15:11] */
+#define ARIZONA_EQ3_B4_GAIN_WIDTH                     5  /* EQ3_B4_GAIN - [15:11] */
+#define ARIZONA_EQ3_B5_GAIN_MASK                 0x07C0  /* EQ3_B5_GAIN - [10:6] */
+#define ARIZONA_EQ3_B5_GAIN_SHIFT                     6  /* EQ3_B5_GAIN - [10:6] */
+#define ARIZONA_EQ3_B5_GAIN_WIDTH                     5  /* EQ3_B5_GAIN - [10:6] */
+#define ARIZONA_EQ3_B1_MODE                      0x0001  /* EQ3_B1_MODE */
+#define ARIZONA_EQ3_B1_MODE_MASK                 0x0001  /* EQ3_B1_MODE */
+#define ARIZONA_EQ3_B1_MODE_SHIFT                     0  /* EQ3_B1_MODE */
+#define ARIZONA_EQ3_B1_MODE_WIDTH                     1  /* EQ3_B1_MODE */
+
+/*
+ * R3646 (0xE3E) - EQ3_3
+ */
+#define ARIZONA_EQ3_B1_A_MASK                    0xFFFF  /* EQ3_B1_A - [15:0] */
+#define ARIZONA_EQ3_B1_A_SHIFT                        0  /* EQ3_B1_A - [15:0] */
+#define ARIZONA_EQ3_B1_A_WIDTH                       16  /* EQ3_B1_A - [15:0] */
+
+/*
+ * R3647 (0xE3F) - EQ3_4
+ */
+#define ARIZONA_EQ3_B1_B_MASK                    0xFFFF  /* EQ3_B1_B - [15:0] */
+#define ARIZONA_EQ3_B1_B_SHIFT                        0  /* EQ3_B1_B - [15:0] */
+#define ARIZONA_EQ3_B1_B_WIDTH                       16  /* EQ3_B1_B - [15:0] */
+
+/*
+ * R3648 (0xE40) - EQ3_5
+ */
+#define ARIZONA_EQ3_B1_PG_MASK                   0xFFFF  /* EQ3_B1_PG - [15:0] */
+#define ARIZONA_EQ3_B1_PG_SHIFT                       0  /* EQ3_B1_PG - [15:0] */
+#define ARIZONA_EQ3_B1_PG_WIDTH                      16  /* EQ3_B1_PG - [15:0] */
+
+/*
+ * R3649 (0xE41) - EQ3_6
+ */
+#define ARIZONA_EQ3_B2_A_MASK                    0xFFFF  /* EQ3_B2_A - [15:0] */
+#define ARIZONA_EQ3_B2_A_SHIFT                        0  /* EQ3_B2_A - [15:0] */
+#define ARIZONA_EQ3_B2_A_WIDTH                       16  /* EQ3_B2_A - [15:0] */
+
+/*
+ * R3650 (0xE42) - EQ3_7
+ */
+#define ARIZONA_EQ3_B2_B_MASK                    0xFFFF  /* EQ3_B2_B - [15:0] */
+#define ARIZONA_EQ3_B2_B_SHIFT                        0  /* EQ3_B2_B - [15:0] */
+#define ARIZONA_EQ3_B2_B_WIDTH                       16  /* EQ3_B2_B - [15:0] */
+
+/*
+ * R3651 (0xE43) - EQ3_8
+ */
+#define ARIZONA_EQ3_B2_C_MASK                    0xFFFF  /* EQ3_B2_C - [15:0] */
+#define ARIZONA_EQ3_B2_C_SHIFT                        0  /* EQ3_B2_C - [15:0] */
+#define ARIZONA_EQ3_B2_C_WIDTH                       16  /* EQ3_B2_C - [15:0] */
+
+/*
+ * R3652 (0xE44) - EQ3_9
+ */
+#define ARIZONA_EQ3_B2_PG_MASK                   0xFFFF  /* EQ3_B2_PG - [15:0] */
+#define ARIZONA_EQ3_B2_PG_SHIFT                       0  /* EQ3_B2_PG - [15:0] */
+#define ARIZONA_EQ3_B2_PG_WIDTH                      16  /* EQ3_B2_PG - [15:0] */
+
+/*
+ * R3653 (0xE45) - EQ3_10
+ */
+#define ARIZONA_EQ3_B3_A_MASK                    0xFFFF  /* EQ3_B3_A - [15:0] */
+#define ARIZONA_EQ3_B3_A_SHIFT                        0  /* EQ3_B3_A - [15:0] */
+#define ARIZONA_EQ3_B3_A_WIDTH                       16  /* EQ3_B3_A - [15:0] */
+
+/*
+ * R3654 (0xE46) - EQ3_11
+ */
+#define ARIZONA_EQ3_B3_B_MASK                    0xFFFF  /* EQ3_B3_B - [15:0] */
+#define ARIZONA_EQ3_B3_B_SHIFT                        0  /* EQ3_B3_B - [15:0] */
+#define ARIZONA_EQ3_B3_B_WIDTH                       16  /* EQ3_B3_B - [15:0] */
+
+/*
+ * R3655 (0xE47) - EQ3_12
+ */
+#define ARIZONA_EQ3_B3_C_MASK                    0xFFFF  /* EQ3_B3_C - [15:0] */
+#define ARIZONA_EQ3_B3_C_SHIFT                        0  /* EQ3_B3_C - [15:0] */
+#define ARIZONA_EQ3_B3_C_WIDTH                       16  /* EQ3_B3_C - [15:0] */
+
+/*
+ * R3656 (0xE48) - EQ3_13
+ */
+#define ARIZONA_EQ3_B3_PG_MASK                   0xFFFF  /* EQ3_B3_PG - [15:0] */
+#define ARIZONA_EQ3_B3_PG_SHIFT                       0  /* EQ3_B3_PG - [15:0] */
+#define ARIZONA_EQ3_B3_PG_WIDTH                      16  /* EQ3_B3_PG - [15:0] */
+
+/*
+ * R3657 (0xE49) - EQ3_14
+ */
+#define ARIZONA_EQ3_B4_A_MASK                    0xFFFF  /* EQ3_B4_A - [15:0] */
+#define ARIZONA_EQ3_B4_A_SHIFT                        0  /* EQ3_B4_A - [15:0] */
+#define ARIZONA_EQ3_B4_A_WIDTH                       16  /* EQ3_B4_A - [15:0] */
+
+/*
+ * R3658 (0xE4A) - EQ3_15
+ */
+#define ARIZONA_EQ3_B4_B_MASK                    0xFFFF  /* EQ3_B4_B - [15:0] */
+#define ARIZONA_EQ3_B4_B_SHIFT                        0  /* EQ3_B4_B - [15:0] */
+#define ARIZONA_EQ3_B4_B_WIDTH                       16  /* EQ3_B4_B - [15:0] */
+
+/*
+ * R3659 (0xE4B) - EQ3_16
+ */
+#define ARIZONA_EQ3_B4_C_MASK                    0xFFFF  /* EQ3_B4_C - [15:0] */
+#define ARIZONA_EQ3_B4_C_SHIFT                        0  /* EQ3_B4_C - [15:0] */
+#define ARIZONA_EQ3_B4_C_WIDTH                       16  /* EQ3_B4_C - [15:0] */
+
+/*
+ * R3660 (0xE4C) - EQ3_17
+ */
+#define ARIZONA_EQ3_B4_PG_MASK                   0xFFFF  /* EQ3_B4_PG - [15:0] */
+#define ARIZONA_EQ3_B4_PG_SHIFT                       0  /* EQ3_B4_PG - [15:0] */
+#define ARIZONA_EQ3_B4_PG_WIDTH                      16  /* EQ3_B4_PG - [15:0] */
+
+/*
+ * R3661 (0xE4D) - EQ3_18
+ */
+#define ARIZONA_EQ3_B5_A_MASK                    0xFFFF  /* EQ3_B5_A - [15:0] */
+#define ARIZONA_EQ3_B5_A_SHIFT                        0  /* EQ3_B5_A - [15:0] */
+#define ARIZONA_EQ3_B5_A_WIDTH                       16  /* EQ3_B5_A - [15:0] */
+
+/*
+ * R3662 (0xE4E) - EQ3_19
+ */
+#define ARIZONA_EQ3_B5_B_MASK                    0xFFFF  /* EQ3_B5_B - [15:0] */
+#define ARIZONA_EQ3_B5_B_SHIFT                        0  /* EQ3_B5_B - [15:0] */
+#define ARIZONA_EQ3_B5_B_WIDTH                       16  /* EQ3_B5_B - [15:0] */
+
+/*
+ * R3663 (0xE4F) - EQ3_20
+ */
+#define ARIZONA_EQ3_B5_PG_MASK                   0xFFFF  /* EQ3_B5_PG - [15:0] */
+#define ARIZONA_EQ3_B5_PG_SHIFT                       0  /* EQ3_B5_PG - [15:0] */
+#define ARIZONA_EQ3_B5_PG_WIDTH                      16  /* EQ3_B5_PG - [15:0] */
+
+/*
+ * R3664 (0xE50) - EQ3_21
+ */
+#define ARIZONA_EQ3_B1_C_MASK                    0xFFFF  /* EQ3_B1_C - [15:0] */
+#define ARIZONA_EQ3_B1_C_SHIFT                        0  /* EQ3_B1_C - [15:0] */
+#define ARIZONA_EQ3_B1_C_WIDTH                       16  /* EQ3_B1_C - [15:0] */
+
+/*
+ * R3666 (0xE52) - EQ4_1
+ */
+#define ARIZONA_EQ4_B1_GAIN_MASK                 0xF800  /* EQ4_B1_GAIN - [15:11] */
+#define ARIZONA_EQ4_B1_GAIN_SHIFT                    11  /* EQ4_B1_GAIN - [15:11] */
+#define ARIZONA_EQ4_B1_GAIN_WIDTH                     5  /* EQ4_B1_GAIN - [15:11] */
+#define ARIZONA_EQ4_B2_GAIN_MASK                 0x07C0  /* EQ4_B2_GAIN - [10:6] */
+#define ARIZONA_EQ4_B2_GAIN_SHIFT                     6  /* EQ4_B2_GAIN - [10:6] */
+#define ARIZONA_EQ4_B2_GAIN_WIDTH                     5  /* EQ4_B2_GAIN - [10:6] */
+#define ARIZONA_EQ4_B3_GAIN_MASK                 0x003E  /* EQ4_B3_GAIN - [5:1] */
+#define ARIZONA_EQ4_B3_GAIN_SHIFT                     1  /* EQ4_B3_GAIN - [5:1] */
+#define ARIZONA_EQ4_B3_GAIN_WIDTH                     5  /* EQ4_B3_GAIN - [5:1] */
+#define ARIZONA_EQ4_ENA                          0x0001  /* EQ4_ENA */
+#define ARIZONA_EQ4_ENA_MASK                     0x0001  /* EQ4_ENA */
+#define ARIZONA_EQ4_ENA_SHIFT                         0  /* EQ4_ENA */
+#define ARIZONA_EQ4_ENA_WIDTH                         1  /* EQ4_ENA */
+
+/*
+ * R3667 (0xE53) - EQ4_2
+ */
+#define ARIZONA_EQ4_B4_GAIN_MASK                 0xF800  /* EQ4_B4_GAIN - [15:11] */
+#define ARIZONA_EQ4_B4_GAIN_SHIFT                    11  /* EQ4_B4_GAIN - [15:11] */
+#define ARIZONA_EQ4_B4_GAIN_WIDTH                     5  /* EQ4_B4_GAIN - [15:11] */
+#define ARIZONA_EQ4_B5_GAIN_MASK                 0x07C0  /* EQ4_B5_GAIN - [10:6] */
+#define ARIZONA_EQ4_B5_GAIN_SHIFT                     6  /* EQ4_B5_GAIN - [10:6] */
+#define ARIZONA_EQ4_B5_GAIN_WIDTH                     5  /* EQ4_B5_GAIN - [10:6] */
+#define ARIZONA_EQ4_B1_MODE                      0x0001  /* EQ4_B1_MODE */
+#define ARIZONA_EQ4_B1_MODE_MASK                 0x0001  /* EQ4_B1_MODE */
+#define ARIZONA_EQ4_B1_MODE_SHIFT                     0  /* EQ4_B1_MODE */
+#define ARIZONA_EQ4_B1_MODE_WIDTH                     1  /* EQ4_B1_MODE */
+
+/*
+ * R3668 (0xE54) - EQ4_3
+ */
+#define ARIZONA_EQ4_B1_A_MASK                    0xFFFF  /* EQ4_B1_A - [15:0] */
+#define ARIZONA_EQ4_B1_A_SHIFT                        0  /* EQ4_B1_A - [15:0] */
+#define ARIZONA_EQ4_B1_A_WIDTH                       16  /* EQ4_B1_A - [15:0] */
+
+/*
+ * R3669 (0xE55) - EQ4_4
+ */
+#define ARIZONA_EQ4_B1_B_MASK                    0xFFFF  /* EQ4_B1_B - [15:0] */
+#define ARIZONA_EQ4_B1_B_SHIFT                        0  /* EQ4_B1_B - [15:0] */
+#define ARIZONA_EQ4_B1_B_WIDTH                       16  /* EQ4_B1_B - [15:0] */
+
+/*
+ * R3670 (0xE56) - EQ4_5
+ */
+#define ARIZONA_EQ4_B1_PG_MASK                   0xFFFF  /* EQ4_B1_PG - [15:0] */
+#define ARIZONA_EQ4_B1_PG_SHIFT                       0  /* EQ4_B1_PG - [15:0] */
+#define ARIZONA_EQ4_B1_PG_WIDTH                      16  /* EQ4_B1_PG - [15:0] */
+
+/*
+ * R3671 (0xE57) - EQ4_6
+ */
+#define ARIZONA_EQ4_B2_A_MASK                    0xFFFF  /* EQ4_B2_A - [15:0] */
+#define ARIZONA_EQ4_B2_A_SHIFT                        0  /* EQ4_B2_A - [15:0] */
+#define ARIZONA_EQ4_B2_A_WIDTH                       16  /* EQ4_B2_A - [15:0] */
+
+/*
+ * R3672 (0xE58) - EQ4_7
+ */
+#define ARIZONA_EQ4_B2_B_MASK                    0xFFFF  /* EQ4_B2_B - [15:0] */
+#define ARIZONA_EQ4_B2_B_SHIFT                        0  /* EQ4_B2_B - [15:0] */
+#define ARIZONA_EQ4_B2_B_WIDTH                       16  /* EQ4_B2_B - [15:0] */
+
+/*
+ * R3673 (0xE59) - EQ4_8
+ */
+#define ARIZONA_EQ4_B2_C_MASK                    0xFFFF  /* EQ4_B2_C - [15:0] */
+#define ARIZONA_EQ4_B2_C_SHIFT                        0  /* EQ4_B2_C - [15:0] */
+#define ARIZONA_EQ4_B2_C_WIDTH                       16  /* EQ4_B2_C - [15:0] */
+
+/*
+ * R3674 (0xE5A) - EQ4_9
+ */
+#define ARIZONA_EQ4_B2_PG_MASK                   0xFFFF  /* EQ4_B2_PG - [15:0] */
+#define ARIZONA_EQ4_B2_PG_SHIFT                       0  /* EQ4_B2_PG - [15:0] */
+#define ARIZONA_EQ4_B2_PG_WIDTH                      16  /* EQ4_B2_PG - [15:0] */
+
+/*
+ * R3675 (0xE5B) - EQ4_10
+ */
+#define ARIZONA_EQ4_B3_A_MASK                    0xFFFF  /* EQ4_B3_A - [15:0] */
+#define ARIZONA_EQ4_B3_A_SHIFT                        0  /* EQ4_B3_A - [15:0] */
+#define ARIZONA_EQ4_B3_A_WIDTH                       16  /* EQ4_B3_A - [15:0] */
+
+/*
+ * R3676 (0xE5C) - EQ4_11
+ */
+#define ARIZONA_EQ4_B3_B_MASK                    0xFFFF  /* EQ4_B3_B - [15:0] */
+#define ARIZONA_EQ4_B3_B_SHIFT                        0  /* EQ4_B3_B - [15:0] */
+#define ARIZONA_EQ4_B3_B_WIDTH                       16  /* EQ4_B3_B - [15:0] */
+
+/*
+ * R3677 (0xE5D) - EQ4_12
+ */
+#define ARIZONA_EQ4_B3_C_MASK                    0xFFFF  /* EQ4_B3_C - [15:0] */
+#define ARIZONA_EQ4_B3_C_SHIFT                        0  /* EQ4_B3_C - [15:0] */
+#define ARIZONA_EQ4_B3_C_WIDTH                       16  /* EQ4_B3_C - [15:0] */
+
+/*
+ * R3678 (0xE5E) - EQ4_13
+ */
+#define ARIZONA_EQ4_B3_PG_MASK                   0xFFFF  /* EQ4_B3_PG - [15:0] */
+#define ARIZONA_EQ4_B3_PG_SHIFT                       0  /* EQ4_B3_PG - [15:0] */
+#define ARIZONA_EQ4_B3_PG_WIDTH                      16  /* EQ4_B3_PG - [15:0] */
+
+/*
+ * R3679 (0xE5F) - EQ4_14
+ */
+#define ARIZONA_EQ4_B4_A_MASK                    0xFFFF  /* EQ4_B4_A - [15:0] */
+#define ARIZONA_EQ4_B4_A_SHIFT                        0  /* EQ4_B4_A - [15:0] */
+#define ARIZONA_EQ4_B4_A_WIDTH                       16  /* EQ4_B4_A - [15:0] */
+
+/*
+ * R3680 (0xE60) - EQ4_15
+ */
+#define ARIZONA_EQ4_B4_B_MASK                    0xFFFF  /* EQ4_B4_B - [15:0] */
+#define ARIZONA_EQ4_B4_B_SHIFT                        0  /* EQ4_B4_B - [15:0] */
+#define ARIZONA_EQ4_B4_B_WIDTH                       16  /* EQ4_B4_B - [15:0] */
+
+/*
+ * R3681 (0xE61) - EQ4_16
+ */
+#define ARIZONA_EQ4_B4_C_MASK                    0xFFFF  /* EQ4_B4_C - [15:0] */
+#define ARIZONA_EQ4_B4_C_SHIFT                        0  /* EQ4_B4_C - [15:0] */
+#define ARIZONA_EQ4_B4_C_WIDTH                       16  /* EQ4_B4_C - [15:0] */
+
+/*
+ * R3682 (0xE62) - EQ4_17
+ */
+#define ARIZONA_EQ4_B4_PG_MASK                   0xFFFF  /* EQ4_B4_PG - [15:0] */
+#define ARIZONA_EQ4_B4_PG_SHIFT                       0  /* EQ4_B4_PG - [15:0] */
+#define ARIZONA_EQ4_B4_PG_WIDTH                      16  /* EQ4_B4_PG - [15:0] */
+
+/*
+ * R3683 (0xE63) - EQ4_18
+ */
+#define ARIZONA_EQ4_B5_A_MASK                    0xFFFF  /* EQ4_B5_A - [15:0] */
+#define ARIZONA_EQ4_B5_A_SHIFT                        0  /* EQ4_B5_A - [15:0] */
+#define ARIZONA_EQ4_B5_A_WIDTH                       16  /* EQ4_B5_A - [15:0] */
+
+/*
+ * R3684 (0xE64) - EQ4_19
+ */
+#define ARIZONA_EQ4_B5_B_MASK                    0xFFFF  /* EQ4_B5_B - [15:0] */
+#define ARIZONA_EQ4_B5_B_SHIFT                        0  /* EQ4_B5_B - [15:0] */
+#define ARIZONA_EQ4_B5_B_WIDTH                       16  /* EQ4_B5_B - [15:0] */
+
+/*
+ * R3685 (0xE65) - EQ4_20
+ */
+#define ARIZONA_EQ4_B5_PG_MASK                   0xFFFF  /* EQ4_B5_PG - [15:0] */
+#define ARIZONA_EQ4_B5_PG_SHIFT                       0  /* EQ4_B5_PG - [15:0] */
+#define ARIZONA_EQ4_B5_PG_WIDTH                      16  /* EQ4_B5_PG - [15:0] */
+
+/*
+ * R3686 (0xE66) - EQ4_21
+ */
+#define ARIZONA_EQ4_B1_C_MASK                    0xFFFF  /* EQ4_B1_C - [15:0] */
+#define ARIZONA_EQ4_B1_C_SHIFT                        0  /* EQ4_B1_C - [15:0] */
+#define ARIZONA_EQ4_B1_C_WIDTH                       16  /* EQ4_B1_C - [15:0] */
+
+/*
+ * R3712 (0xE80) - DRC1 ctrl1
+ */
+#define ARIZONA_DRC1_SIG_DET_RMS_MASK            0xF800  /* DRC1_SIG_DET_RMS - [15:11] */
+#define ARIZONA_DRC1_SIG_DET_RMS_SHIFT               11  /* DRC1_SIG_DET_RMS - [15:11] */
+#define ARIZONA_DRC1_SIG_DET_RMS_WIDTH                5  /* DRC1_SIG_DET_RMS - [15:11] */
+#define ARIZONA_DRC1_SIG_DET_PK_MASK             0x0600  /* DRC1_SIG_DET_PK - [10:9] */
+#define ARIZONA_DRC1_SIG_DET_PK_SHIFT                 9  /* DRC1_SIG_DET_PK - [10:9] */
+#define ARIZONA_DRC1_SIG_DET_PK_WIDTH                 2  /* DRC1_SIG_DET_PK - [10:9] */
+#define ARIZONA_DRC1_NG_ENA                      0x0100  /* DRC1_NG_ENA */
+#define ARIZONA_DRC1_NG_ENA_MASK                 0x0100  /* DRC1_NG_ENA */
+#define ARIZONA_DRC1_NG_ENA_SHIFT                     8  /* DRC1_NG_ENA */
+#define ARIZONA_DRC1_NG_ENA_WIDTH                     1  /* DRC1_NG_ENA */
+#define ARIZONA_DRC1_SIG_DET_MODE                0x0080  /* DRC1_SIG_DET_MODE */
+#define ARIZONA_DRC1_SIG_DET_MODE_MASK           0x0080  /* DRC1_SIG_DET_MODE */
+#define ARIZONA_DRC1_SIG_DET_MODE_SHIFT               7  /* DRC1_SIG_DET_MODE */
+#define ARIZONA_DRC1_SIG_DET_MODE_WIDTH               1  /* DRC1_SIG_DET_MODE */
+#define ARIZONA_DRC1_SIG_DET                     0x0040  /* DRC1_SIG_DET */
+#define ARIZONA_DRC1_SIG_DET_MASK                0x0040  /* DRC1_SIG_DET */
+#define ARIZONA_DRC1_SIG_DET_SHIFT                    6  /* DRC1_SIG_DET */
+#define ARIZONA_DRC1_SIG_DET_WIDTH                    1  /* DRC1_SIG_DET */
+#define ARIZONA_DRC1_KNEE2_OP_ENA                0x0020  /* DRC1_KNEE2_OP_ENA */
+#define ARIZONA_DRC1_KNEE2_OP_ENA_MASK           0x0020  /* DRC1_KNEE2_OP_ENA */
+#define ARIZONA_DRC1_KNEE2_OP_ENA_SHIFT               5  /* DRC1_KNEE2_OP_ENA */
+#define ARIZONA_DRC1_KNEE2_OP_ENA_WIDTH               1  /* DRC1_KNEE2_OP_ENA */
+#define ARIZONA_DRC1_QR                          0x0010  /* DRC1_QR */
+#define ARIZONA_DRC1_QR_MASK                     0x0010  /* DRC1_QR */
+#define ARIZONA_DRC1_QR_SHIFT                         4  /* DRC1_QR */
+#define ARIZONA_DRC1_QR_WIDTH                         1  /* DRC1_QR */
+#define ARIZONA_DRC1_ANTICLIP                    0x0008  /* DRC1_ANTICLIP */
+#define ARIZONA_DRC1_ANTICLIP_MASK               0x0008  /* DRC1_ANTICLIP */
+#define ARIZONA_DRC1_ANTICLIP_SHIFT                   3  /* DRC1_ANTICLIP */
+#define ARIZONA_DRC1_ANTICLIP_WIDTH                   1  /* DRC1_ANTICLIP */
+#define ARIZONA_DRC1L_ENA                        0x0002  /* DRC1L_ENA */
+#define ARIZONA_DRC1L_ENA_MASK                   0x0002  /* DRC1L_ENA */
+#define ARIZONA_DRC1L_ENA_SHIFT                       1  /* DRC1L_ENA */
+#define ARIZONA_DRC1L_ENA_WIDTH                       1  /* DRC1L_ENA */
+#define ARIZONA_DRC1R_ENA                        0x0001  /* DRC1R_ENA */
+#define ARIZONA_DRC1R_ENA_MASK                   0x0001  /* DRC1R_ENA */
+#define ARIZONA_DRC1R_ENA_SHIFT                       0  /* DRC1R_ENA */
+#define ARIZONA_DRC1R_ENA_WIDTH                       1  /* DRC1R_ENA */
+
+/*
+ * R3713 (0xE81) - DRC1 ctrl2
+ */
+#define ARIZONA_DRC1_ATK_MASK                    0x1E00  /* DRC1_ATK - [12:9] */
+#define ARIZONA_DRC1_ATK_SHIFT                        9  /* DRC1_ATK - [12:9] */
+#define ARIZONA_DRC1_ATK_WIDTH                        4  /* DRC1_ATK - [12:9] */
+#define ARIZONA_DRC1_DCY_MASK                    0x01E0  /* DRC1_DCY - [8:5] */
+#define ARIZONA_DRC1_DCY_SHIFT                        5  /* DRC1_DCY - [8:5] */
+#define ARIZONA_DRC1_DCY_WIDTH                        4  /* DRC1_DCY - [8:5] */
+#define ARIZONA_DRC1_MINGAIN_MASK                0x001C  /* DRC1_MINGAIN - [4:2] */
+#define ARIZONA_DRC1_MINGAIN_SHIFT                    2  /* DRC1_MINGAIN - [4:2] */
+#define ARIZONA_DRC1_MINGAIN_WIDTH                    3  /* DRC1_MINGAIN - [4:2] */
+#define ARIZONA_DRC1_MAXGAIN_MASK                0x0003  /* DRC1_MAXGAIN - [1:0] */
+#define ARIZONA_DRC1_MAXGAIN_SHIFT                    0  /* DRC1_MAXGAIN - [1:0] */
+#define ARIZONA_DRC1_MAXGAIN_WIDTH                    2  /* DRC1_MAXGAIN - [1:0] */
+
+/*
+ * R3714 (0xE82) - DRC1 ctrl3
+ */
+#define ARIZONA_DRC1_NG_MINGAIN_MASK             0xF000  /* DRC1_NG_MINGAIN - [15:12] */
+#define ARIZONA_DRC1_NG_MINGAIN_SHIFT                12  /* DRC1_NG_MINGAIN - [15:12] */
+#define ARIZONA_DRC1_NG_MINGAIN_WIDTH                 4  /* DRC1_NG_MINGAIN - [15:12] */
+#define ARIZONA_DRC1_NG_EXP_MASK                 0x0C00  /* DRC1_NG_EXP - [11:10] */
+#define ARIZONA_DRC1_NG_EXP_SHIFT                    10  /* DRC1_NG_EXP - [11:10] */
+#define ARIZONA_DRC1_NG_EXP_WIDTH                     2  /* DRC1_NG_EXP - [11:10] */
+#define ARIZONA_DRC1_QR_THR_MASK                 0x0300  /* DRC1_QR_THR - [9:8] */
+#define ARIZONA_DRC1_QR_THR_SHIFT                     8  /* DRC1_QR_THR - [9:8] */
+#define ARIZONA_DRC1_QR_THR_WIDTH                     2  /* DRC1_QR_THR - [9:8] */
+#define ARIZONA_DRC1_QR_DCY_MASK                 0x00C0  /* DRC1_QR_DCY - [7:6] */
+#define ARIZONA_DRC1_QR_DCY_SHIFT                     6  /* DRC1_QR_DCY - [7:6] */
+#define ARIZONA_DRC1_QR_DCY_WIDTH                     2  /* DRC1_QR_DCY - [7:6] */
+#define ARIZONA_DRC1_HI_COMP_MASK                0x0038  /* DRC1_HI_COMP - [5:3] */
+#define ARIZONA_DRC1_HI_COMP_SHIFT                    3  /* DRC1_HI_COMP - [5:3] */
+#define ARIZONA_DRC1_HI_COMP_WIDTH                    3  /* DRC1_HI_COMP - [5:3] */
+#define ARIZONA_DRC1_LO_COMP_MASK                0x0007  /* DRC1_LO_COMP - [2:0] */
+#define ARIZONA_DRC1_LO_COMP_SHIFT                    0  /* DRC1_LO_COMP - [2:0] */
+#define ARIZONA_DRC1_LO_COMP_WIDTH                    3  /* DRC1_LO_COMP - [2:0] */
+
+/*
+ * R3715 (0xE83) - DRC1 ctrl4
+ */
+#define ARIZONA_DRC1_KNEE_IP_MASK                0x07E0  /* DRC1_KNEE_IP - [10:5] */
+#define ARIZONA_DRC1_KNEE_IP_SHIFT                    5  /* DRC1_KNEE_IP - [10:5] */
+#define ARIZONA_DRC1_KNEE_IP_WIDTH                    6  /* DRC1_KNEE_IP - [10:5] */
+#define ARIZONA_DRC1_KNEE_OP_MASK                0x001F  /* DRC1_KNEE_OP - [4:0] */
+#define ARIZONA_DRC1_KNEE_OP_SHIFT                    0  /* DRC1_KNEE_OP - [4:0] */
+#define ARIZONA_DRC1_KNEE_OP_WIDTH                    5  /* DRC1_KNEE_OP - [4:0] */
+
+/*
+ * R3716 (0xE84) - DRC1 ctrl5
+ */
+#define ARIZONA_DRC1_KNEE2_IP_MASK               0x03E0  /* DRC1_KNEE2_IP - [9:5] */
+#define ARIZONA_DRC1_KNEE2_IP_SHIFT                   5  /* DRC1_KNEE2_IP - [9:5] */
+#define ARIZONA_DRC1_KNEE2_IP_WIDTH                   5  /* DRC1_KNEE2_IP - [9:5] */
+#define ARIZONA_DRC1_KNEE2_OP_MASK               0x001F  /* DRC1_KNEE2_OP - [4:0] */
+#define ARIZONA_DRC1_KNEE2_OP_SHIFT                   0  /* DRC1_KNEE2_OP - [4:0] */
+#define ARIZONA_DRC1_KNEE2_OP_WIDTH                   5  /* DRC1_KNEE2_OP - [4:0] */
+
+/*
+ * R3721 (0xE89) - DRC2 ctrl1
+ */
+#define ARIZONA_DRC2_SIG_DET_RMS_MASK            0xF800  /* DRC2_SIG_DET_RMS - [15:11] */
+#define ARIZONA_DRC2_SIG_DET_RMS_SHIFT               11  /* DRC2_SIG_DET_RMS - [15:11] */
+#define ARIZONA_DRC2_SIG_DET_RMS_WIDTH                5  /* DRC2_SIG_DET_RMS - [15:11] */
+#define ARIZONA_DRC2_SIG_DET_PK_MASK             0x0600  /* DRC2_SIG_DET_PK - [10:9] */
+#define ARIZONA_DRC2_SIG_DET_PK_SHIFT                 9  /* DRC2_SIG_DET_PK - [10:9] */
+#define ARIZONA_DRC2_SIG_DET_PK_WIDTH                 2  /* DRC2_SIG_DET_PK - [10:9] */
+#define ARIZONA_DRC2_NG_ENA                      0x0100  /* DRC2_NG_ENA */
+#define ARIZONA_DRC2_NG_ENA_MASK                 0x0100  /* DRC2_NG_ENA */
+#define ARIZONA_DRC2_NG_ENA_SHIFT                     8  /* DRC2_NG_ENA */
+#define ARIZONA_DRC2_NG_ENA_WIDTH                     1  /* DRC2_NG_ENA */
+#define ARIZONA_DRC2_SIG_DET_MODE                0x0080  /* DRC2_SIG_DET_MODE */
+#define ARIZONA_DRC2_SIG_DET_MODE_MASK           0x0080  /* DRC2_SIG_DET_MODE */
+#define ARIZONA_DRC2_SIG_DET_MODE_SHIFT               7  /* DRC2_SIG_DET_MODE */
+#define ARIZONA_DRC2_SIG_DET_MODE_WIDTH               1  /* DRC2_SIG_DET_MODE */
+#define ARIZONA_DRC2_SIG_DET                     0x0040  /* DRC2_SIG_DET */
+#define ARIZONA_DRC2_SIG_DET_MASK                0x0040  /* DRC2_SIG_DET */
+#define ARIZONA_DRC2_SIG_DET_SHIFT                    6  /* DRC2_SIG_DET */
+#define ARIZONA_DRC2_SIG_DET_WIDTH                    1  /* DRC2_SIG_DET */
+#define ARIZONA_DRC2_KNEE2_OP_ENA                0x0020  /* DRC2_KNEE2_OP_ENA */
+#define ARIZONA_DRC2_KNEE2_OP_ENA_MASK           0x0020  /* DRC2_KNEE2_OP_ENA */
+#define ARIZONA_DRC2_KNEE2_OP_ENA_SHIFT               5  /* DRC2_KNEE2_OP_ENA */
+#define ARIZONA_DRC2_KNEE2_OP_ENA_WIDTH               1  /* DRC2_KNEE2_OP_ENA */
+#define ARIZONA_DRC2_QR                          0x0010  /* DRC2_QR */
+#define ARIZONA_DRC2_QR_MASK                     0x0010  /* DRC2_QR */
+#define ARIZONA_DRC2_QR_SHIFT                         4  /* DRC2_QR */
+#define ARIZONA_DRC2_QR_WIDTH                         1  /* DRC2_QR */
+#define ARIZONA_DRC2_ANTICLIP                    0x0008  /* DRC2_ANTICLIP */
+#define ARIZONA_DRC2_ANTICLIP_MASK               0x0008  /* DRC2_ANTICLIP */
+#define ARIZONA_DRC2_ANTICLIP_SHIFT                   3  /* DRC2_ANTICLIP */
+#define ARIZONA_DRC2_ANTICLIP_WIDTH                   1  /* DRC2_ANTICLIP */
+#define ARIZONA_DRC2L_ENA                        0x0002  /* DRC2L_ENA */
+#define ARIZONA_DRC2L_ENA_MASK                   0x0002  /* DRC2L_ENA */
+#define ARIZONA_DRC2L_ENA_SHIFT                       1  /* DRC2L_ENA */
+#define ARIZONA_DRC2L_ENA_WIDTH                       1  /* DRC2L_ENA */
+#define ARIZONA_DRC2R_ENA                        0x0001  /* DRC2R_ENA */
+#define ARIZONA_DRC2R_ENA_MASK                   0x0001  /* DRC2R_ENA */
+#define ARIZONA_DRC2R_ENA_SHIFT                       0  /* DRC2R_ENA */
+#define ARIZONA_DRC2R_ENA_WIDTH                       1  /* DRC2R_ENA */
+
+/*
+ * R3722 (0xE8A) - DRC2 ctrl2
+ */
+#define ARIZONA_DRC2_ATK_MASK                    0x1E00  /* DRC2_ATK - [12:9] */
+#define ARIZONA_DRC2_ATK_SHIFT                        9  /* DRC2_ATK - [12:9] */
+#define ARIZONA_DRC2_ATK_WIDTH                        4  /* DRC2_ATK - [12:9] */
+#define ARIZONA_DRC2_DCY_MASK                    0x01E0  /* DRC2_DCY - [8:5] */
+#define ARIZONA_DRC2_DCY_SHIFT                        5  /* DRC2_DCY - [8:5] */
+#define ARIZONA_DRC2_DCY_WIDTH                        4  /* DRC2_DCY - [8:5] */
+#define ARIZONA_DRC2_MINGAIN_MASK                0x001C  /* DRC2_MINGAIN - [4:2] */
+#define ARIZONA_DRC2_MINGAIN_SHIFT                    2  /* DRC2_MINGAIN - [4:2] */
+#define ARIZONA_DRC2_MINGAIN_WIDTH                    3  /* DRC2_MINGAIN - [4:2] */
+#define ARIZONA_DRC2_MAXGAIN_MASK                0x0003  /* DRC2_MAXGAIN - [1:0] */
+#define ARIZONA_DRC2_MAXGAIN_SHIFT                    0  /* DRC2_MAXGAIN - [1:0] */
+#define ARIZONA_DRC2_MAXGAIN_WIDTH                    2  /* DRC2_MAXGAIN - [1:0] */
+
+/*
+ * R3723 (0xE8B) - DRC2 ctrl3
+ */
+#define ARIZONA_DRC2_NG_MINGAIN_MASK             0xF000  /* DRC2_NG_MINGAIN - [15:12] */
+#define ARIZONA_DRC2_NG_MINGAIN_SHIFT                12  /* DRC2_NG_MINGAIN - [15:12] */
+#define ARIZONA_DRC2_NG_MINGAIN_WIDTH                 4  /* DRC2_NG_MINGAIN - [15:12] */
+#define ARIZONA_DRC2_NG_EXP_MASK                 0x0C00  /* DRC2_NG_EXP - [11:10] */
+#define ARIZONA_DRC2_NG_EXP_SHIFT                    10  /* DRC2_NG_EXP - [11:10] */
+#define ARIZONA_DRC2_NG_EXP_WIDTH                     2  /* DRC2_NG_EXP - [11:10] */
+#define ARIZONA_DRC2_QR_THR_MASK                 0x0300  /* DRC2_QR_THR - [9:8] */
+#define ARIZONA_DRC2_QR_THR_SHIFT                     8  /* DRC2_QR_THR - [9:8] */
+#define ARIZONA_DRC2_QR_THR_WIDTH                     2  /* DRC2_QR_THR - [9:8] */
+#define ARIZONA_DRC2_QR_DCY_MASK                 0x00C0  /* DRC2_QR_DCY - [7:6] */
+#define ARIZONA_DRC2_QR_DCY_SHIFT                     6  /* DRC2_QR_DCY - [7:6] */
+#define ARIZONA_DRC2_QR_DCY_WIDTH                     2  /* DRC2_QR_DCY - [7:6] */
+#define ARIZONA_DRC2_HI_COMP_MASK                0x0038  /* DRC2_HI_COMP - [5:3] */
+#define ARIZONA_DRC2_HI_COMP_SHIFT                    3  /* DRC2_HI_COMP - [5:3] */
+#define ARIZONA_DRC2_HI_COMP_WIDTH                    3  /* DRC2_HI_COMP - [5:3] */
+#define ARIZONA_DRC2_LO_COMP_MASK                0x0007  /* DRC2_LO_COMP - [2:0] */
+#define ARIZONA_DRC2_LO_COMP_SHIFT                    0  /* DRC2_LO_COMP - [2:0] */
+#define ARIZONA_DRC2_LO_COMP_WIDTH                    3  /* DRC2_LO_COMP - [2:0] */
+
+/*
+ * R3724 (0xE8C) - DRC2 ctrl4
+ */
+#define ARIZONA_DRC2_KNEE_IP_MASK                0x07E0  /* DRC2_KNEE_IP - [10:5] */
+#define ARIZONA_DRC2_KNEE_IP_SHIFT                    5  /* DRC2_KNEE_IP - [10:5] */
+#define ARIZONA_DRC2_KNEE_IP_WIDTH                    6  /* DRC2_KNEE_IP - [10:5] */
+#define ARIZONA_DRC2_KNEE_OP_MASK                0x001F  /* DRC2_KNEE_OP - [4:0] */
+#define ARIZONA_DRC2_KNEE_OP_SHIFT                    0  /* DRC2_KNEE_OP - [4:0] */
+#define ARIZONA_DRC2_KNEE_OP_WIDTH                    5  /* DRC2_KNEE_OP - [4:0] */
+
+/*
+ * R3725 (0xE8D) - DRC2 ctrl5
+ */
+#define ARIZONA_DRC2_KNEE2_IP_MASK               0x03E0  /* DRC2_KNEE2_IP - [9:5] */
+#define ARIZONA_DRC2_KNEE2_IP_SHIFT                   5  /* DRC2_KNEE2_IP - [9:5] */
+#define ARIZONA_DRC2_KNEE2_IP_WIDTH                   5  /* DRC2_KNEE2_IP - [9:5] */
+#define ARIZONA_DRC2_KNEE2_OP_MASK               0x001F  /* DRC2_KNEE2_OP - [4:0] */
+#define ARIZONA_DRC2_KNEE2_OP_SHIFT                   0  /* DRC2_KNEE2_OP - [4:0] */
+#define ARIZONA_DRC2_KNEE2_OP_WIDTH                   5  /* DRC2_KNEE2_OP - [4:0] */
+
+/*
+ * R3776 (0xEC0) - HPLPF1_1
+ */
+#define ARIZONA_LHPF1_MODE                       0x0002  /* LHPF1_MODE */
+#define ARIZONA_LHPF1_MODE_MASK                  0x0002  /* LHPF1_MODE */
+#define ARIZONA_LHPF1_MODE_SHIFT                      1  /* LHPF1_MODE */
+#define ARIZONA_LHPF1_MODE_WIDTH                      1  /* LHPF1_MODE */
+#define ARIZONA_LHPF1_ENA                        0x0001  /* LHPF1_ENA */
+#define ARIZONA_LHPF1_ENA_MASK                   0x0001  /* LHPF1_ENA */
+#define ARIZONA_LHPF1_ENA_SHIFT                       0  /* LHPF1_ENA */
+#define ARIZONA_LHPF1_ENA_WIDTH                       1  /* LHPF1_ENA */
+
+/*
+ * R3777 (0xEC1) - HPLPF1_2
+ */
+#define ARIZONA_LHPF1_COEFF_MASK                 0xFFFF  /* LHPF1_COEFF - [15:0] */
+#define ARIZONA_LHPF1_COEFF_SHIFT                     0  /* LHPF1_COEFF - [15:0] */
+#define ARIZONA_LHPF1_COEFF_WIDTH                    16  /* LHPF1_COEFF - [15:0] */
+
+/*
+ * R3780 (0xEC4) - HPLPF2_1
+ */
+#define ARIZONA_LHPF2_MODE                       0x0002  /* LHPF2_MODE */
+#define ARIZONA_LHPF2_MODE_MASK                  0x0002  /* LHPF2_MODE */
+#define ARIZONA_LHPF2_MODE_SHIFT                      1  /* LHPF2_MODE */
+#define ARIZONA_LHPF2_MODE_WIDTH                      1  /* LHPF2_MODE */
+#define ARIZONA_LHPF2_ENA                        0x0001  /* LHPF2_ENA */
+#define ARIZONA_LHPF2_ENA_MASK                   0x0001  /* LHPF2_ENA */
+#define ARIZONA_LHPF2_ENA_SHIFT                       0  /* LHPF2_ENA */
+#define ARIZONA_LHPF2_ENA_WIDTH                       1  /* LHPF2_ENA */
+
+/*
+ * R3781 (0xEC5) - HPLPF2_2
+ */
+#define ARIZONA_LHPF2_COEFF_MASK                 0xFFFF  /* LHPF2_COEFF - [15:0] */
+#define ARIZONA_LHPF2_COEFF_SHIFT                     0  /* LHPF2_COEFF - [15:0] */
+#define ARIZONA_LHPF2_COEFF_WIDTH                    16  /* LHPF2_COEFF - [15:0] */
+
+/*
+ * R3784 (0xEC8) - HPLPF3_1
+ */
+#define ARIZONA_LHPF3_MODE                       0x0002  /* LHPF3_MODE */
+#define ARIZONA_LHPF3_MODE_MASK                  0x0002  /* LHPF3_MODE */
+#define ARIZONA_LHPF3_MODE_SHIFT                      1  /* LHPF3_MODE */
+#define ARIZONA_LHPF3_MODE_WIDTH                      1  /* LHPF3_MODE */
+#define ARIZONA_LHPF3_ENA                        0x0001  /* LHPF3_ENA */
+#define ARIZONA_LHPF3_ENA_MASK                   0x0001  /* LHPF3_ENA */
+#define ARIZONA_LHPF3_ENA_SHIFT                       0  /* LHPF3_ENA */
+#define ARIZONA_LHPF3_ENA_WIDTH                       1  /* LHPF3_ENA */
+
+/*
+ * R3785 (0xEC9) - HPLPF3_2
+ */
+#define ARIZONA_LHPF3_COEFF_MASK                 0xFFFF  /* LHPF3_COEFF - [15:0] */
+#define ARIZONA_LHPF3_COEFF_SHIFT                     0  /* LHPF3_COEFF - [15:0] */
+#define ARIZONA_LHPF3_COEFF_WIDTH                    16  /* LHPF3_COEFF - [15:0] */
+
+/*
+ * R3788 (0xECC) - HPLPF4_1
+ */
+#define ARIZONA_LHPF4_MODE                       0x0002  /* LHPF4_MODE */
+#define ARIZONA_LHPF4_MODE_MASK                  0x0002  /* LHPF4_MODE */
+#define ARIZONA_LHPF4_MODE_SHIFT                      1  /* LHPF4_MODE */
+#define ARIZONA_LHPF4_MODE_WIDTH                      1  /* LHPF4_MODE */
+#define ARIZONA_LHPF4_ENA                        0x0001  /* LHPF4_ENA */
+#define ARIZONA_LHPF4_ENA_MASK                   0x0001  /* LHPF4_ENA */
+#define ARIZONA_LHPF4_ENA_SHIFT                       0  /* LHPF4_ENA */
+#define ARIZONA_LHPF4_ENA_WIDTH                       1  /* LHPF4_ENA */
+
+/*
+ * R3789 (0xECD) - HPLPF4_2
+ */
+#define ARIZONA_LHPF4_COEFF_MASK                 0xFFFF  /* LHPF4_COEFF - [15:0] */
+#define ARIZONA_LHPF4_COEFF_SHIFT                     0  /* LHPF4_COEFF - [15:0] */
+#define ARIZONA_LHPF4_COEFF_WIDTH                    16  /* LHPF4_COEFF - [15:0] */
+
+/*
+ * R3808 (0xEE0) - ASRC_ENABLE
+ */
+#define ARIZONA_ASRC2L_ENA                       0x0008  /* ASRC2L_ENA */
+#define ARIZONA_ASRC2L_ENA_MASK                  0x0008  /* ASRC2L_ENA */
+#define ARIZONA_ASRC2L_ENA_SHIFT                      3  /* ASRC2L_ENA */
+#define ARIZONA_ASRC2L_ENA_WIDTH                      1  /* ASRC2L_ENA */
+#define ARIZONA_ASRC2R_ENA                       0x0004  /* ASRC2R_ENA */
+#define ARIZONA_ASRC2R_ENA_MASK                  0x0004  /* ASRC2R_ENA */
+#define ARIZONA_ASRC2R_ENA_SHIFT                      2  /* ASRC2R_ENA */
+#define ARIZONA_ASRC2R_ENA_WIDTH                      1  /* ASRC2R_ENA */
+#define ARIZONA_ASRC1L_ENA                       0x0002  /* ASRC1L_ENA */
+#define ARIZONA_ASRC1L_ENA_MASK                  0x0002  /* ASRC1L_ENA */
+#define ARIZONA_ASRC1L_ENA_SHIFT                      1  /* ASRC1L_ENA */
+#define ARIZONA_ASRC1L_ENA_WIDTH                      1  /* ASRC1L_ENA */
+#define ARIZONA_ASRC1R_ENA                       0x0001  /* ASRC1R_ENA */
+#define ARIZONA_ASRC1R_ENA_MASK                  0x0001  /* ASRC1R_ENA */
+#define ARIZONA_ASRC1R_ENA_SHIFT                      0  /* ASRC1R_ENA */
+#define ARIZONA_ASRC1R_ENA_WIDTH                      1  /* ASRC1R_ENA */
+
+/*
+ * R3810 (0xEE2) - ASRC_RATE1
+ */
+#define ARIZONA_ASRC_RATE1_MASK                  0x7800  /* ASRC_RATE1 - [14:11] */
+#define ARIZONA_ASRC_RATE1_SHIFT                     11  /* ASRC_RATE1 - [14:11] */
+#define ARIZONA_ASRC_RATE1_WIDTH                      4  /* ASRC_RATE1 - [14:11] */
+
+/*
+ * R3811 (0xEE3) - ASRC_RATE2
+ */
+#define ARIZONA_ASRC_RATE2_MASK                  0x7800  /* ASRC_RATE2 - [14:11] */
+#define ARIZONA_ASRC_RATE2_SHIFT                     11  /* ASRC_RATE2 - [14:11] */
+#define ARIZONA_ASRC_RATE2_WIDTH                      4  /* ASRC_RATE2 - [14:11] */
+
+/*
+ * R3824 (0xEF0) - ISRC 1 CTRL 1
+ */
+#define ARIZONA_ISRC1_FSH_MASK                   0x7800  /* ISRC1_FSH - [14:11] */
+#define ARIZONA_ISRC1_FSH_SHIFT                      11  /* ISRC1_FSH - [14:11] */
+#define ARIZONA_ISRC1_FSH_WIDTH                       4  /* ISRC1_FSH - [14:11] */
+#define ARIZONA_ISRC1_CLK_SEL_MASK               0x0700  /* ISRC1_CLK_SEL - [10:8] */
+#define ARIZONA_ISRC1_CLK_SEL_SHIFT                   8  /* ISRC1_CLK_SEL - [10:8] */
+#define ARIZONA_ISRC1_CLK_SEL_WIDTH                   3  /* ISRC1_CLK_SEL - [10:8] */
+
+/*
+ * R3825 (0xEF1) - ISRC 1 CTRL 2
+ */
+#define ARIZONA_ISRC1_FSL_MASK                   0x7800  /* ISRC1_FSL - [14:11] */
+#define ARIZONA_ISRC1_FSL_SHIFT                      11  /* ISRC1_FSL - [14:11] */
+#define ARIZONA_ISRC1_FSL_WIDTH                       4  /* ISRC1_FSL - [14:11] */
+
+/*
+ * R3826 (0xEF2) - ISRC 1 CTRL 3
+ */
+#define ARIZONA_ISRC1_INT0_ENA                   0x8000  /* ISRC1_INT0_ENA */
+#define ARIZONA_ISRC1_INT0_ENA_MASK              0x8000  /* ISRC1_INT0_ENA */
+#define ARIZONA_ISRC1_INT0_ENA_SHIFT                 15  /* ISRC1_INT0_ENA */
+#define ARIZONA_ISRC1_INT0_ENA_WIDTH                  1  /* ISRC1_INT0_ENA */
+#define ARIZONA_ISRC1_INT1_ENA                   0x4000  /* ISRC1_INT1_ENA */
+#define ARIZONA_ISRC1_INT1_ENA_MASK              0x4000  /* ISRC1_INT1_ENA */
+#define ARIZONA_ISRC1_INT1_ENA_SHIFT                 14  /* ISRC1_INT1_ENA */
+#define ARIZONA_ISRC1_INT1_ENA_WIDTH                  1  /* ISRC1_INT1_ENA */
+#define ARIZONA_ISRC1_INT2_ENA                   0x2000  /* ISRC1_INT2_ENA */
+#define ARIZONA_ISRC1_INT2_ENA_MASK              0x2000  /* ISRC1_INT2_ENA */
+#define ARIZONA_ISRC1_INT2_ENA_SHIFT                 13  /* ISRC1_INT2_ENA */
+#define ARIZONA_ISRC1_INT2_ENA_WIDTH                  1  /* ISRC1_INT2_ENA */
+#define ARIZONA_ISRC1_INT3_ENA                   0x1000  /* ISRC1_INT3_ENA */
+#define ARIZONA_ISRC1_INT3_ENA_MASK              0x1000  /* ISRC1_INT3_ENA */
+#define ARIZONA_ISRC1_INT3_ENA_SHIFT                 12  /* ISRC1_INT3_ENA */
+#define ARIZONA_ISRC1_INT3_ENA_WIDTH                  1  /* ISRC1_INT3_ENA */
+#define ARIZONA_ISRC1_DEC0_ENA                   0x0200  /* ISRC1_DEC0_ENA */
+#define ARIZONA_ISRC1_DEC0_ENA_MASK              0x0200  /* ISRC1_DEC0_ENA */
+#define ARIZONA_ISRC1_DEC0_ENA_SHIFT                  9  /* ISRC1_DEC0_ENA */
+#define ARIZONA_ISRC1_DEC0_ENA_WIDTH                  1  /* ISRC1_DEC0_ENA */
+#define ARIZONA_ISRC1_DEC1_ENA                   0x0100  /* ISRC1_DEC1_ENA */
+#define ARIZONA_ISRC1_DEC1_ENA_MASK              0x0100  /* ISRC1_DEC1_ENA */
+#define ARIZONA_ISRC1_DEC1_ENA_SHIFT                  8  /* ISRC1_DEC1_ENA */
+#define ARIZONA_ISRC1_DEC1_ENA_WIDTH                  1  /* ISRC1_DEC1_ENA */
+#define ARIZONA_ISRC1_DEC2_ENA                   0x0080  /* ISRC1_DEC2_ENA */
+#define ARIZONA_ISRC1_DEC2_ENA_MASK              0x0080  /* ISRC1_DEC2_ENA */
+#define ARIZONA_ISRC1_DEC2_ENA_SHIFT                  7  /* ISRC1_DEC2_ENA */
+#define ARIZONA_ISRC1_DEC2_ENA_WIDTH                  1  /* ISRC1_DEC2_ENA */
+#define ARIZONA_ISRC1_DEC3_ENA                   0x0040  /* ISRC1_DEC3_ENA */
+#define ARIZONA_ISRC1_DEC3_ENA_MASK              0x0040  /* ISRC1_DEC3_ENA */
+#define ARIZONA_ISRC1_DEC3_ENA_SHIFT                  6  /* ISRC1_DEC3_ENA */
+#define ARIZONA_ISRC1_DEC3_ENA_WIDTH                  1  /* ISRC1_DEC3_ENA */
+#define ARIZONA_ISRC1_NOTCH_ENA                  0x0001  /* ISRC1_NOTCH_ENA */
+#define ARIZONA_ISRC1_NOTCH_ENA_MASK             0x0001  /* ISRC1_NOTCH_ENA */
+#define ARIZONA_ISRC1_NOTCH_ENA_SHIFT                 0  /* ISRC1_NOTCH_ENA */
+#define ARIZONA_ISRC1_NOTCH_ENA_WIDTH                 1  /* ISRC1_NOTCH_ENA */
+
+/*
+ * R3827 (0xEF3) - ISRC 2 CTRL 1
+ */
+#define ARIZONA_ISRC2_FSH_MASK                   0x7800  /* ISRC2_FSH - [14:11] */
+#define ARIZONA_ISRC2_FSH_SHIFT                      11  /* ISRC2_FSH - [14:11] */
+#define ARIZONA_ISRC2_FSH_WIDTH                       4  /* ISRC2_FSH - [14:11] */
+#define ARIZONA_ISRC2_CLK_SEL_MASK               0x0700  /* ISRC2_CLK_SEL - [10:8] */
+#define ARIZONA_ISRC2_CLK_SEL_SHIFT                   8  /* ISRC2_CLK_SEL - [10:8] */
+#define ARIZONA_ISRC2_CLK_SEL_WIDTH                   3  /* ISRC2_CLK_SEL - [10:8] */
+
+/*
+ * R3828 (0xEF4) - ISRC 2 CTRL 2
+ */
+#define ARIZONA_ISRC2_FSL_MASK                   0x7800  /* ISRC2_FSL - [14:11] */
+#define ARIZONA_ISRC2_FSL_SHIFT                      11  /* ISRC2_FSL - [14:11] */
+#define ARIZONA_ISRC2_FSL_WIDTH                       4  /* ISRC2_FSL - [14:11] */
+
+/*
+ * R3829 (0xEF5) - ISRC 2 CTRL 3
+ */
+#define ARIZONA_ISRC2_INT0_ENA                   0x8000  /* ISRC2_INT0_ENA */
+#define ARIZONA_ISRC2_INT0_ENA_MASK              0x8000  /* ISRC2_INT0_ENA */
+#define ARIZONA_ISRC2_INT0_ENA_SHIFT                 15  /* ISRC2_INT0_ENA */
+#define ARIZONA_ISRC2_INT0_ENA_WIDTH                  1  /* ISRC2_INT0_ENA */
+#define ARIZONA_ISRC2_INT1_ENA                   0x4000  /* ISRC2_INT1_ENA */
+#define ARIZONA_ISRC2_INT1_ENA_MASK              0x4000  /* ISRC2_INT1_ENA */
+#define ARIZONA_ISRC2_INT1_ENA_SHIFT                 14  /* ISRC2_INT1_ENA */
+#define ARIZONA_ISRC2_INT1_ENA_WIDTH                  1  /* ISRC2_INT1_ENA */
+#define ARIZONA_ISRC2_INT2_ENA                   0x2000  /* ISRC2_INT2_ENA */
+#define ARIZONA_ISRC2_INT2_ENA_MASK              0x2000  /* ISRC2_INT2_ENA */
+#define ARIZONA_ISRC2_INT2_ENA_SHIFT                 13  /* ISRC2_INT2_ENA */
+#define ARIZONA_ISRC2_INT2_ENA_WIDTH                  1  /* ISRC2_INT2_ENA */
+#define ARIZONA_ISRC2_INT3_ENA                   0x1000  /* ISRC2_INT3_ENA */
+#define ARIZONA_ISRC2_INT3_ENA_MASK              0x1000  /* ISRC2_INT3_ENA */
+#define ARIZONA_ISRC2_INT3_ENA_SHIFT                 12  /* ISRC2_INT3_ENA */
+#define ARIZONA_ISRC2_INT3_ENA_WIDTH                  1  /* ISRC2_INT3_ENA */
+#define ARIZONA_ISRC2_DEC0_ENA                   0x0200  /* ISRC2_DEC0_ENA */
+#define ARIZONA_ISRC2_DEC0_ENA_MASK              0x0200  /* ISRC2_DEC0_ENA */
+#define ARIZONA_ISRC2_DEC0_ENA_SHIFT                  9  /* ISRC2_DEC0_ENA */
+#define ARIZONA_ISRC2_DEC0_ENA_WIDTH                  1  /* ISRC2_DEC0_ENA */
+#define ARIZONA_ISRC2_DEC1_ENA                   0x0100  /* ISRC2_DEC1_ENA */
+#define ARIZONA_ISRC2_DEC1_ENA_MASK              0x0100  /* ISRC2_DEC1_ENA */
+#define ARIZONA_ISRC2_DEC1_ENA_SHIFT                  8  /* ISRC2_DEC1_ENA */
+#define ARIZONA_ISRC2_DEC1_ENA_WIDTH                  1  /* ISRC2_DEC1_ENA */
+#define ARIZONA_ISRC2_DEC2_ENA                   0x0080  /* ISRC2_DEC2_ENA */
+#define ARIZONA_ISRC2_DEC2_ENA_MASK              0x0080  /* ISRC2_DEC2_ENA */
+#define ARIZONA_ISRC2_DEC2_ENA_SHIFT                  7  /* ISRC2_DEC2_ENA */
+#define ARIZONA_ISRC2_DEC2_ENA_WIDTH                  1  /* ISRC2_DEC2_ENA */
+#define ARIZONA_ISRC2_DEC3_ENA                   0x0040  /* ISRC2_DEC3_ENA */
+#define ARIZONA_ISRC2_DEC3_ENA_MASK              0x0040  /* ISRC2_DEC3_ENA */
+#define ARIZONA_ISRC2_DEC3_ENA_SHIFT                  6  /* ISRC2_DEC3_ENA */
+#define ARIZONA_ISRC2_DEC3_ENA_WIDTH                  1  /* ISRC2_DEC3_ENA */
+#define ARIZONA_ISRC2_NOTCH_ENA                  0x0001  /* ISRC2_NOTCH_ENA */
+#define ARIZONA_ISRC2_NOTCH_ENA_MASK             0x0001  /* ISRC2_NOTCH_ENA */
+#define ARIZONA_ISRC2_NOTCH_ENA_SHIFT                 0  /* ISRC2_NOTCH_ENA */
+#define ARIZONA_ISRC2_NOTCH_ENA_WIDTH                 1  /* ISRC2_NOTCH_ENA */
+
+/*
+ * R3830 (0xEF6) - ISRC 3 CTRL 1
+ */
+#define ARIZONA_ISRC3_FSH_MASK                   0x7800  /* ISRC3_FSH - [14:11] */
+#define ARIZONA_ISRC3_FSH_SHIFT                      11  /* ISRC3_FSH - [14:11] */
+#define ARIZONA_ISRC3_FSH_WIDTH                       4  /* ISRC3_FSH - [14:11] */
+#define ARIZONA_ISRC3_CLK_SEL_MASK               0x0700  /* ISRC3_CLK_SEL - [10:8] */
+#define ARIZONA_ISRC3_CLK_SEL_SHIFT                   8  /* ISRC3_CLK_SEL - [10:8] */
+#define ARIZONA_ISRC3_CLK_SEL_WIDTH                   3  /* ISRC3_CLK_SEL - [10:8] */
+
+/*
+ * R3831 (0xEF7) - ISRC 3 CTRL 2
+ */
+#define ARIZONA_ISRC3_FSL_MASK                   0x7800  /* ISRC3_FSL - [14:11] */
+#define ARIZONA_ISRC3_FSL_SHIFT                      11  /* ISRC3_FSL - [14:11] */
+#define ARIZONA_ISRC3_FSL_WIDTH                       4  /* ISRC3_FSL - [14:11] */
+
+/*
+ * R3832 (0xEF8) - ISRC 3 CTRL 3
+ */
+#define ARIZONA_ISRC3_INT0_ENA                   0x8000  /* ISRC3_INT0_ENA */
+#define ARIZONA_ISRC3_INT0_ENA_MASK              0x8000  /* ISRC3_INT0_ENA */
+#define ARIZONA_ISRC3_INT0_ENA_SHIFT                 15  /* ISRC3_INT0_ENA */
+#define ARIZONA_ISRC3_INT0_ENA_WIDTH                  1  /* ISRC3_INT0_ENA */
+#define ARIZONA_ISRC3_INT1_ENA                   0x4000  /* ISRC3_INT1_ENA */
+#define ARIZONA_ISRC3_INT1_ENA_MASK              0x4000  /* ISRC3_INT1_ENA */
+#define ARIZONA_ISRC3_INT1_ENA_SHIFT                 14  /* ISRC3_INT1_ENA */
+#define ARIZONA_ISRC3_INT1_ENA_WIDTH                  1  /* ISRC3_INT1_ENA */
+#define ARIZONA_ISRC3_INT2_ENA                   0x2000  /* ISRC3_INT2_ENA */
+#define ARIZONA_ISRC3_INT2_ENA_MASK              0x2000  /* ISRC3_INT2_ENA */
+#define ARIZONA_ISRC3_INT2_ENA_SHIFT                 13  /* ISRC3_INT2_ENA */
+#define ARIZONA_ISRC3_INT2_ENA_WIDTH                  1  /* ISRC3_INT2_ENA */
+#define ARIZONA_ISRC3_INT3_ENA                   0x1000  /* ISRC3_INT3_ENA */
+#define ARIZONA_ISRC3_INT3_ENA_MASK              0x1000  /* ISRC3_INT3_ENA */
+#define ARIZONA_ISRC3_INT3_ENA_SHIFT                 12  /* ISRC3_INT3_ENA */
+#define ARIZONA_ISRC3_INT3_ENA_WIDTH                  1  /* ISRC3_INT3_ENA */
+#define ARIZONA_ISRC3_DEC0_ENA                   0x0200  /* ISRC3_DEC0_ENA */
+#define ARIZONA_ISRC3_DEC0_ENA_MASK              0x0200  /* ISRC3_DEC0_ENA */
+#define ARIZONA_ISRC3_DEC0_ENA_SHIFT                  9  /* ISRC3_DEC0_ENA */
+#define ARIZONA_ISRC3_DEC0_ENA_WIDTH                  1  /* ISRC3_DEC0_ENA */
+#define ARIZONA_ISRC3_DEC1_ENA                   0x0100  /* ISRC3_DEC1_ENA */
+#define ARIZONA_ISRC3_DEC1_ENA_MASK              0x0100  /* ISRC3_DEC1_ENA */
+#define ARIZONA_ISRC3_DEC1_ENA_SHIFT                  8  /* ISRC3_DEC1_ENA */
+#define ARIZONA_ISRC3_DEC1_ENA_WIDTH                  1  /* ISRC3_DEC1_ENA */
+#define ARIZONA_ISRC3_DEC2_ENA                   0x0080  /* ISRC3_DEC2_ENA */
+#define ARIZONA_ISRC3_DEC2_ENA_MASK              0x0080  /* ISRC3_DEC2_ENA */
+#define ARIZONA_ISRC3_DEC2_ENA_SHIFT                  7  /* ISRC3_DEC2_ENA */
+#define ARIZONA_ISRC3_DEC2_ENA_WIDTH                  1  /* ISRC3_DEC2_ENA */
+#define ARIZONA_ISRC3_DEC3_ENA                   0x0040  /* ISRC3_DEC3_ENA */
+#define ARIZONA_ISRC3_DEC3_ENA_MASK              0x0040  /* ISRC3_DEC3_ENA */
+#define ARIZONA_ISRC3_DEC3_ENA_SHIFT                  6  /* ISRC3_DEC3_ENA */
+#define ARIZONA_ISRC3_DEC3_ENA_WIDTH                  1  /* ISRC3_DEC3_ENA */
+#define ARIZONA_ISRC3_NOTCH_ENA                  0x0001  /* ISRC3_NOTCH_ENA */
+#define ARIZONA_ISRC3_NOTCH_ENA_MASK             0x0001  /* ISRC3_NOTCH_ENA */
+#define ARIZONA_ISRC3_NOTCH_ENA_SHIFT                 0  /* ISRC3_NOTCH_ENA */
+#define ARIZONA_ISRC3_NOTCH_ENA_WIDTH                 1  /* ISRC3_NOTCH_ENA */
+
+/*
+ * R4352 (0x1100) - DSP1 Control 1
+ */
+#define ARIZONA_DSP1_RATE_MASK                   0x7800  /* DSP1_RATE - [14:11] */
+#define ARIZONA_DSP1_RATE_SHIFT                      11  /* DSP1_RATE - [14:11] */
+#define ARIZONA_DSP1_RATE_WIDTH                       4  /* DSP1_RATE - [14:11] */
+#define ARIZONA_DSP1_MEM_ENA                     0x0010  /* DSP1_MEM_ENA */
+#define ARIZONA_DSP1_MEM_ENA_MASK                0x0010  /* DSP1_MEM_ENA */
+#define ARIZONA_DSP1_MEM_ENA_SHIFT                    4  /* DSP1_MEM_ENA */
+#define ARIZONA_DSP1_MEM_ENA_WIDTH                    1  /* DSP1_MEM_ENA */
+#define ARIZONA_DSP1_SYS_ENA                     0x0004  /* DSP1_SYS_ENA */
+#define ARIZONA_DSP1_SYS_ENA_MASK                0x0004  /* DSP1_SYS_ENA */
+#define ARIZONA_DSP1_SYS_ENA_SHIFT                    2  /* DSP1_SYS_ENA */
+#define ARIZONA_DSP1_SYS_ENA_WIDTH                    1  /* DSP1_SYS_ENA */
+#define ARIZONA_DSP1_CORE_ENA                    0x0002  /* DSP1_CORE_ENA */
+#define ARIZONA_DSP1_CORE_ENA_MASK               0x0002  /* DSP1_CORE_ENA */
+#define ARIZONA_DSP1_CORE_ENA_SHIFT                   1  /* DSP1_CORE_ENA */
+#define ARIZONA_DSP1_CORE_ENA_WIDTH                   1  /* DSP1_CORE_ENA */
+#define ARIZONA_DSP1_START                       0x0001  /* DSP1_START */
+#define ARIZONA_DSP1_START_MASK                  0x0001  /* DSP1_START */
+#define ARIZONA_DSP1_START_SHIFT                      0  /* DSP1_START */
+#define ARIZONA_DSP1_START_WIDTH                      1  /* DSP1_START */
+
+/*
+ * R4353 (0x1101) - DSP1 Clocking 1
+ */
+#define ARIZONA_DSP1_CLK_SEL_MASK                0x0007  /* DSP1_CLK_SEL - [2:0] */
+#define ARIZONA_DSP1_CLK_SEL_SHIFT                    0  /* DSP1_CLK_SEL - [2:0] */
+#define ARIZONA_DSP1_CLK_SEL_WIDTH                    3  /* DSP1_CLK_SEL - [2:0] */
+
+/*
+ * R4356 (0x1104) - DSP1 Status 1
+ */
+#define ARIZONA_DSP1_RAM_RDY                     0x0001  /* DSP1_RAM_RDY */
+#define ARIZONA_DSP1_RAM_RDY_MASK                0x0001  /* DSP1_RAM_RDY */
+#define ARIZONA_DSP1_RAM_RDY_SHIFT                    0  /* DSP1_RAM_RDY */
+#define ARIZONA_DSP1_RAM_RDY_WIDTH                    1  /* DSP1_RAM_RDY */
+
+/*
+ * R4357 (0x1105) - DSP1 Status 2
+ */
+#define ARIZONA_DSP1_PING_FULL                   0x8000  /* DSP1_PING_FULL */
+#define ARIZONA_DSP1_PING_FULL_MASK              0x8000  /* DSP1_PING_FULL */
+#define ARIZONA_DSP1_PING_FULL_SHIFT                 15  /* DSP1_PING_FULL */
+#define ARIZONA_DSP1_PING_FULL_WIDTH                  1  /* DSP1_PING_FULL */
+#define ARIZONA_DSP1_PONG_FULL                   0x4000  /* DSP1_PONG_FULL */
+#define ARIZONA_DSP1_PONG_FULL_MASK              0x4000  /* DSP1_PONG_FULL */
+#define ARIZONA_DSP1_PONG_FULL_SHIFT                 14  /* DSP1_PONG_FULL */
+#define ARIZONA_DSP1_PONG_FULL_WIDTH                  1  /* DSP1_PONG_FULL */
+#define ARIZONA_DSP1_WDMA_ACTIVE_CHANNELS_MASK   0x00FF  /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define ARIZONA_DSP1_WDMA_ACTIVE_CHANNELS_SHIFT       0  /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */
+#define ARIZONA_DSP1_WDMA_ACTIVE_CHANNELS_WIDTH       8  /* DSP1_WDMA_ACTIVE_CHANNELS - [7:0] */
+
+#endif
index 4e76163dd8624dec3dba23b7bdebb32ce8ad2d11..3a8435a8058f1cec9357b3f980efb0eae18f5569 100644 (file)
@@ -36,6 +36,11 @@ struct mfd_cell {
        /* platform data passed to the sub devices drivers */
        void                    *platform_data;
        size_t                  pdata_size;
+       /*
+        * Device Tree compatible string
+        * See: Documentation/devicetree/usage-model.txt Chapter 2.2 for details
+        */
+       const char              *of_compatible;
 
        /*
         * These resources can be specified relative to the parent device.
index b3a43b1263fead2092a4bffd7b87d878e5c0cbb5..b82f6ee66a0bb21849777fddbdffdc3585ca03d1 100644 (file)
@@ -530,7 +530,7 @@ int db8500_prcmu_stop_temp_sense(void);
 int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
 int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
 
-void prcmu_ac_wake_req(void);
+int prcmu_ac_wake_req(void);
 void prcmu_ac_sleep_req(void);
 void db8500_prcmu_modem_reset(void);
 
@@ -680,7 +680,10 @@ static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
        return -ENOSYS;
 }
 
-static inline void prcmu_ac_wake_req(void) {}
+static inline int prcmu_ac_wake_req(void)
+{
+       return 0;
+}
 
 static inline void prcmu_ac_sleep_req(void) {}
 
index 5a13f93d8f1c97325ceb3d562ab0741c9ededdee..5b90e94399e1b2d8707885ee85be713b9288ab57 100644 (file)
@@ -345,7 +345,7 @@ static inline u16 prcmu_get_reset_code(void)
        return db8500_prcmu_get_reset_code();
 }
 
-void prcmu_ac_wake_req(void);
+int prcmu_ac_wake_req(void);
 void prcmu_ac_sleep_req(void);
 static inline void prcmu_modem_reset(void)
 {
@@ -533,7 +533,10 @@ static inline u16 prcmu_get_reset_code(void)
        return 0;
 }
 
-static inline void prcmu_ac_wake_req(void) {}
+static inline int prcmu_ac_wake_req(void)
+{
+       return 0;
+}
 
 static inline void prcmu_ac_sleep_req(void) {}
 
diff --git a/include/linux/mfd/max77686-private.h b/include/linux/mfd/max77686-private.h
new file mode 100644 (file)
index 0000000..d327d49
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * max77686.h - Voltage regulator driver for the Maxim 77686
+ *
+ *  Copyright (C) 2012 Samsung Electrnoics
+ *  Chiwoong Byun <woong.byun@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LINUX_MFD_MAX77686_PRIV_H
+#define __LINUX_MFD_MAX77686_PRIV_H
+
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+
+#define MAX77686_REG_INVALID           (0xff)
+
+enum max77686_pmic_reg {
+       MAX77686_REG_DEVICE_ID          = 0x00,
+       MAX77686_REG_INTSRC             = 0x01,
+       MAX77686_REG_INT1               = 0x02,
+       MAX77686_REG_INT2               = 0x03,
+
+       MAX77686_REG_INT1MSK            = 0x04,
+       MAX77686_REG_INT2MSK            = 0x05,
+
+       MAX77686_REG_STATUS1            = 0x06,
+       MAX77686_REG_STATUS2            = 0x07,
+
+       MAX77686_REG_PWRON              = 0x08,
+       MAX77686_REG_ONOFF_DELAY        = 0x09,
+       MAX77686_REG_MRSTB              = 0x0A,
+       /* Reserved: 0x0B-0x0F */
+
+       MAX77686_REG_BUCK1CTRL          = 0x10,
+       MAX77686_REG_BUCK1OUT           = 0x11,
+       MAX77686_REG_BUCK2CTRL1         = 0x12,
+       MAX77686_REG_BUCK234FREQ        = 0x13,
+       MAX77686_REG_BUCK2DVS1          = 0x14,
+       MAX77686_REG_BUCK2DVS2          = 0x15,
+       MAX77686_REG_BUCK2DVS3          = 0x16,
+       MAX77686_REG_BUCK2DVS4          = 0x17,
+       MAX77686_REG_BUCK2DVS5          = 0x18,
+       MAX77686_REG_BUCK2DVS6          = 0x19,
+       MAX77686_REG_BUCK2DVS7          = 0x1A,
+       MAX77686_REG_BUCK2DVS8          = 0x1B,
+       MAX77686_REG_BUCK3CTRL1         = 0x1C,
+       /* Reserved: 0x1D */
+       MAX77686_REG_BUCK3DVS1          = 0x1E,
+       MAX77686_REG_BUCK3DVS2          = 0x1F,
+       MAX77686_REG_BUCK3DVS3          = 0x20,
+       MAX77686_REG_BUCK3DVS4          = 0x21,
+       MAX77686_REG_BUCK3DVS5          = 0x22,
+       MAX77686_REG_BUCK3DVS6          = 0x23,
+       MAX77686_REG_BUCK3DVS7          = 0x24,
+       MAX77686_REG_BUCK3DVS8          = 0x25,
+       MAX77686_REG_BUCK4CTRL1         = 0x26,
+       /* Reserved: 0x27 */
+       MAX77686_REG_BUCK4DVS1          = 0x28,
+       MAX77686_REG_BUCK4DVS2          = 0x29,
+       MAX77686_REG_BUCK4DVS3          = 0x2A,
+       MAX77686_REG_BUCK4DVS4          = 0x2B,
+       MAX77686_REG_BUCK4DVS5          = 0x2C,
+       MAX77686_REG_BUCK4DVS6          = 0x2D,
+       MAX77686_REG_BUCK4DVS7          = 0x2E,
+       MAX77686_REG_BUCK4DVS8          = 0x2F,
+       MAX77686_REG_BUCK5CTRL          = 0x30,
+       MAX77686_REG_BUCK5OUT           = 0x31,
+       MAX77686_REG_BUCK6CTRL          = 0x32,
+       MAX77686_REG_BUCK6OUT           = 0x33,
+       MAX77686_REG_BUCK7CTRL          = 0x34,
+       MAX77686_REG_BUCK7OUT           = 0x35,
+       MAX77686_REG_BUCK8CTRL          = 0x36,
+       MAX77686_REG_BUCK8OUT           = 0x37,
+       MAX77686_REG_BUCK9CTRL          = 0x38,
+       MAX77686_REG_BUCK9OUT           = 0x39,
+       /* Reserved: 0x3A-0x3F */
+
+       MAX77686_REG_LDO1CTRL1          = 0x40,
+       MAX77686_REG_LDO2CTRL1          = 0x41,
+       MAX77686_REG_LDO3CTRL1          = 0x42,
+       MAX77686_REG_LDO4CTRL1          = 0x43,
+       MAX77686_REG_LDO5CTRL1          = 0x44,
+       MAX77686_REG_LDO6CTRL1          = 0x45,
+       MAX77686_REG_LDO7CTRL1          = 0x46,
+       MAX77686_REG_LDO8CTRL1          = 0x47,
+       MAX77686_REG_LDO9CTRL1          = 0x48,
+       MAX77686_REG_LDO10CTRL1         = 0x49,
+       MAX77686_REG_LDO11CTRL1         = 0x4A,
+       MAX77686_REG_LDO12CTRL1         = 0x4B,
+       MAX77686_REG_LDO13CTRL1         = 0x4C,
+       MAX77686_REG_LDO14CTRL1         = 0x4D,
+       MAX77686_REG_LDO15CTRL1         = 0x4E,
+       MAX77686_REG_LDO16CTRL1         = 0x4F,
+       MAX77686_REG_LDO17CTRL1         = 0x50,
+       MAX77686_REG_LDO18CTRL1         = 0x51,
+       MAX77686_REG_LDO19CTRL1         = 0x52,
+       MAX77686_REG_LDO20CTRL1         = 0x53,
+       MAX77686_REG_LDO21CTRL1         = 0x54,
+       MAX77686_REG_LDO22CTRL1         = 0x55,
+       MAX77686_REG_LDO23CTRL1         = 0x56,
+       MAX77686_REG_LDO24CTRL1         = 0x57,
+       MAX77686_REG_LDO25CTRL1         = 0x58,
+       MAX77686_REG_LDO26CTRL1         = 0x59,
+       /* Reserved: 0x5A-0x5F */
+       MAX77686_REG_LDO1CTRL2          = 0x60,
+       MAX77686_REG_LDO2CTRL2          = 0x61,
+       MAX77686_REG_LDO3CTRL2          = 0x62,
+       MAX77686_REG_LDO4CTRL2          = 0x63,
+       MAX77686_REG_LDO5CTRL2          = 0x64,
+       MAX77686_REG_LDO6CTRL2          = 0x65,
+       MAX77686_REG_LDO7CTRL2          = 0x66,
+       MAX77686_REG_LDO8CTRL2          = 0x67,
+       MAX77686_REG_LDO9CTRL2          = 0x68,
+       MAX77686_REG_LDO10CTRL2         = 0x69,
+       MAX77686_REG_LDO11CTRL2         = 0x6A,
+       MAX77686_REG_LDO12CTRL2         = 0x6B,
+       MAX77686_REG_LDO13CTRL2         = 0x6C,
+       MAX77686_REG_LDO14CTRL2         = 0x6D,
+       MAX77686_REG_LDO15CTRL2         = 0x6E,
+       MAX77686_REG_LDO16CTRL2         = 0x6F,
+       MAX77686_REG_LDO17CTRL2         = 0x70,
+       MAX77686_REG_LDO18CTRL2         = 0x71,
+       MAX77686_REG_LDO19CTRL2         = 0x72,
+       MAX77686_REG_LDO20CTRL2         = 0x73,
+       MAX77686_REG_LDO21CTRL2         = 0x74,
+       MAX77686_REG_LDO22CTRL2         = 0x75,
+       MAX77686_REG_LDO23CTRL2         = 0x76,
+       MAX77686_REG_LDO24CTRL2         = 0x77,
+       MAX77686_REG_LDO25CTRL2         = 0x78,
+       MAX77686_REG_LDO26CTRL2         = 0x79,
+       /* Reserved: 0x7A-0x7D */
+
+       MAX77686_REG_BBAT_CHG           = 0x7E,
+       MAX77686_REG_32KHZ                      = 0x7F,
+
+       MAX77686_REG_PMIC_END           = 0x80,
+};
+
+enum max77686_rtc_reg {
+       MAX77686_RTC_INT                        = 0x00,
+       MAX77686_RTC_INTM                       = 0x01,
+       MAX77686_RTC_CONTROLM           = 0x02,
+       MAX77686_RTC_CONTROL            = 0x03,
+       MAX77686_RTC_UPDATE0            = 0x04,
+       /* Reserved: 0x5 */
+       MAX77686_WTSR_SMPL_CNTL         = 0x06,
+       MAX77686_RTC_SEC                        = 0x07,
+       MAX77686_RTC_MIN                        = 0x08,
+       MAX77686_RTC_HOUR                       = 0x09,
+       MAX77686_RTC_WEEKDAY            = 0x0A,
+       MAX77686_RTC_MONTH                      = 0x0B,
+       MAX77686_RTC_YEAR                       = 0x0C,
+       MAX77686_RTC_DATE                       = 0x0D,
+       MAX77686_ALARM1_SEC                     = 0x0E,
+       MAX77686_ALARM1_MIN                     = 0x0F,
+       MAX77686_ALARM1_HOUR            = 0x10,
+       MAX77686_ALARM1_WEEKDAY         = 0x11,
+       MAX77686_ALARM1_MONTH           = 0x12,
+       MAX77686_ALARM1_YEAR            = 0x13,
+       MAX77686_ALARM1_DATE            = 0x14,
+       MAX77686_ALARM2_SEC                     = 0x15,
+       MAX77686_ALARM2_MIN                     = 0x16,
+       MAX77686_ALARM2_HOUR            = 0x17,
+       MAX77686_ALARM2_WEEKDAY         = 0x18,
+       MAX77686_ALARM2_MONTH           = 0x19,
+       MAX77686_ALARM2_YEAR            = 0x1A,
+       MAX77686_ALARM2_DATE            = 0x1B,
+};
+
+#define MAX77686_IRQSRC_PMIC   (0)
+#define MAX77686_IRQSRC_RTC            (1 << 0)
+
+enum max77686_irq_source {
+       PMIC_INT1 = 0,
+       PMIC_INT2,
+       RTC_INT,
+
+       MAX77686_IRQ_GROUP_NR,
+};
+
+enum max77686_irq {
+       MAX77686_PMICIRQ_PWRONF,
+       MAX77686_PMICIRQ_PWRONR,
+       MAX77686_PMICIRQ_JIGONBF,
+       MAX77686_PMICIRQ_JIGONBR,
+       MAX77686_PMICIRQ_ACOKBF,
+       MAX77686_PMICIRQ_ACOKBR,
+       MAX77686_PMICIRQ_ONKEY1S,
+       MAX77686_PMICIRQ_MRSTB,
+
+       MAX77686_PMICIRQ_140C,
+       MAX77686_PMICIRQ_120C,
+
+       MAX77686_RTCIRQ_RTC60S,
+       MAX77686_RTCIRQ_RTCA1,
+       MAX77686_RTCIRQ_RTCA2,
+       MAX77686_RTCIRQ_SMPL,
+       MAX77686_RTCIRQ_RTC1S,
+       MAX77686_RTCIRQ_WTSR,
+
+       MAX77686_IRQ_NR,
+};
+
+struct max77686_dev {
+       struct device *dev;
+       struct i2c_client *i2c; /* 0xcc / PMIC, Battery Control, and FLASH */
+       struct i2c_client *rtc; /* slave addr 0x0c */
+
+       int type;
+
+       struct regmap *regmap;          /* regmap for mfd */
+       struct regmap *rtc_regmap;      /* regmap for rtc */
+
+       struct irq_domain *irq_domain;
+
+       int irq;
+       int irq_gpio;
+       bool wakeup;
+       struct mutex irqlock;
+       int irq_masks_cur[MAX77686_IRQ_GROUP_NR];
+       int irq_masks_cache[MAX77686_IRQ_GROUP_NR];
+};
+
+enum max77686_types {
+       TYPE_MAX77686,
+};
+
+extern int max77686_irq_init(struct max77686_dev *max77686);
+extern void max77686_irq_exit(struct max77686_dev *max77686);
+extern int max77686_irq_resume(struct max77686_dev *max77686);
+
+#endif /*  __LINUX_MFD_MAX77686_PRIV_H */
diff --git a/include/linux/mfd/max77686.h b/include/linux/mfd/max77686.h
new file mode 100644 (file)
index 0000000..3d7ae4d
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * max77686.h - Driver for the Maxim 77686
+ *
+ *  Copyright (C) 2012 Samsung Electrnoics
+ *  Chiwoong Byun <woong.byun@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max8997.h
+ *
+ * MAX77686 has PMIC, RTC devices.
+ * The devices share the same I2C bus and included in
+ * this mfd driver.
+ */
+
+#ifndef __LINUX_MFD_MAX77686_H
+#define __LINUX_MFD_MAX77686_H
+
+#include <linux/regulator/consumer.h>
+
+/* MAX77686 regulator IDs */
+enum max77686_regulators {
+       MAX77686_LDO1 = 0,
+       MAX77686_LDO2,
+       MAX77686_LDO3,
+       MAX77686_LDO4,
+       MAX77686_LDO5,
+       MAX77686_LDO6,
+       MAX77686_LDO7,
+       MAX77686_LDO8,
+       MAX77686_LDO9,
+       MAX77686_LDO10,
+       MAX77686_LDO11,
+       MAX77686_LDO12,
+       MAX77686_LDO13,
+       MAX77686_LDO14,
+       MAX77686_LDO15,
+       MAX77686_LDO16,
+       MAX77686_LDO17,
+       MAX77686_LDO18,
+       MAX77686_LDO19,
+       MAX77686_LDO20,
+       MAX77686_LDO21,
+       MAX77686_LDO22,
+       MAX77686_LDO23,
+       MAX77686_LDO24,
+       MAX77686_LDO25,
+       MAX77686_LDO26,
+       MAX77686_BUCK1,
+       MAX77686_BUCK2,
+       MAX77686_BUCK3,
+       MAX77686_BUCK4,
+       MAX77686_BUCK5,
+       MAX77686_BUCK6,
+       MAX77686_BUCK7,
+       MAX77686_BUCK8,
+       MAX77686_BUCK9,
+
+       MAX77686_REG_MAX,
+};
+
+struct max77686_regulator_data {
+       int id;
+       struct regulator_init_data *initdata;
+};
+
+enum max77686_opmode {
+       MAX77686_OPMODE_NORMAL,
+       MAX77686_OPMODE_LP,
+       MAX77686_OPMODE_STANDBY,
+};
+
+struct max77686_opmode_data {
+       int id;
+       int mode;
+};
+
+struct max77686_platform_data {
+       /* IRQ */
+       int irq_gpio;
+       int ono;
+       int wakeup;
+
+       /* ---- PMIC ---- */
+       struct max77686_regulator_data *regulators;
+       int num_regulators;
+
+       struct max77686_opmode_data *opmode_data;
+
+       /*
+        * GPIO-DVS feature is not enabled with the current version of
+        * MAX77686 driver. Buck2/3/4_voltages[0] is used as the default
+        * voltage at probe. DVS/SELB gpios are set as OUTPUT-LOW.
+        */
+       int buck234_gpio_dvs[3]; /* GPIO of [0]DVS1, [1]DVS2, [2]DVS3 */
+       int buck234_gpio_selb[3]; /* [0]SELB2, [1]SELB3, [2]SELB4 */
+       unsigned int buck2_voltage[8]; /* buckx_voltage in uV */
+       unsigned int buck3_voltage[8];
+       unsigned int buck4_voltage[8];
+};
+
+#endif /* __LINUX_MFD_MAX77686_H */
index 68263c5fa53c00fd8d125c6dcaa4c7d2dfafe1f7..1eeae5c07915dea761aba5d353db41d7bf033e39 100644 (file)
@@ -190,7 +190,6 @@ struct max77693_dev {
        struct i2c_client *i2c;         /* 0xCC , PMIC, Charger, Flash LED */
        struct i2c_client *muic;        /* 0x4A , MUIC */
        struct i2c_client *haptic;      /* 0x90 , Haptic */
-       struct mutex iolock;
 
        int type;
 
index 3f4deb62d6b0d4c4c3475e074244860977fd259c..830152cfae339727ad1d70875a61dbdaa34a6c67 100644 (file)
@@ -23,6 +23,8 @@
 #define __LINUX_MFD_MAX8997_PRIV_H
 
 #include <linux/i2c.h>
+#include <linux/export.h>
+#include <linux/irqdomain.h>
 
 #define MAX8997_REG_INVALID    (0xff)
 
@@ -325,7 +327,7 @@ struct max8997_dev {
 
        int irq;
        int ono;
-       int irq_base;
+       struct irq_domain *irq_domain;
        struct mutex irqlock;
        int irq_masks_cur[MAX8997_IRQ_GROUP_NR];
        int irq_masks_cache[MAX8997_IRQ_GROUP_NR];
index b40c08cd30bc82b97fd006d4800f07345f318c2c..328d8e24b533acaf524746d01dbf1cba76656782 100644 (file)
@@ -181,7 +181,6 @@ struct max8997_led_platform_data {
 
 struct max8997_platform_data {
        /* IRQ */
-       int irq_base;
        int ono;
        int wakeup;
 
diff --git a/include/linux/mfd/s5m87xx/s5m-core.h b/include/linux/mfd/s5m87xx/s5m-core.h
deleted file mode 100644 (file)
index 0b2e0ed..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * s5m-core.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd
- *              http://www.samsung.com
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
-
-#ifndef __LINUX_MFD_S5M_CORE_H
-#define __LINUX_MFD_S5M_CORE_H
-
-#define NUM_IRQ_REGS   4
-
-enum s5m_device_type {
-       S5M8751X,
-       S5M8763X,
-       S5M8767X,
-};
-
-/* S5M8767 registers */
-enum s5m8767_reg {
-       S5M8767_REG_ID,
-       S5M8767_REG_INT1,
-       S5M8767_REG_INT2,
-       S5M8767_REG_INT3,
-       S5M8767_REG_INT1M,
-       S5M8767_REG_INT2M,
-       S5M8767_REG_INT3M,
-       S5M8767_REG_STATUS1,
-       S5M8767_REG_STATUS2,
-       S5M8767_REG_STATUS3,
-       S5M8767_REG_CTRL1,
-       S5M8767_REG_CTRL2,
-       S5M8767_REG_LOWBAT1,
-       S5M8767_REG_LOWBAT2,
-       S5M8767_REG_BUCHG,
-       S5M8767_REG_DVSRAMP,
-       S5M8767_REG_DVSTIMER2 = 0x10,
-       S5M8767_REG_DVSTIMER3,
-       S5M8767_REG_DVSTIMER4,
-       S5M8767_REG_LDO1,
-       S5M8767_REG_LDO2,
-       S5M8767_REG_LDO3,
-       S5M8767_REG_LDO4,
-       S5M8767_REG_LDO5,
-       S5M8767_REG_LDO6,
-       S5M8767_REG_LDO7,
-       S5M8767_REG_LDO8,
-       S5M8767_REG_LDO9,
-       S5M8767_REG_LDO10,
-       S5M8767_REG_LDO11,
-       S5M8767_REG_LDO12,
-       S5M8767_REG_LDO13,
-       S5M8767_REG_LDO14 = 0x20,
-       S5M8767_REG_LDO15,
-       S5M8767_REG_LDO16,
-       S5M8767_REG_LDO17,
-       S5M8767_REG_LDO18,
-       S5M8767_REG_LDO19,
-       S5M8767_REG_LDO20,
-       S5M8767_REG_LDO21,
-       S5M8767_REG_LDO22,
-       S5M8767_REG_LDO23,
-       S5M8767_REG_LDO24,
-       S5M8767_REG_LDO25,
-       S5M8767_REG_LDO26,
-       S5M8767_REG_LDO27,
-       S5M8767_REG_LDO28,
-       S5M8767_REG_UVLO = 0x31,
-       S5M8767_REG_BUCK1CTRL1,
-       S5M8767_REG_BUCK1CTRL2,
-       S5M8767_REG_BUCK2CTRL,
-       S5M8767_REG_BUCK2DVS1,
-       S5M8767_REG_BUCK2DVS2,
-       S5M8767_REG_BUCK2DVS3,
-       S5M8767_REG_BUCK2DVS4,
-       S5M8767_REG_BUCK2DVS5,
-       S5M8767_REG_BUCK2DVS6,
-       S5M8767_REG_BUCK2DVS7,
-       S5M8767_REG_BUCK2DVS8,
-       S5M8767_REG_BUCK3CTRL,
-       S5M8767_REG_BUCK3DVS1,
-       S5M8767_REG_BUCK3DVS2,
-       S5M8767_REG_BUCK3DVS3,
-       S5M8767_REG_BUCK3DVS4,
-       S5M8767_REG_BUCK3DVS5,
-       S5M8767_REG_BUCK3DVS6,
-       S5M8767_REG_BUCK3DVS7,
-       S5M8767_REG_BUCK3DVS8,
-       S5M8767_REG_BUCK4CTRL,
-       S5M8767_REG_BUCK4DVS1,
-       S5M8767_REG_BUCK4DVS2,
-       S5M8767_REG_BUCK4DVS3,
-       S5M8767_REG_BUCK4DVS4,
-       S5M8767_REG_BUCK4DVS5,
-       S5M8767_REG_BUCK4DVS6,
-       S5M8767_REG_BUCK4DVS7,
-       S5M8767_REG_BUCK4DVS8,
-       S5M8767_REG_BUCK5CTRL1,
-       S5M8767_REG_BUCK5CTRL2,
-       S5M8767_REG_BUCK5CTRL3,
-       S5M8767_REG_BUCK5CTRL4,
-       S5M8767_REG_BUCK5CTRL5,
-       S5M8767_REG_BUCK6CTRL1,
-       S5M8767_REG_BUCK6CTRL2,
-       S5M8767_REG_BUCK7CTRL1,
-       S5M8767_REG_BUCK7CTRL2,
-       S5M8767_REG_BUCK8CTRL1,
-       S5M8767_REG_BUCK8CTRL2,
-       S5M8767_REG_BUCK9CTRL1,
-       S5M8767_REG_BUCK9CTRL2,
-       S5M8767_REG_LDO1CTRL,
-       S5M8767_REG_LDO2_1CTRL,
-       S5M8767_REG_LDO2_2CTRL,
-       S5M8767_REG_LDO2_3CTRL,
-       S5M8767_REG_LDO2_4CTRL,
-       S5M8767_REG_LDO3CTRL,
-       S5M8767_REG_LDO4CTRL,
-       S5M8767_REG_LDO5CTRL,
-       S5M8767_REG_LDO6CTRL,
-       S5M8767_REG_LDO7CTRL,
-       S5M8767_REG_LDO8CTRL,
-       S5M8767_REG_LDO9CTRL,
-       S5M8767_REG_LDO10CTRL,
-       S5M8767_REG_LDO11CTRL,
-       S5M8767_REG_LDO12CTRL,
-       S5M8767_REG_LDO13CTRL,
-       S5M8767_REG_LDO14CTRL,
-       S5M8767_REG_LDO15CTRL,
-       S5M8767_REG_LDO16CTRL,
-       S5M8767_REG_LDO17CTRL,
-       S5M8767_REG_LDO18CTRL,
-       S5M8767_REG_LDO19CTRL,
-       S5M8767_REG_LDO20CTRL,
-       S5M8767_REG_LDO21CTRL,
-       S5M8767_REG_LDO22CTRL,
-       S5M8767_REG_LDO23CTRL,
-       S5M8767_REG_LDO24CTRL,
-       S5M8767_REG_LDO25CTRL,
-       S5M8767_REG_LDO26CTRL,
-       S5M8767_REG_LDO27CTRL,
-       S5M8767_REG_LDO28CTRL,
-};
-
-/* S5M8763 registers */
-enum s5m8763_reg {
-       S5M8763_REG_IRQ1,
-       S5M8763_REG_IRQ2,
-       S5M8763_REG_IRQ3,
-       S5M8763_REG_IRQ4,
-       S5M8763_REG_IRQM1,
-       S5M8763_REG_IRQM2,
-       S5M8763_REG_IRQM3,
-       S5M8763_REG_IRQM4,
-       S5M8763_REG_STATUS1,
-       S5M8763_REG_STATUS2,
-       S5M8763_REG_STATUSM1,
-       S5M8763_REG_STATUSM2,
-       S5M8763_REG_CHGR1,
-       S5M8763_REG_CHGR2,
-       S5M8763_REG_LDO_ACTIVE_DISCHARGE1,
-       S5M8763_REG_LDO_ACTIVE_DISCHARGE2,
-       S5M8763_REG_BUCK_ACTIVE_DISCHARGE3,
-       S5M8763_REG_ONOFF1,
-       S5M8763_REG_ONOFF2,
-       S5M8763_REG_ONOFF3,
-       S5M8763_REG_ONOFF4,
-       S5M8763_REG_BUCK1_VOLTAGE1,
-       S5M8763_REG_BUCK1_VOLTAGE2,
-       S5M8763_REG_BUCK1_VOLTAGE3,
-       S5M8763_REG_BUCK1_VOLTAGE4,
-       S5M8763_REG_BUCK2_VOLTAGE1,
-       S5M8763_REG_BUCK2_VOLTAGE2,
-       S5M8763_REG_BUCK3,
-       S5M8763_REG_BUCK4,
-       S5M8763_REG_LDO1_LDO2,
-       S5M8763_REG_LDO3,
-       S5M8763_REG_LDO4,
-       S5M8763_REG_LDO5,
-       S5M8763_REG_LDO6,
-       S5M8763_REG_LDO7,
-       S5M8763_REG_LDO7_LDO8,
-       S5M8763_REG_LDO9_LDO10,
-       S5M8763_REG_LDO11,
-       S5M8763_REG_LDO12,
-       S5M8763_REG_LDO13,
-       S5M8763_REG_LDO14,
-       S5M8763_REG_LDO15,
-       S5M8763_REG_LDO16,
-       S5M8763_REG_BKCHR,
-       S5M8763_REG_LBCNFG1,
-       S5M8763_REG_LBCNFG2,
-};
-
-enum s5m8767_irq {
-       S5M8767_IRQ_PWRR,
-       S5M8767_IRQ_PWRF,
-       S5M8767_IRQ_PWR1S,
-       S5M8767_IRQ_JIGR,
-       S5M8767_IRQ_JIGF,
-       S5M8767_IRQ_LOWBAT2,
-       S5M8767_IRQ_LOWBAT1,
-
-       S5M8767_IRQ_MRB,
-       S5M8767_IRQ_DVSOK2,
-       S5M8767_IRQ_DVSOK3,
-       S5M8767_IRQ_DVSOK4,
-
-       S5M8767_IRQ_RTC60S,
-       S5M8767_IRQ_RTCA1,
-       S5M8767_IRQ_RTCA2,
-       S5M8767_IRQ_SMPL,
-       S5M8767_IRQ_RTC1S,
-       S5M8767_IRQ_WTSR,
-
-       S5M8767_IRQ_NR,
-};
-
-#define S5M8767_IRQ_PWRR_MASK          (1 << 0)
-#define S5M8767_IRQ_PWRF_MASK          (1 << 1)
-#define S5M8767_IRQ_PWR1S_MASK         (1 << 3)
-#define S5M8767_IRQ_JIGR_MASK          (1 << 4)
-#define S5M8767_IRQ_JIGF_MASK          (1 << 5)
-#define S5M8767_IRQ_LOWBAT2_MASK       (1 << 6)
-#define S5M8767_IRQ_LOWBAT1_MASK       (1 << 7)
-
-#define S5M8767_IRQ_MRB_MASK           (1 << 2)
-#define S5M8767_IRQ_DVSOK2_MASK                (1 << 3)
-#define S5M8767_IRQ_DVSOK3_MASK                (1 << 4)
-#define S5M8767_IRQ_DVSOK4_MASK                (1 << 5)
-
-#define S5M8767_IRQ_RTC60S_MASK                (1 << 0)
-#define S5M8767_IRQ_RTCA1_MASK         (1 << 1)
-#define S5M8767_IRQ_RTCA2_MASK         (1 << 2)
-#define S5M8767_IRQ_SMPL_MASK          (1 << 3)
-#define S5M8767_IRQ_RTC1S_MASK         (1 << 4)
-#define S5M8767_IRQ_WTSR_MASK          (1 << 5)
-
-enum s5m8763_irq {
-       S5M8763_IRQ_DCINF,
-       S5M8763_IRQ_DCINR,
-       S5M8763_IRQ_JIGF,
-       S5M8763_IRQ_JIGR,
-       S5M8763_IRQ_PWRONF,
-       S5M8763_IRQ_PWRONR,
-
-       S5M8763_IRQ_WTSREVNT,
-       S5M8763_IRQ_SMPLEVNT,
-       S5M8763_IRQ_ALARM1,
-       S5M8763_IRQ_ALARM0,
-
-       S5M8763_IRQ_ONKEY1S,
-       S5M8763_IRQ_TOPOFFR,
-       S5M8763_IRQ_DCINOVPR,
-       S5M8763_IRQ_CHGRSTF,
-       S5M8763_IRQ_DONER,
-       S5M8763_IRQ_CHGFAULT,
-
-       S5M8763_IRQ_LOBAT1,
-       S5M8763_IRQ_LOBAT2,
-
-       S5M8763_IRQ_NR,
-};
-
-#define S5M8763_IRQ_DCINF_MASK         (1 << 2)
-#define S5M8763_IRQ_DCINR_MASK         (1 << 3)
-#define S5M8763_IRQ_JIGF_MASK          (1 << 4)
-#define S5M8763_IRQ_JIGR_MASK          (1 << 5)
-#define S5M8763_IRQ_PWRONF_MASK                (1 << 6)
-#define S5M8763_IRQ_PWRONR_MASK                (1 << 7)
-
-#define S5M8763_IRQ_WTSREVNT_MASK      (1 << 0)
-#define S5M8763_IRQ_SMPLEVNT_MASK      (1 << 1)
-#define S5M8763_IRQ_ALARM1_MASK                (1 << 2)
-#define S5M8763_IRQ_ALARM0_MASK                (1 << 3)
-
-#define S5M8763_IRQ_ONKEY1S_MASK       (1 << 0)
-#define S5M8763_IRQ_TOPOFFR_MASK       (1 << 2)
-#define S5M8763_IRQ_DCINOVPR_MASK      (1 << 3)
-#define S5M8763_IRQ_CHGRSTF_MASK       (1 << 4)
-#define S5M8763_IRQ_DONER_MASK         (1 << 5)
-#define S5M8763_IRQ_CHGFAULT_MASK      (1 << 7)
-
-#define S5M8763_IRQ_LOBAT1_MASK                (1 << 0)
-#define S5M8763_IRQ_LOBAT2_MASK                (1 << 1)
-
-#define S5M8763_ENRAMP                  (1 << 4)
-
-/**
- * struct s5m87xx_dev - s5m87xx master device for sub-drivers
- * @dev: master device of the chip (can be used to access platform data)
- * @i2c: i2c client private data for regulator
- * @rtc: i2c client private data for rtc
- * @iolock: mutex for serializing io access
- * @irqlock: mutex for buslock
- * @irq_base: base IRQ number for s5m87xx, required for IRQs
- * @irq: generic IRQ number for s5m87xx
- * @ono: power onoff IRQ number for s5m87xx
- * @irq_masks_cur: currently active value
- * @irq_masks_cache: cached hardware value
- * @type: indicate which s5m87xx "variant" is used
- */
-struct s5m87xx_dev {
-       struct device *dev;
-       struct regmap *regmap;
-       struct i2c_client *i2c;
-       struct i2c_client *rtc;
-       struct mutex iolock;
-       struct mutex irqlock;
-
-       int device_type;
-       int irq_base;
-       int irq;
-       int ono;
-       u8 irq_masks_cur[NUM_IRQ_REGS];
-       u8 irq_masks_cache[NUM_IRQ_REGS];
-       int type;
-       bool wakeup;
-};
-
-int s5m_irq_init(struct s5m87xx_dev *s5m87xx);
-void s5m_irq_exit(struct s5m87xx_dev *s5m87xx);
-int s5m_irq_resume(struct s5m87xx_dev *s5m87xx);
-
-extern int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest);
-extern int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf);
-extern int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value);
-extern int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf);
-extern int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask);
-
-struct s5m_platform_data {
-       struct s5m_regulator_data       *regulators;
-       struct s5m_opmode_data          *opmode;
-       int                             device_type;
-       int                             num_regulators;
-
-       int                             irq_base;
-       int                             (*cfg_pmic_irq)(void);
-
-       int                             ono;
-       bool                            wakeup;
-       bool                            buck_voltage_lock;
-
-       int                             buck_gpios[3];
-       int                             buck_ds[3];
-       int                             buck2_voltage[8];
-       bool                            buck2_gpiodvs;
-       int                             buck3_voltage[8];
-       bool                            buck3_gpiodvs;
-       int                             buck4_voltage[8];
-       bool                            buck4_gpiodvs;
-
-       int                             buck_set1;
-       int                             buck_set2;
-       int                             buck_set3;
-       int                             buck2_enable;
-       int                             buck3_enable;
-       int                             buck4_enable;
-       int                             buck_default_idx;
-       int                             buck2_default_idx;
-       int                             buck3_default_idx;
-       int                             buck4_default_idx;
-
-       int                             buck_ramp_delay;
-       bool                            buck2_ramp_enable;
-       bool                            buck3_ramp_enable;
-       bool                            buck4_ramp_enable;
-
-       int                             buck2_init;
-       int                             buck3_init;
-       int                             buck4_init;
-};
-
-#endif /*  __LINUX_MFD_S5M_CORE_H */
diff --git a/include/linux/mfd/s5m87xx/s5m-pmic.h b/include/linux/mfd/s5m87xx/s5m-pmic.h
deleted file mode 100644 (file)
index 7c719f2..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/* s5m87xx.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __LINUX_MFD_S5M_PMIC_H
-#define __LINUX_MFD_S5M_PMIC_H
-
-#include <linux/regulator/machine.h>
-
-/* S5M8767 regulator ids */
-enum s5m8767_regulators {
-       S5M8767_LDO1,
-       S5M8767_LDO2,
-       S5M8767_LDO3,
-       S5M8767_LDO4,
-       S5M8767_LDO5,
-       S5M8767_LDO6,
-       S5M8767_LDO7,
-       S5M8767_LDO8,
-       S5M8767_LDO9,
-       S5M8767_LDO10,
-       S5M8767_LDO11,
-       S5M8767_LDO12,
-       S5M8767_LDO13,
-       S5M8767_LDO14,
-       S5M8767_LDO15,
-       S5M8767_LDO16,
-       S5M8767_LDO17,
-       S5M8767_LDO18,
-       S5M8767_LDO19,
-       S5M8767_LDO20,
-       S5M8767_LDO21,
-       S5M8767_LDO22,
-       S5M8767_LDO23,
-       S5M8767_LDO24,
-       S5M8767_LDO25,
-       S5M8767_LDO26,
-       S5M8767_LDO27,
-       S5M8767_LDO28,
-       S5M8767_BUCK1,
-       S5M8767_BUCK2,
-       S5M8767_BUCK3,
-       S5M8767_BUCK4,
-       S5M8767_BUCK5,
-       S5M8767_BUCK6,
-       S5M8767_BUCK7,
-       S5M8767_BUCK8,
-       S5M8767_BUCK9,
-       S5M8767_AP_EN32KHZ,
-       S5M8767_CP_EN32KHZ,
-
-       S5M8767_REG_MAX,
-};
-
-#define S5M8767_ENCTRL_SHIFT  6
-
-/* S5M8763 regulator ids */
-enum s5m8763_regulators {
-       S5M8763_LDO1,
-       S5M8763_LDO2,
-       S5M8763_LDO3,
-       S5M8763_LDO4,
-       S5M8763_LDO5,
-       S5M8763_LDO6,
-       S5M8763_LDO7,
-       S5M8763_LDO8,
-       S5M8763_LDO9,
-       S5M8763_LDO10,
-       S5M8763_LDO11,
-       S5M8763_LDO12,
-       S5M8763_LDO13,
-       S5M8763_LDO14,
-       S5M8763_LDO15,
-       S5M8763_LDO16,
-       S5M8763_BUCK1,
-       S5M8763_BUCK2,
-       S5M8763_BUCK3,
-       S5M8763_BUCK4,
-       S5M8763_AP_EN32KHZ,
-       S5M8763_CP_EN32KHZ,
-       S5M8763_ENCHGVI,
-       S5M8763_ESAFEUSB1,
-       S5M8763_ESAFEUSB2,
-};
-
-/**
- * s5m87xx_regulator_data - regulator data
- * @id: regulator id
- * @initdata: regulator init data (contraints, supplies, ...)
- */
-struct s5m_regulator_data {
-       int                             id;
-       struct regulator_init_data      *initdata;
-};
-
-/*
- * s5m_opmode_data - regulator operation mode data
- * @id: regulator id
- * @mode: regulator operation mode
- */
-struct s5m_opmode_data {
-       int id;
-       int mode;
-};
-
-/*
- * s5m regulator operation mode
- * S5M_OPMODE_OFF      Regulator always OFF
- * S5M_OPMODE_ON       Regulator always ON
- * S5M_OPMODE_LOWPOWER  Regulator is on in low-power mode
- * S5M_OPMODE_SUSPEND   Regulator is changed by PWREN pin
- *                     If PWREN is high, regulator is on
- *                     If PWREN is low, regulator is off
- */
-
-enum s5m_opmode {
-       S5M_OPMODE_OFF,
-       S5M_OPMODE_ON,
-       S5M_OPMODE_LOWPOWER,
-       S5M_OPMODE_SUSPEND,
-};
-
-#endif /*  __LINUX_MFD_S5M_PMIC_H */
diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h
new file mode 100644 (file)
index 0000000..b50c38f
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * core.h
+ *
+ * copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_SEC_CORE_H
+#define __LINUX_MFD_SEC_CORE_H
+
+#define NUM_IRQ_REGS   4
+
+enum sec_device_type {
+       S5M8751X,
+       S5M8763X,
+       S5M8767X,
+       S2MPS11X,
+};
+
+/**
+ * struct sec_pmic_dev - s5m87xx master device for sub-drivers
+ * @dev: master device of the chip (can be used to access platform data)
+ * @i2c: i2c client private data for regulator
+ * @rtc: i2c client private data for rtc
+ * @iolock: mutex for serializing io access
+ * @irqlock: mutex for buslock
+ * @irq_base: base IRQ number for sec-pmic, required for IRQs
+ * @irq: generic IRQ number for s5m87xx
+ * @ono: power onoff IRQ number for s5m87xx
+ * @irq_masks_cur: currently active value
+ * @irq_masks_cache: cached hardware value
+ * @type: indicate which s5m87xx "variant" is used
+ */
+struct sec_pmic_dev {
+       struct device *dev;
+       struct regmap *regmap;
+       struct i2c_client *i2c;
+       struct i2c_client *rtc;
+       struct mutex iolock;
+       struct mutex irqlock;
+
+       int device_type;
+       int irq_base;
+       int irq;
+       struct regmap_irq_chip_data *irq_data;
+
+       int ono;
+       u8 irq_masks_cur[NUM_IRQ_REGS];
+       u8 irq_masks_cache[NUM_IRQ_REGS];
+       int type;
+       bool wakeup;
+};
+
+int sec_irq_init(struct sec_pmic_dev *sec_pmic);
+void sec_irq_exit(struct sec_pmic_dev *sec_pmic);
+int sec_irq_resume(struct sec_pmic_dev *sec_pmic);
+
+extern int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest);
+extern int sec_bulk_read(struct sec_pmic_dev *sec_pmic, u8 reg, int count, u8 *buf);
+extern int sec_reg_write(struct sec_pmic_dev *sec_pmic, u8 reg, u8 value);
+extern int sec_bulk_write(struct sec_pmic_dev *sec_pmic, u8 reg, int count, u8 *buf);
+extern int sec_reg_update(struct sec_pmic_dev *sec_pmic, u8 reg, u8 val, u8 mask);
+
+struct sec_platform_data {
+       struct sec_regulator_data       *regulators;
+       struct sec_opmode_data          *opmode;
+       int                             device_type;
+       int                             num_regulators;
+
+       int                             irq_base;
+       int                             (*cfg_pmic_irq)(void);
+
+       int                             ono;
+       bool                            wakeup;
+       bool                            buck_voltage_lock;
+
+       int                             buck_gpios[3];
+       int                             buck_ds[3];
+       int                             buck2_voltage[8];
+       bool                            buck2_gpiodvs;
+       int                             buck3_voltage[8];
+       bool                            buck3_gpiodvs;
+       int                             buck4_voltage[8];
+       bool                            buck4_gpiodvs;
+
+       int                             buck_set1;
+       int                             buck_set2;
+       int                             buck_set3;
+       int                             buck2_enable;
+       int                             buck3_enable;
+       int                             buck4_enable;
+       int                             buck_default_idx;
+       int                             buck2_default_idx;
+       int                             buck3_default_idx;
+       int                             buck4_default_idx;
+
+       int                             buck_ramp_delay;
+
+       int                             buck2_ramp_delay;
+       int                             buck34_ramp_delay;
+       int                             buck5_ramp_delay;
+       int                             buck16_ramp_delay;
+       int                             buck7810_ramp_delay;
+       int                             buck9_ramp_delay;
+
+       bool                            buck2_ramp_enable;
+       bool                            buck3_ramp_enable;
+       bool                            buck4_ramp_enable;
+       bool                            buck6_ramp_enable;
+
+       int                             buck2_init;
+       int                             buck3_init;
+       int                             buck4_init;
+};
+
+/**
+ * sec_regulator_data - regulator data
+ * @id: regulator id
+ * @initdata: regulator init data (contraints, supplies, ...)
+ */
+struct sec_regulator_data {
+       int                             id;
+       struct regulator_init_data      *initdata;
+};
+
+/*
+ * sec_opmode_data - regulator operation mode data
+ * @id: regulator id
+ * @mode: regulator operation mode
+ */
+struct sec_opmode_data {
+       int id;
+       int mode;
+};
+
+/*
+ * samsung regulator operation mode
+ * SEC_OPMODE_OFF      Regulator always OFF
+ * SEC_OPMODE_ON       Regulator always ON
+ * SEC_OPMODE_LOWPOWER  Regulator is on in low-power mode
+ * SEC_OPMODE_SUSPEND   Regulator is changed by PWREN pin
+ *                     If PWREN is high, regulator is on
+ *                     If PWREN is low, regulator is off
+ */
+
+enum sec_opmode {
+       SEC_OPMODE_OFF,
+       SEC_OPMODE_ON,
+       SEC_OPMODE_LOWPOWER,
+       SEC_OPMODE_SUSPEND,
+};
+
+#endif /*  __LINUX_MFD_SEC_CORE_H */
diff --git a/include/linux/mfd/samsung/irq.h b/include/linux/mfd/samsung/irq.h
new file mode 100644 (file)
index 0000000..d43b4f9
--- /dev/null
@@ -0,0 +1,152 @@
+/* irq.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_SEC_IRQ_H
+#define __LINUX_MFD_SEC_IRQ_H
+
+enum s2mps11_irq {
+       S2MPS11_IRQ_PWRONF,
+       S2MPS11_IRQ_PWRONR,
+       S2MPS11_IRQ_JIGONBF,
+       S2MPS11_IRQ_JIGONBR,
+       S2MPS11_IRQ_ACOKBF,
+       S2MPS11_IRQ_ACOKBR,
+       S2MPS11_IRQ_PWRON1S,
+       S2MPS11_IRQ_MRB,
+
+       S2MPS11_IRQ_RTC60S,
+       S2MPS11_IRQ_RTCA1,
+       S2MPS11_IRQ_RTCA2,
+       S2MPS11_IRQ_SMPL,
+       S2MPS11_IRQ_RTC1S,
+       S2MPS11_IRQ_WTSR,
+
+       S2MPS11_IRQ_INT120C,
+       S2MPS11_IRQ_INT140C,
+
+       S2MPS11_IRQ_NR,
+};
+
+#define S2MPS11_IRQ_PWRONF_MASK                (1 << 0)
+#define S2MPS11_IRQ_PWRONR_MASK                (1 << 1)
+#define S2MPS11_IRQ_JIGONBF_MASK       (1 << 2)
+#define S2MPS11_IRQ_JIGONBR_MASK       (1 << 3)
+#define S2MPS11_IRQ_ACOKBF_MASK                (1 << 4)
+#define S2MPS11_IRQ_ACOKBR_MASK                (1 << 5)
+#define S2MPS11_IRQ_PWRON1S_MASK       (1 << 6)
+#define S2MPS11_IRQ_MRB_MASK           (1 << 7)
+
+#define S2MPS11_IRQ_RTC60S_MASK                (1 << 0)
+#define S2MPS11_IRQ_RTCA1_MASK         (1 << 1)
+#define S2MPS11_IRQ_RTCA2_MASK         (1 << 2)
+#define S2MPS11_IRQ_SMPL_MASK          (1 << 3)
+#define S2MPS11_IRQ_RTC1S_MASK         (1 << 4)
+#define S2MPS11_IRQ_WTSR_MASK          (1 << 5)
+
+#define S2MPS11_IRQ_INT120C_MASK       (1 << 0)
+#define S2MPS11_IRQ_INT140C_MASK       (1 << 1)
+
+enum s5m8767_irq {
+       S5M8767_IRQ_PWRR,
+       S5M8767_IRQ_PWRF,
+       S5M8767_IRQ_PWR1S,
+       S5M8767_IRQ_JIGR,
+       S5M8767_IRQ_JIGF,
+       S5M8767_IRQ_LOWBAT2,
+       S5M8767_IRQ_LOWBAT1,
+
+       S5M8767_IRQ_MRB,
+       S5M8767_IRQ_DVSOK2,
+       S5M8767_IRQ_DVSOK3,
+       S5M8767_IRQ_DVSOK4,
+
+       S5M8767_IRQ_RTC60S,
+       S5M8767_IRQ_RTCA1,
+       S5M8767_IRQ_RTCA2,
+       S5M8767_IRQ_SMPL,
+       S5M8767_IRQ_RTC1S,
+       S5M8767_IRQ_WTSR,
+
+       S5M8767_IRQ_NR,
+};
+
+#define S5M8767_IRQ_PWRR_MASK          (1 << 0)
+#define S5M8767_IRQ_PWRF_MASK          (1 << 1)
+#define S5M8767_IRQ_PWR1S_MASK         (1 << 3)
+#define S5M8767_IRQ_JIGR_MASK          (1 << 4)
+#define S5M8767_IRQ_JIGF_MASK          (1 << 5)
+#define S5M8767_IRQ_LOWBAT2_MASK       (1 << 6)
+#define S5M8767_IRQ_LOWBAT1_MASK       (1 << 7)
+
+#define S5M8767_IRQ_MRB_MASK           (1 << 2)
+#define S5M8767_IRQ_DVSOK2_MASK                (1 << 3)
+#define S5M8767_IRQ_DVSOK3_MASK                (1 << 4)
+#define S5M8767_IRQ_DVSOK4_MASK                (1 << 5)
+
+#define S5M8767_IRQ_RTC60S_MASK                (1 << 0)
+#define S5M8767_IRQ_RTCA1_MASK         (1 << 1)
+#define S5M8767_IRQ_RTCA2_MASK         (1 << 2)
+#define S5M8767_IRQ_SMPL_MASK          (1 << 3)
+#define S5M8767_IRQ_RTC1S_MASK         (1 << 4)
+#define S5M8767_IRQ_WTSR_MASK          (1 << 5)
+
+enum s5m8763_irq {
+       S5M8763_IRQ_DCINF,
+       S5M8763_IRQ_DCINR,
+       S5M8763_IRQ_JIGF,
+       S5M8763_IRQ_JIGR,
+       S5M8763_IRQ_PWRONF,
+       S5M8763_IRQ_PWRONR,
+
+       S5M8763_IRQ_WTSREVNT,
+       S5M8763_IRQ_SMPLEVNT,
+       S5M8763_IRQ_ALARM1,
+       S5M8763_IRQ_ALARM0,
+
+       S5M8763_IRQ_ONKEY1S,
+       S5M8763_IRQ_TOPOFFR,
+       S5M8763_IRQ_DCINOVPR,
+       S5M8763_IRQ_CHGRSTF,
+       S5M8763_IRQ_DONER,
+       S5M8763_IRQ_CHGFAULT,
+
+       S5M8763_IRQ_LOBAT1,
+       S5M8763_IRQ_LOBAT2,
+
+       S5M8763_IRQ_NR,
+};
+
+#define S5M8763_IRQ_DCINF_MASK         (1 << 2)
+#define S5M8763_IRQ_DCINR_MASK         (1 << 3)
+#define S5M8763_IRQ_JIGF_MASK          (1 << 4)
+#define S5M8763_IRQ_JIGR_MASK          (1 << 5)
+#define S5M8763_IRQ_PWRONF_MASK                (1 << 6)
+#define S5M8763_IRQ_PWRONR_MASK                (1 << 7)
+
+#define S5M8763_IRQ_WTSREVNT_MASK      (1 << 0)
+#define S5M8763_IRQ_SMPLEVNT_MASK      (1 << 1)
+#define S5M8763_IRQ_ALARM1_MASK                (1 << 2)
+#define S5M8763_IRQ_ALARM0_MASK                (1 << 3)
+
+#define S5M8763_IRQ_ONKEY1S_MASK       (1 << 0)
+#define S5M8763_IRQ_TOPOFFR_MASK       (1 << 2)
+#define S5M8763_IRQ_DCINOVPR_MASK      (1 << 3)
+#define S5M8763_IRQ_CHGRSTF_MASK       (1 << 4)
+#define S5M8763_IRQ_DONER_MASK         (1 << 5)
+#define S5M8763_IRQ_CHGFAULT_MASK      (1 << 7)
+
+#define S5M8763_IRQ_LOBAT1_MASK                (1 << 0)
+#define S5M8763_IRQ_LOBAT2_MASK                (1 << 1)
+
+#define S5M8763_ENRAMP                  (1 << 4)
+
+#endif /*  __LINUX_MFD_SEC_IRQ_H */
similarity index 59%
rename from include/linux/mfd/s5m87xx/s5m-rtc.h
rename to include/linux/mfd/samsung/rtc.h
index 6ce8da264cec3eda3179842c7c831cb4b5ec28f9..71597e20cddb54d1aaa45474f82120c4d1f1e868 100644 (file)
@@ -1,5 +1,4 @@
-/*
- * s5m-rtc.h
+/*  rtc.h
  *
  * Copyright (c) 2011 Samsung Electronics Co., Ltd
  *              http://www.samsung.com
  *
  */
 
-#ifndef __LINUX_MFD_S5M_RTC_H
-#define __LINUX_MFD_S5M_RTC_H
+#ifndef __LINUX_MFD_SEC_RTC_H
+#define __LINUX_MFD_SEC_RTC_H
 
-enum s5m87xx_rtc_reg {
-       S5M87XX_RTC_SEC,
-       S5M87XX_RTC_MIN,
-       S5M87XX_RTC_HOUR,
-       S5M87XX_RTC_WEEKDAY,
-       S5M87XX_RTC_DATE,
-       S5M87XX_RTC_MONTH,
-       S5M87XX_RTC_YEAR1,
-       S5M87XX_RTC_YEAR2,
-       S5M87XX_ALARM0_SEC,
-       S5M87XX_ALARM0_MIN,
-       S5M87XX_ALARM0_HOUR,
-       S5M87XX_ALARM0_WEEKDAY,
-       S5M87XX_ALARM0_DATE,
-       S5M87XX_ALARM0_MONTH,
-       S5M87XX_ALARM0_YEAR1,
-       S5M87XX_ALARM0_YEAR2,
-       S5M87XX_ALARM1_SEC,
-       S5M87XX_ALARM1_MIN,
-       S5M87XX_ALARM1_HOUR,
-       S5M87XX_ALARM1_WEEKDAY,
-       S5M87XX_ALARM1_DATE,
-       S5M87XX_ALARM1_MONTH,
-       S5M87XX_ALARM1_YEAR1,
-       S5M87XX_ALARM1_YEAR2,
-       S5M87XX_ALARM0_CONF,
-       S5M87XX_ALARM1_CONF,
-       S5M87XX_RTC_STATUS,
-       S5M87XX_WTSR_SMPL_CNTL,
-       S5M87XX_RTC_UDR_CON,
+enum sec_rtc_reg {
+       SEC_RTC_SEC,
+       SEC_RTC_MIN,
+       SEC_RTC_HOUR,
+       SEC_RTC_WEEKDAY,
+       SEC_RTC_DATE,
+       SEC_RTC_MONTH,
+       SEC_RTC_YEAR1,
+       SEC_RTC_YEAR2,
+       SEC_ALARM0_SEC,
+       SEC_ALARM0_MIN,
+       SEC_ALARM0_HOUR,
+       SEC_ALARM0_WEEKDAY,
+       SEC_ALARM0_DATE,
+       SEC_ALARM0_MONTH,
+       SEC_ALARM0_YEAR1,
+       SEC_ALARM0_YEAR2,
+       SEC_ALARM1_SEC,
+       SEC_ALARM1_MIN,
+       SEC_ALARM1_HOUR,
+       SEC_ALARM1_WEEKDAY,
+       SEC_ALARM1_DATE,
+       SEC_ALARM1_MONTH,
+       SEC_ALARM1_YEAR1,
+       SEC_ALARM1_YEAR2,
+       SEC_ALARM0_CONF,
+       SEC_ALARM1_CONF,
+       SEC_RTC_STATUS,
+       SEC_WTSR_SMPL_CNTL,
+       SEC_RTC_UDR_CON,
 };
 
 #define RTC_I2C_ADDR           (0x0C >> 1)
@@ -81,4 +80,4 @@ enum {
        RTC_YEAR2,
 };
 
-#endif /*  __LINUX_MFD_S5M_RTC_H */
+#endif /*  __LINUX_MFD_SEC_RTC_H */
diff --git a/include/linux/mfd/samsung/s2mps11.h b/include/linux/mfd/samsung/s2mps11.h
new file mode 100644 (file)
index 0000000..ad2252f
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * s2mps11.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_S2MPS11_H
+#define __LINUX_MFD_S2MPS11_H
+
+/* S2MPS11 registers */
+enum s2mps11_reg {
+       S2MPS11_REG_ID,
+       S2MPS11_REG_INT1,
+       S2MPS11_REG_INT2,
+       S2MPS11_REG_INT3,
+       S2MPS11_REG_INT1M,
+       S2MPS11_REG_INT2M,
+       S2MPS11_REG_INT3M,
+       S2MPS11_REG_ST1,
+       S2MPS11_REG_ST2,
+       S2MPS11_REG_OFFSRC,
+       S2MPS11_REG_PWRONSRC,
+       S2MPS11_REG_RTC_CTRL,
+       S2MPS11_REG_CTRL1,
+       S2MPS11_REG_ETC_TEST,
+       S2MPS11_REG_RSVD3,
+       S2MPS11_REG_BU_CHG,
+       S2MPS11_REG_RAMP,
+       S2MPS11_REG_RAMP_BUCK,
+       S2MPS11_REG_LDO1_8,
+       S2MPS11_REG_LDO9_16,
+       S2MPS11_REG_LDO17_24,
+       S2MPS11_REG_LDO25_32,
+       S2MPS11_REG_LDO33_38,
+       S2MPS11_REG_LDO1_8_1,
+       S2MPS11_REG_LDO9_16_1,
+       S2MPS11_REG_LDO17_24_1,
+       S2MPS11_REG_LDO25_32_1,
+       S2MPS11_REG_LDO33_38_1,
+       S2MPS11_REG_OTP_ADRL,
+       S2MPS11_REG_OTP_ADRH,
+       S2MPS11_REG_OTP_DATA,
+       S2MPS11_REG_MON1SEL,
+       S2MPS11_REG_MON2SEL,
+       S2MPS11_REG_LEE,
+       S2MPS11_REG_RSVD_NO,
+       S2MPS11_REG_UVLO,
+       S2MPS11_REG_LEE_NO,
+       S2MPS11_REG_B1CTRL1,
+       S2MPS11_REG_B1CTRL2,
+       S2MPS11_REG_B2CTRL1,
+       S2MPS11_REG_B2CTRL2,
+       S2MPS11_REG_B3CTRL1,
+       S2MPS11_REG_B3CTRL2,
+       S2MPS11_REG_B4CTRL1,
+       S2MPS11_REG_B4CTRL2,
+       S2MPS11_REG_B5CTRL1,
+       S2MPS11_REG_BUCK5_SW,
+       S2MPS11_REG_B5CTRL2,
+       S2MPS11_REG_B5CTRL3,
+       S2MPS11_REG_B5CTRL4,
+       S2MPS11_REG_B5CTRL5,
+       S2MPS11_REG_B6CTRL1,
+       S2MPS11_REG_B6CTRL2,
+       S2MPS11_REG_B7CTRL1,
+       S2MPS11_REG_B7CTRL2,
+       S2MPS11_REG_B8CTRL1,
+       S2MPS11_REG_B8CTRL2,
+       S2MPS11_REG_B9CTRL1,
+       S2MPS11_REG_B9CTRL2,
+       S2MPS11_REG_B10CTRL1,
+       S2MPS11_REG_B10CTRL2,
+       S2MPS11_REG_L1CTRL,
+       S2MPS11_REG_L2CTRL,
+       S2MPS11_REG_L3CTRL,
+       S2MPS11_REG_L4CTRL,
+       S2MPS11_REG_L5CTRL,
+       S2MPS11_REG_L6CTRL,
+       S2MPS11_REG_L7CTRL,
+       S2MPS11_REG_L8CTRL,
+       S2MPS11_REG_L9CTRL,
+       S2MPS11_REG_L10CTRL,
+       S2MPS11_REG_L11CTRL,
+       S2MPS11_REG_L12CTRL,
+       S2MPS11_REG_L13CTRL,
+       S2MPS11_REG_L14CTRL,
+       S2MPS11_REG_L15CTRL,
+       S2MPS11_REG_L16CTRL,
+       S2MPS11_REG_L17CTRL,
+       S2MPS11_REG_L18CTRL,
+       S2MPS11_REG_L19CTRL,
+       S2MPS11_REG_L20CTRL,
+       S2MPS11_REG_L21CTRL,
+       S2MPS11_REG_L22CTRL,
+       S2MPS11_REG_L23CTRL,
+       S2MPS11_REG_L24CTRL,
+       S2MPS11_REG_L25CTRL,
+       S2MPS11_REG_L26CTRL,
+       S2MPS11_REG_L27CTRL,
+       S2MPS11_REG_L28CTRL,
+       S2MPS11_REG_L29CTRL,
+       S2MPS11_REG_L30CTRL,
+       S2MPS11_REG_L31CTRL,
+       S2MPS11_REG_L32CTRL,
+       S2MPS11_REG_L33CTRL,
+       S2MPS11_REG_L34CTRL,
+       S2MPS11_REG_L35CTRL,
+       S2MPS11_REG_L36CTRL,
+       S2MPS11_REG_L37CTRL,
+       S2MPS11_REG_L38CTRL,
+};
+
+/* S2MPS11 regulator ids */
+enum s2mps11_regulators {
+       S2MPS11_LDO1,
+       S2MPS11_LDO2,
+       S2MPS11_LDO3,
+       S2MPS11_LDO4,
+       S2MPS11_LDO5,
+       S2MPS11_LDO6,
+       S2MPS11_LDO7,
+       S2MPS11_LDO8,
+       S2MPS11_LDO9,
+       S2MPS11_LDO10,
+       S2MPS11_LDO11,
+       S2MPS11_LDO12,
+       S2MPS11_LDO13,
+       S2MPS11_LDO14,
+       S2MPS11_LDO15,
+       S2MPS11_LDO16,
+       S2MPS11_LDO17,
+       S2MPS11_LDO18,
+       S2MPS11_LDO19,
+       S2MPS11_LDO20,
+       S2MPS11_LDO21,
+       S2MPS11_LDO22,
+       S2MPS11_LDO23,
+       S2MPS11_LDO24,
+       S2MPS11_LDO25,
+       S2MPS11_LDO26,
+       S2MPS11_LDO27,
+       S2MPS11_LDO28,
+       S2MPS11_LDO29,
+       S2MPS11_LDO30,
+       S2MPS11_LDO31,
+       S2MPS11_LDO32,
+       S2MPS11_LDO33,
+       S2MPS11_LDO34,
+       S2MPS11_LDO35,
+       S2MPS11_LDO36,
+       S2MPS11_LDO37,
+       S2MPS11_LDO38,
+       S2MPS11_BUCK1,
+       S2MPS11_BUCK2,
+       S2MPS11_BUCK3,
+       S2MPS11_BUCK4,
+       S2MPS11_BUCK5,
+       S2MPS11_BUCK6,
+       S2MPS11_BUCK7,
+       S2MPS11_BUCK8,
+       S2MPS11_BUCK9,
+       S2MPS11_BUCK10,
+       S2MPS11_AP_EN32KHZ,
+       S2MPS11_CP_EN32KHZ,
+       S2MPS11_BT_EN32KHZ,
+
+       S2MPS11_REG_MAX,
+};
+
+#define S2MPS11_BUCK_MIN1      600000
+#define S2MPS11_BUCK_MIN2      750000
+#define S2MPS11_BUCK_MIN3      3000000
+#define S2MPS11_LDO_MIN        800000
+#define S2MPS11_BUCK_STEP1     6250
+#define S2MPS11_BUCK_STEP2     12500
+#define S2MPS11_BUCK_STEP3     25000
+#define S2MPS11_LDO_STEP1      50000
+#define S2MPS11_LDO_STEP2      25000
+#define S2MPS11_LDO_VSEL_MASK  0x3F
+#define S2MPS11_BUCK_VSEL_MASK 0xFF
+#define S2MPS11_ENABLE_MASK    (0x03 << S2MPS11_ENABLE_SHIFT)
+#define S2MPS11_ENABLE_SHIFT   0x06
+#define S2MPS11_LDO_N_VOLTAGES (S2MPS11_LDO_VSEL_MASK + 1)
+#define S2MPS11_BUCK_N_VOLTAGES (S2MPS11_BUCK_VSEL_MASK + 1)
+
+#define S2MPS11_PMIC_EN_SHIFT  6
+#define S2MPS11_REGULATOR_MAX (S2MPS11_REG_MAX - 3)
+
+#endif /*  __LINUX_MFD_S2MPS11_H */
diff --git a/include/linux/mfd/samsung/s5m8763.h b/include/linux/mfd/samsung/s5m8763.h
new file mode 100644 (file)
index 0000000..e025418
--- /dev/null
@@ -0,0 +1,96 @@
+/*  s5m8763.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_S5M8763_H
+#define __LINUX_MFD_S5M8763_H
+
+/* S5M8763 registers */
+enum s5m8763_reg {
+       S5M8763_REG_IRQ1,
+       S5M8763_REG_IRQ2,
+       S5M8763_REG_IRQ3,
+       S5M8763_REG_IRQ4,
+       S5M8763_REG_IRQM1,
+       S5M8763_REG_IRQM2,
+       S5M8763_REG_IRQM3,
+       S5M8763_REG_IRQM4,
+       S5M8763_REG_STATUS1,
+       S5M8763_REG_STATUS2,
+       S5M8763_REG_STATUSM1,
+       S5M8763_REG_STATUSM2,
+       S5M8763_REG_CHGR1,
+       S5M8763_REG_CHGR2,
+       S5M8763_REG_LDO_ACTIVE_DISCHARGE1,
+       S5M8763_REG_LDO_ACTIVE_DISCHARGE2,
+       S5M8763_REG_BUCK_ACTIVE_DISCHARGE3,
+       S5M8763_REG_ONOFF1,
+       S5M8763_REG_ONOFF2,
+       S5M8763_REG_ONOFF3,
+       S5M8763_REG_ONOFF4,
+       S5M8763_REG_BUCK1_VOLTAGE1,
+       S5M8763_REG_BUCK1_VOLTAGE2,
+       S5M8763_REG_BUCK1_VOLTAGE3,
+       S5M8763_REG_BUCK1_VOLTAGE4,
+       S5M8763_REG_BUCK2_VOLTAGE1,
+       S5M8763_REG_BUCK2_VOLTAGE2,
+       S5M8763_REG_BUCK3,
+       S5M8763_REG_BUCK4,
+       S5M8763_REG_LDO1_LDO2,
+       S5M8763_REG_LDO3,
+       S5M8763_REG_LDO4,
+       S5M8763_REG_LDO5,
+       S5M8763_REG_LDO6,
+       S5M8763_REG_LDO7,
+       S5M8763_REG_LDO7_LDO8,
+       S5M8763_REG_LDO9_LDO10,
+       S5M8763_REG_LDO11,
+       S5M8763_REG_LDO12,
+       S5M8763_REG_LDO13,
+       S5M8763_REG_LDO14,
+       S5M8763_REG_LDO15,
+       S5M8763_REG_LDO16,
+       S5M8763_REG_BKCHR,
+       S5M8763_REG_LBCNFG1,
+       S5M8763_REG_LBCNFG2,
+};
+
+/* S5M8763 regulator ids */
+enum s5m8763_regulators {
+       S5M8763_LDO1,
+       S5M8763_LDO2,
+       S5M8763_LDO3,
+       S5M8763_LDO4,
+       S5M8763_LDO5,
+       S5M8763_LDO6,
+       S5M8763_LDO7,
+       S5M8763_LDO8,
+       S5M8763_LDO9,
+       S5M8763_LDO10,
+       S5M8763_LDO11,
+       S5M8763_LDO12,
+       S5M8763_LDO13,
+       S5M8763_LDO14,
+       S5M8763_LDO15,
+       S5M8763_LDO16,
+       S5M8763_BUCK1,
+       S5M8763_BUCK2,
+       S5M8763_BUCK3,
+       S5M8763_BUCK4,
+       S5M8763_AP_EN32KHZ,
+       S5M8763_CP_EN32KHZ,
+       S5M8763_ENCHGVI,
+       S5M8763_ESAFEUSB1,
+       S5M8763_ESAFEUSB2,
+};
+
+#define S5M8763_ENRAMP                  (1 << 4)
+#endif /* __LINUX_MFD_S5M8763_H */
diff --git a/include/linux/mfd/samsung/s5m8767.h b/include/linux/mfd/samsung/s5m8767.h
new file mode 100644 (file)
index 0000000..306a95f
--- /dev/null
@@ -0,0 +1,188 @@
+/*  s5m8767.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_S5M8767_H
+#define __LINUX_MFD_S5M8767_H
+
+/* S5M8767 registers */
+enum s5m8767_reg {
+       S5M8767_REG_ID,
+       S5M8767_REG_INT1,
+       S5M8767_REG_INT2,
+       S5M8767_REG_INT3,
+       S5M8767_REG_INT1M,
+       S5M8767_REG_INT2M,
+       S5M8767_REG_INT3M,
+       S5M8767_REG_STATUS1,
+       S5M8767_REG_STATUS2,
+       S5M8767_REG_STATUS3,
+       S5M8767_REG_CTRL1,
+       S5M8767_REG_CTRL2,
+       S5M8767_REG_LOWBAT1,
+       S5M8767_REG_LOWBAT2,
+       S5M8767_REG_BUCHG,
+       S5M8767_REG_DVSRAMP,
+       S5M8767_REG_DVSTIMER2 = 0x10,
+       S5M8767_REG_DVSTIMER3,
+       S5M8767_REG_DVSTIMER4,
+       S5M8767_REG_LDO1,
+       S5M8767_REG_LDO2,
+       S5M8767_REG_LDO3,
+       S5M8767_REG_LDO4,
+       S5M8767_REG_LDO5,
+       S5M8767_REG_LDO6,
+       S5M8767_REG_LDO7,
+       S5M8767_REG_LDO8,
+       S5M8767_REG_LDO9,
+       S5M8767_REG_LDO10,
+       S5M8767_REG_LDO11,
+       S5M8767_REG_LDO12,
+       S5M8767_REG_LDO13,
+       S5M8767_REG_LDO14 = 0x20,
+       S5M8767_REG_LDO15,
+       S5M8767_REG_LDO16,
+       S5M8767_REG_LDO17,
+       S5M8767_REG_LDO18,
+       S5M8767_REG_LDO19,
+       S5M8767_REG_LDO20,
+       S5M8767_REG_LDO21,
+       S5M8767_REG_LDO22,
+       S5M8767_REG_LDO23,
+       S5M8767_REG_LDO24,
+       S5M8767_REG_LDO25,
+       S5M8767_REG_LDO26,
+       S5M8767_REG_LDO27,
+       S5M8767_REG_LDO28,
+       S5M8767_REG_UVLO = 0x31,
+       S5M8767_REG_BUCK1CTRL1,
+       S5M8767_REG_BUCK1CTRL2,
+       S5M8767_REG_BUCK2CTRL,
+       S5M8767_REG_BUCK2DVS1,
+       S5M8767_REG_BUCK2DVS2,
+       S5M8767_REG_BUCK2DVS3,
+       S5M8767_REG_BUCK2DVS4,
+       S5M8767_REG_BUCK2DVS5,
+       S5M8767_REG_BUCK2DVS6,
+       S5M8767_REG_BUCK2DVS7,
+       S5M8767_REG_BUCK2DVS8,
+       S5M8767_REG_BUCK3CTRL,
+       S5M8767_REG_BUCK3DVS1,
+       S5M8767_REG_BUCK3DVS2,
+       S5M8767_REG_BUCK3DVS3,
+       S5M8767_REG_BUCK3DVS4,
+       S5M8767_REG_BUCK3DVS5,
+       S5M8767_REG_BUCK3DVS6,
+       S5M8767_REG_BUCK3DVS7,
+       S5M8767_REG_BUCK3DVS8,
+       S5M8767_REG_BUCK4CTRL,
+       S5M8767_REG_BUCK4DVS1,
+       S5M8767_REG_BUCK4DVS2,
+       S5M8767_REG_BUCK4DVS3,
+       S5M8767_REG_BUCK4DVS4,
+       S5M8767_REG_BUCK4DVS5,
+       S5M8767_REG_BUCK4DVS6,
+       S5M8767_REG_BUCK4DVS7,
+       S5M8767_REG_BUCK4DVS8,
+       S5M8767_REG_BUCK5CTRL1,
+       S5M8767_REG_BUCK5CTRL2,
+       S5M8767_REG_BUCK5CTRL3,
+       S5M8767_REG_BUCK5CTRL4,
+       S5M8767_REG_BUCK5CTRL5,
+       S5M8767_REG_BUCK6CTRL1,
+       S5M8767_REG_BUCK6CTRL2,
+       S5M8767_REG_BUCK7CTRL1,
+       S5M8767_REG_BUCK7CTRL2,
+       S5M8767_REG_BUCK8CTRL1,
+       S5M8767_REG_BUCK8CTRL2,
+       S5M8767_REG_BUCK9CTRL1,
+       S5M8767_REG_BUCK9CTRL2,
+       S5M8767_REG_LDO1CTRL,
+       S5M8767_REG_LDO2_1CTRL,
+       S5M8767_REG_LDO2_2CTRL,
+       S5M8767_REG_LDO2_3CTRL,
+       S5M8767_REG_LDO2_4CTRL,
+       S5M8767_REG_LDO3CTRL,
+       S5M8767_REG_LDO4CTRL,
+       S5M8767_REG_LDO5CTRL,
+       S5M8767_REG_LDO6CTRL,
+       S5M8767_REG_LDO7CTRL,
+       S5M8767_REG_LDO8CTRL,
+       S5M8767_REG_LDO9CTRL,
+       S5M8767_REG_LDO10CTRL,
+       S5M8767_REG_LDO11CTRL,
+       S5M8767_REG_LDO12CTRL,
+       S5M8767_REG_LDO13CTRL,
+       S5M8767_REG_LDO14CTRL,
+       S5M8767_REG_LDO15CTRL,
+       S5M8767_REG_LDO16CTRL,
+       S5M8767_REG_LDO17CTRL,
+       S5M8767_REG_LDO18CTRL,
+       S5M8767_REG_LDO19CTRL,
+       S5M8767_REG_LDO20CTRL,
+       S5M8767_REG_LDO21CTRL,
+       S5M8767_REG_LDO22CTRL,
+       S5M8767_REG_LDO23CTRL,
+       S5M8767_REG_LDO24CTRL,
+       S5M8767_REG_LDO25CTRL,
+       S5M8767_REG_LDO26CTRL,
+       S5M8767_REG_LDO27CTRL,
+       S5M8767_REG_LDO28CTRL,
+};
+
+/* S5M8767 regulator ids */
+enum s5m8767_regulators {
+       S5M8767_LDO1,
+       S5M8767_LDO2,
+       S5M8767_LDO3,
+       S5M8767_LDO4,
+       S5M8767_LDO5,
+       S5M8767_LDO6,
+       S5M8767_LDO7,
+       S5M8767_LDO8,
+       S5M8767_LDO9,
+       S5M8767_LDO10,
+       S5M8767_LDO11,
+       S5M8767_LDO12,
+       S5M8767_LDO13,
+       S5M8767_LDO14,
+       S5M8767_LDO15,
+       S5M8767_LDO16,
+       S5M8767_LDO17,
+       S5M8767_LDO18,
+       S5M8767_LDO19,
+       S5M8767_LDO20,
+       S5M8767_LDO21,
+       S5M8767_LDO22,
+       S5M8767_LDO23,
+       S5M8767_LDO24,
+       S5M8767_LDO25,
+       S5M8767_LDO26,
+       S5M8767_LDO27,
+       S5M8767_LDO28,
+       S5M8767_BUCK1,
+       S5M8767_BUCK2,
+       S5M8767_BUCK3,
+       S5M8767_BUCK4,
+       S5M8767_BUCK5,
+       S5M8767_BUCK6,
+       S5M8767_BUCK7,
+       S5M8767_BUCK8,
+       S5M8767_BUCK9,
+       S5M8767_AP_EN32KHZ,
+       S5M8767_CP_EN32KHZ,
+
+       S5M8767_REG_MAX,
+};
+
+#define S5M8767_ENCTRL_SHIFT  6
+
+#endif /* __LINUX_MFD_S5M8767_H */
index 6c4c478e21a4f79d33577db36faba4e9f37f3cd3..9bf8767818b450003dface8acf7585d4ce809059 100644 (file)
@@ -807,6 +807,7 @@ struct tps65910_board {
        int irq_base;
        int vmbch_threshold;
        int vmbch2_threshold;
+       bool en_ck32k_xtal;
        bool en_dev_slp;
        struct tps65910_sleep_keepon_data *slp_keepon;
        bool en_gpio_sleep[TPS6591X_MAX_NUM_GPIO];
index 6659487c31e7a010c96bcef991f05b546fa103d1..eaad49f7c130f0d148b0a7679bd4a6195194e422 100644 (file)
 #define TWL6040_CELLS                  2
 
 #define TWL6040_REV_ES1_0              0x00
-#define TWL6040_REV_ES1_1              0x01
-#define TWL6040_REV_ES1_2              0x02
+#define TWL6040_REV_ES1_1              0x01 /* Rev ES1.1 and ES1.2 */
+#define TWL6040_REV_ES1_3              0x02
+#define TWL6041_REV_ES2_0              0x10
 
 #define TWL6040_IRQ_TH                 0
 #define TWL6040_IRQ_PLUG               1
@@ -206,7 +207,6 @@ struct twl6040 {
        struct regmap *regmap;
        struct regulator_bulk_data supplies[2]; /* supplies for vio, v2v1 */
        struct mutex mutex;
-       struct mutex io_mutex;
        struct mutex irq_mutex;
        struct mfd_cell cells[TWL6040_CELLS];
        struct completion ready;
index 9192b6404a7347d5b6e665925a421cf1024d3c24..509481d9cf195b636ff3003ca89498b5697e3f00 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/mutex.h>
 #include <linux/interrupt.h>
 #include <linux/completion.h>
+#include <linux/regmap.h>
 
 #include <linux/mfd/wm8350/audio.h>
 #include <linux/mfd/wm8350/gpio.h>
@@ -66,6 +67,9 @@
 
 #define WM8350_MAX_REGISTER                     0xFF
 
+#define WM8350_UNLOCK_KEY              0x0013
+#define WM8350_LOCK_KEY                        0x0000
+
 /*
  * Field Definitions.
  */
 
 #define WM8350_NUM_IRQ_REGS 7
 
-struct wm8350_reg_access {
-       u16 readable;           /* Mask of readable bits */
-       u16 writable;           /* Mask of writable bits */
-       u16 vol;                /* Mask of volatile bits */
-};
-extern const struct wm8350_reg_access wm8350_reg_io_map[];
-extern const u16 wm8350_mode0_defaults[];
-extern const u16 wm8350_mode1_defaults[];
-extern const u16 wm8350_mode2_defaults[];
-extern const u16 wm8350_mode3_defaults[];
-extern const u16 wm8351_mode0_defaults[];
-extern const u16 wm8351_mode1_defaults[];
-extern const u16 wm8351_mode2_defaults[];
-extern const u16 wm8351_mode3_defaults[];
-extern const u16 wm8352_mode0_defaults[];
-extern const u16 wm8352_mode1_defaults[];
-extern const u16 wm8352_mode2_defaults[];
-extern const u16 wm8352_mode3_defaults[];
+extern const struct regmap_config wm8350_regmap;
 
 struct wm8350;
-struct regmap;
 
 struct wm8350_hwmon {
        struct platform_device *pdev;
@@ -614,7 +600,7 @@ struct wm8350 {
 
        /* device IO */
        struct regmap *regmap;
-       u16 *reg_cache;
+       bool unlocked;
 
        struct mutex auxadc_mutex;
        struct completion auxadc_done;
index 893267bb622932d9299f6f81f87c5d87ef0d0fe0..f0361c031927417ee9af47ef0a2be55e718e344d 100644 (file)
@@ -141,6 +141,7 @@ struct wm8994_pdata {
        struct wm8994_ldo_pdata ldo[WM8994_NUM_LDO];
 
        int irq_base;  /** Base IRQ number for WM8994, required for IRQs */
+       unsigned long irq_flags; /** user irq flags */
 
         int num_drc_cfgs;
         struct wm8994_drc_cfg *drc_cfgs;
index 704a626d94a08adc03b32b756d2d0a1c9a1f40cf..074eb98fe15dec4d7a8f01336875a91349d27a3e 100644 (file)
@@ -53,7 +53,7 @@ struct page {
        struct {
                union {
                        pgoff_t index;          /* Our offset within mapping. */
-                       void *freelist;         /* slub first free object */
+                       void *freelist;         /* slub/slob first free object */
                };
 
                union {
@@ -91,11 +91,12 @@ struct page {
                                         */
                                        atomic_t _mapcount;
 
-                                       struct {
+                                       struct { /* SLUB */
                                                unsigned inuse:16;
                                                unsigned objects:15;
                                                unsigned frozen:1;
                                        };
+                                       int units;      /* SLOB */
                                };
                                atomic_t _count;                /* Usage count, see below. */
                        };
@@ -117,6 +118,12 @@ struct page {
                        short int pobjects;
 #endif
                };
+
+               struct list_head list;  /* slobs list of pages */
+               struct {                /* slab fields */
+                       struct kmem_cache *slab_cache;
+                       struct slab *slab_page;
+               };
        };
 
        /* Remainder is not double word aligned */
index b23cfc120edb46c5b285de63edeff61fb03242ec..4b6043c20f7745be854b6fd95ba3fbd8fc450ec3 100644 (file)
@@ -427,10 +427,6 @@ extern __be32 root_nfs_parse_addr(char *name); /*__init*/
 /*
  * linux/fs/nfs/file.c
  */
-extern const struct inode_operations nfs_file_inode_operations;
-#ifdef CONFIG_NFS_V3
-extern const struct inode_operations nfs3_file_inode_operations;
-#endif /* CONFIG_NFS_V3 */
 extern const struct file_operations nfs_file_operations;
 #ifdef CONFIG_NFS_V4
 extern const struct file_operations nfs4_file_operations;
@@ -485,10 +481,6 @@ extern ssize_t nfs_file_direct_write(struct kiocb *iocb,
 /*
  * linux/fs/nfs/dir.c
  */
-extern const struct inode_operations nfs_dir_inode_operations;
-#ifdef CONFIG_NFS_V3
-extern const struct inode_operations nfs3_dir_inode_operations;
-#endif /* CONFIG_NFS_V3 */
 extern const struct file_operations nfs_dir_operations;
 extern const struct dentry_operations nfs_dentry_operations;
 
index f58325a1d8fbe290fb8a7eb6e4ddc060ef553f91..65327652c61a7941d043c5fe1058cba160299d1c 100644 (file)
@@ -69,10 +69,9 @@ struct nfs_client {
        struct idmap *          cl_idmap;
 
        /* Our own IP address, as a null-terminated string.
-        * This is used to generate the clientid, and the callback address.
+        * This is used to generate the mv0 callback address.
         */
        char                    cl_ipaddr[48];
-       unsigned char           cl_id_uniquifier;
        u32                     cl_cb_ident;    /* v4.0 callback identifier */
        const struct nfs4_minor_version_ops *cl_mvops;
 
index 88d166b555e8539fa8ec5cb896c56ecea7417bdc..880805774f9f105425a7eade9721b9965f7d43c9 100644 (file)
@@ -42,7 +42,7 @@ struct nfs_page {
                                wb_bytes;       /* Length of request */
        struct kref             wb_kref;        /* reference count */
        unsigned long           wb_flags;
-       struct nfs_writeverf    wb_verf;        /* Commit cookie */
+       struct nfs_write_verifier       wb_verf;        /* Commit cookie */
 };
 
 struct nfs_pageio_descriptor;
index d3b7c18b18f4e068997789bda6cc25be52720f8a..0e181c2320b7796bc9ed41cb3ebfc4c56a885339 100644 (file)
@@ -514,9 +514,13 @@ struct nfs_writeargs {
        struct nfs4_sequence_args       seq_args;
 };
 
+struct nfs_write_verifier {
+       char                    data[8];
+};
+
 struct nfs_writeverf {
+       struct nfs_write_verifier verifier;
        enum nfs3_stable_how    committed;
-       __be32                  verifier[2];
 };
 
 struct nfs_writeres {
@@ -1349,6 +1353,8 @@ struct nfs_renamedata {
 struct nfs_access_entry;
 struct nfs_client;
 struct rpc_timeout;
+struct nfs_client_initdata;
+struct nfs_pageio_descriptor;
 
 /*
  * RPC procedure vector for NFSv2/NFSv3 demuxing
@@ -1402,9 +1408,13 @@ struct nfs_rpc_ops {
        int     (*set_capabilities)(struct nfs_server *, struct nfs_fh *);
        int     (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int);
        void    (*read_setup)   (struct nfs_read_data *, struct rpc_message *);
+       void    (*read_pageio_init)(struct nfs_pageio_descriptor *, struct inode *,
+                                   const struct nfs_pgio_completion_ops *);
        void    (*read_rpc_prepare)(struct rpc_task *, struct nfs_read_data *);
        int     (*read_done)  (struct rpc_task *, struct nfs_read_data *);
        void    (*write_setup)  (struct nfs_write_data *, struct rpc_message *);
+       void    (*write_pageio_init)(struct nfs_pageio_descriptor *, struct inode *, int,
+                                    const struct nfs_pgio_completion_ops *);
        void    (*write_rpc_prepare)(struct rpc_task *, struct nfs_write_data *);
        int     (*write_done)  (struct rpc_task *, struct nfs_write_data *);
        void    (*commit_setup) (struct nfs_commit_data *, struct rpc_message *);
@@ -1418,9 +1428,13 @@ struct nfs_rpc_ops {
                                struct nfs_open_context *ctx,
                                int open_flags,
                                struct iattr *iattr);
+       int (*have_delegation)(struct inode *, fmode_t);
+       int (*return_delegation)(struct inode *);
+       struct nfs_client *(*alloc_client) (const struct nfs_client_initdata *);
        struct nfs_client *
                (*init_client) (struct nfs_client *, const struct rpc_timeout *,
                                const char *, rpc_authflavor_t);
+       void    (*free_client) (struct nfs_client *);
 };
 
 /*
index 89bd4a4dcfb44e379176a11e5fe6d9516025ecaf..98755767c7b067098443397aef09ecb145f0cd3e 100644 (file)
@@ -293,7 +293,7 @@ struct nilfs_dir_entry {
        __le64  inode;                  /* Inode number */
        __le16  rec_len;                /* Directory entry length */
        __u8    name_len;               /* Name length */
-       __u8    file_type;
+       __u8    file_type;              /* Dir entry type (file, dir, etc) */
        char    name[NILFS_NAME_LEN];   /* File name */
        char    pad;
 };
@@ -395,7 +395,7 @@ union nilfs_binfo {
 };
 
 /**
- * struct nilfs_segment_summary - segment summary
+ * struct nilfs_segment_summary - segment summary header
  * @ss_datasum: checksum of data
  * @ss_sumsum: checksum of segment summary
  * @ss_magic: magic number
@@ -683,9 +683,9 @@ struct nilfs_sufile_header {
 
 /**
  * nilfs_suinfo - segment usage information
- * @sui_lastmod:
- * @sui_nblocks:
- * @sui_flags:
+ * @sui_lastmod: timestamp of last modification
+ * @sui_nblocks: number of written blocks in segment
+ * @sui_flags: segment usage flags
  */
 struct nilfs_suinfo {
        __u64 sui_lastmod;
@@ -716,9 +716,10 @@ enum {
 };
 
 /**
- * struct nilfs_cpmode -
- * @cc_cno:
- * @cc_mode:
+ * struct nilfs_cpmode - change checkpoint mode structure
+ * @cm_cno: checkpoint number
+ * @cm_mode: mode of checkpoint
+ * @cm_pad: padding
  */
 struct nilfs_cpmode {
        __u64 cm_cno;
@@ -728,11 +729,11 @@ struct nilfs_cpmode {
 
 /**
  * struct nilfs_argv - argument vector
- * @v_base:
- * @v_nmembs:
- * @v_size:
- * @v_flags:
- * @v_index:
+ * @v_base: pointer on data array from userspace
+ * @v_nmembs: number of members in data array
+ * @v_size: size of data array in bytes
+ * @v_flags: flags
+ * @v_index: start number of target data items
  */
 struct nilfs_argv {
        __u64 v_base;
@@ -743,9 +744,9 @@ struct nilfs_argv {
 };
 
 /**
- * struct nilfs_period -
- * @p_start:
- * @p_end:
+ * struct nilfs_period - period of checkpoint numbers
+ * @p_start: start checkpoint number (inclusive)
+ * @p_end: end checkpoint number (exclusive)
  */
 struct nilfs_period {
        __u64 p_start;
@@ -753,7 +754,7 @@ struct nilfs_period {
 };
 
 /**
- * struct nilfs_cpstat -
+ * struct nilfs_cpstat - checkpoint statistics
  * @cs_cno: checkpoint number
  * @cs_ncps: number of checkpoints
  * @cs_nsss: number of snapshots
@@ -765,7 +766,7 @@ struct nilfs_cpstat {
 };
 
 /**
- * struct nilfs_sustat -
+ * struct nilfs_sustat - segment usage statistics
  * @ss_nsegs: number of segments
  * @ss_ncleansegs: number of clean segments
  * @ss_ndirtysegs: number of dirty segments
@@ -784,10 +785,10 @@ struct nilfs_sustat {
 
 /**
  * struct nilfs_vinfo - virtual block number information
- * @vi_vblocknr:
- * @vi_start:
- * @vi_end:
- * @vi_blocknr:
+ * @vi_vblocknr: virtual block number
+ * @vi_start: start checkpoint number (inclusive)
+ * @vi_end: end checkpoint number (exclusive)
+ * @vi_blocknr: disk block number
  */
 struct nilfs_vinfo {
        __u64 vi_vblocknr;
@@ -797,7 +798,15 @@ struct nilfs_vinfo {
 };
 
 /**
- * struct nilfs_vdesc -
+ * struct nilfs_vdesc - descriptor of virtual block number
+ * @vd_ino: inode number
+ * @vd_cno: checkpoint number
+ * @vd_vblocknr: virtual block number
+ * @vd_period: period of checkpoint numbers
+ * @vd_blocknr: disk block number
+ * @vd_offset: logical block offset inside a file
+ * @vd_flags: flags (data or node block)
+ * @vd_pad: padding
  */
 struct nilfs_vdesc {
        __u64 vd_ino;
@@ -811,7 +820,13 @@ struct nilfs_vdesc {
 };
 
 /**
- * struct nilfs_bdesc -
+ * struct nilfs_bdesc - descriptor of disk block number
+ * @bd_ino: inode number
+ * @bd_oblocknr: disk block address (for skipping dead blocks)
+ * @bd_blocknr: disk block address
+ * @bd_offset: logical block offset inside a file
+ * @bd_level: level in the b-tree organization
+ * @bd_pad: padding
  */
 struct nilfs_bdesc {
        __u64 bd_ino;
index 0e9cf9eec08595d2432d9ae9b16f703475b54d07..42c2a58328c17d40ef2571675a7c4f9cd383356f 100644 (file)
@@ -386,6 +386,13 @@ static inline int of_property_read_u64(const struct device_node *np,
        return -ENOSYS;
 }
 
+static inline int of_property_match_string(struct device_node *np,
+                                          const char *propname,
+                                          const char *string)
+{
+       return -ENOSYS;
+}
+
 static inline struct device_node *of_parse_phandle(struct device_node *np,
                                                   const char *phandle_name,
                                                   int index)
@@ -393,6 +400,15 @@ static inline struct device_node *of_parse_phandle(struct device_node *np,
        return NULL;
 }
 
+static inline int of_parse_phandle_with_args(struct device_node *np,
+                                            const char *list_name,
+                                            const char *cells_name,
+                                            int index,
+                                            struct of_phandle_args *out_args)
+{
+       return -ENOSYS;
+}
+
 static inline int of_alias_get_id(struct device_node *np, const char *stem)
 {
        return -ENOSYS;
similarity index 91%
rename from arch/arm/plat-nomadik/include/plat/i2c.h
rename to include/linux/platform_data/i2c-nomadik.h
index 8ba70ffc31ecaceb2adaf7d421eea9c900fe2b6a..c2303c3e4803577d4d0b2fb7533e4ddb1638a0e7 100644 (file)
@@ -5,8 +5,8 @@
  * it under the terms of the GNU General Public License version 2, as
  * published by the Free Software Foundation.
  */
-#ifndef __PLAT_I2C_H
-#define __PLAT_I2C_H
+#ifndef __PDATA_I2C_NOMADIK_H
+#define __PDATA_I2C_NOMADIK_H
 
 enum i2c_freq_mode {
        I2C_FREQ_MODE_STANDARD,         /* up to 100 Kb/s */
@@ -36,4 +36,4 @@ struct nmk_i2c_controller {
        enum i2c_freq_mode      sm;
 };
 
-#endif /* __PLAT_I2C_H */
+#endif /* __PDATA_I2C_NOMADIK_H */
similarity index 96%
rename from include/linux/lp855x.h
rename to include/linux/platform_data/lp855x.h
index 781a490a451b556168a0ab02c20b9e59d45c4018..cc76f1f18f18fc88b2c8cceb94901eb3976733ae 100644 (file)
                                (LP8556_I2C_ONLY << BRT_MODE_SHFT))
 #define LP8556_COMB2_CONFIG    (LP8556_COMBINED2 << BRT_MODE_SHFT)
 
-/* ROM area boundary */
-#define EEPROM_START   (0xA0)
-#define EEPROM_END     (0xA7)
-#define EPROM_START    (0xA0)
-#define EPROM_END      (0xAF)
-
 enum lp855x_chip_id {
        LP8550,
        LP8551,
index d94804aca764a24c94348f4e11bbd1ad451c725a..944b01dd103ef131b20784f6853524f9bd5812c2 100644 (file)
@@ -52,13 +52,4 @@ struct mv_usb_platform_data {
        int     (*set_vbus)(unsigned int vbus);
        int     (*private_init)(void __iomem *opregs, void __iomem *phyregs);
 };
-
-#ifndef CONFIG_HAVE_CLK
-/* Dummy stub for clk framework */
-#define clk_get(dev, id)       NULL
-#define clk_put(clock)         do {} while (0)
-#define clk_enable(clock)      do {} while (0)
-#define clk_disable(clock)     do {} while (0)
-#endif
-
 #endif
index 241065c9ce51832962f0fce4c93696d4b09dcb9d..cd22029e32aaf5adbd1b8136a3f48982705adbba 100644 (file)
@@ -16,6 +16,7 @@
 #define _CHARGER_MANAGER_H
 
 #include <linux/power_supply.h>
+#include <linux/extcon.h>
 
 enum data_source {
        CM_BATTERY_PRESENT,
@@ -64,6 +65,70 @@ struct charger_global_desc {
        bool assume_timer_stops_in_suspend;
 };
 
+/**
+ * struct charger_cable
+ * @extcon_name: the name of extcon device.
+ * @name: the name of charger cable(external connector).
+ * @extcon_dev: the extcon device.
+ * @wq: the workqueue to control charger according to the state of
+ *     charger cable. If charger cable is attached, enable charger.
+ *     But if charger cable is detached, disable charger.
+ * @nb: the notifier block to receive changed state from EXTCON
+ *     (External Connector) when charger cable is attached/detached.
+ * @attached: the state of charger cable.
+ *     true: the charger cable is attached
+ *     false: the charger cable is detached
+ * @charger: the instance of struct charger_regulator.
+ * @cm: the Charger Manager representing the battery.
+ */
+struct charger_cable {
+       const char *extcon_name;
+       const char *name;
+
+       /* The charger-manager use Exton framework*/
+       struct extcon_specific_cable_nb extcon_dev;
+       struct work_struct wq;
+       struct notifier_block nb;
+
+       /* The state of charger cable */
+       bool attached;
+
+       struct charger_regulator *charger;
+
+       /*
+        * Set min/max current of regulator to protect over-current issue
+        * according to a kind of charger cable when cable is attached.
+        */
+       int min_uA;
+       int max_uA;
+
+       struct charger_manager *cm;
+};
+
+/**
+ * struct charger_regulator
+ * @regulator_name: the name of regulator for using charger.
+ * @consumer: the regulator consumer for the charger.
+ * @cables:
+ *     the array of charger cables to enable/disable charger
+ *     and set current limit according to constratint data of
+ *     struct charger_cable if only charger cable included
+ *     in the array of charger cables is attached/detached.
+ * @num_cables: the number of charger cables.
+ */
+struct charger_regulator {
+       /* The name of regulator for charging */
+       const char *regulator_name;
+       struct regulator *consumer;
+
+       /*
+        * Store constraint information related to current limit,
+        * each cable have different condition for charging.
+        */
+       struct charger_cable *cables;
+       int num_cables;
+};
+
 /**
  * struct charger_desc
  * @psy_name: the name of power-supply-class for charger manager
@@ -109,7 +174,7 @@ struct charger_desc {
        char **psy_charger_stat;
 
        int num_charger_regulators;
-       struct regulator_bulk_data *charger_regulators;
+       struct charger_regulator *charger_regulators;
 
        char *psy_fuel_gauge;
 
index 3b912bee28d1693b8c6617f637354ed2869d306f..0bafbb15f29cf55fb76672972bdc4b947bb2fa2c 100644 (file)
@@ -109,6 +109,8 @@ enum power_supply_property {
        POWER_SUPPLY_PROP_CHARGE_NOW,
        POWER_SUPPLY_PROP_CHARGE_AVG,
        POWER_SUPPLY_PROP_CHARGE_COUNTER,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
        POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
        POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
        POWER_SUPPLY_PROP_ENERGY_FULL,
@@ -116,9 +118,15 @@ enum power_supply_property {
        POWER_SUPPLY_PROP_ENERGY_NOW,
        POWER_SUPPLY_PROP_ENERGY_AVG,
        POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
+       POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN, /* in percents! */
+       POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX, /* in percents! */
        POWER_SUPPLY_PROP_CAPACITY_LEVEL,
        POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
+       POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
        POWER_SUPPLY_PROP_TEMP_AMBIENT,
+       POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN,
+       POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX,
        POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
        POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
        POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
@@ -173,6 +181,9 @@ struct power_supply {
        /* private */
        struct device *dev;
        struct work_struct changed_work;
+#ifdef CONFIG_THERMAL
+       struct thermal_zone_device *tzd;
+#endif
 
 #ifdef CONFIG_LEDS_TRIGGERS
        struct led_trigger *charging_full_trig;
@@ -236,6 +247,7 @@ static inline bool power_supply_is_amp_property(enum power_supply_property psp)
        case POWER_SUPPLY_PROP_CHARGE_NOW:
        case POWER_SUPPLY_PROP_CHARGE_AVG:
        case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
        case POWER_SUPPLY_PROP_CURRENT_MAX:
        case POWER_SUPPLY_PROP_CURRENT_NOW:
        case POWER_SUPPLY_PROP_CURRENT_AVG:
@@ -263,6 +275,7 @@ static inline bool power_supply_is_watt_property(enum power_supply_property psp)
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
        case POWER_SUPPLY_PROP_VOLTAGE_AVG:
        case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
        case POWER_SUPPLY_PROP_POWER_NOW:
                return 1;
        default:
index 1bec2f7a2d4236488af252d138188fa7c29e8369..9afc01e5a0a61ce5f4a9fe1e53ad6e0fb1b8e5bf 100644 (file)
@@ -2,27 +2,34 @@
 #define __KERNEL_PRINTK__
 
 #include <linux/init.h>
+#include <linux/kern_levels.h>
 
 extern const char linux_banner[];
 extern const char linux_proc_banner[];
 
-#define KERN_EMERG     "<0>"   /* system is unusable                   */
-#define KERN_ALERT     "<1>"   /* action must be taken immediately     */
-#define KERN_CRIT      "<2>"   /* critical conditions                  */
-#define KERN_ERR       "<3>"   /* error conditions                     */
-#define KERN_WARNING   "<4>"   /* warning conditions                   */
-#define KERN_NOTICE    "<5>"   /* normal but significant condition     */
-#define KERN_INFO      "<6>"   /* informational                        */
-#define KERN_DEBUG     "<7>"   /* debug-level messages                 */
-
-/* Use the default kernel loglevel */
-#define KERN_DEFAULT   "<d>"
-/*
- * Annotation for a "continued" line of log printout (only done after a
- * line that had no enclosing \n). Only to be used by core/arch code
- * during early bootup (a continued line is not SMP-safe otherwise).
- */
-#define KERN_CONT      "<c>"
+static inline int printk_get_level(const char *buffer)
+{
+       if (buffer[0] == KERN_SOH_ASCII && buffer[1]) {
+               switch (buffer[1]) {
+               case '0' ... '7':
+               case 'd':       /* KERN_DEFAULT */
+                       return buffer[1];
+               }
+       }
+       return 0;
+}
+
+static inline const char *printk_skip_level(const char *buffer)
+{
+       if (printk_get_level(buffer)) {
+               switch (buffer[1]) {
+               case '0' ... '7':
+               case 'd':       /* KERN_DEFAULT */
+                       return buffer + 2;
+               }
+       }
+       return buffer;
+}
 
 extern int console_printk[];
 
index 7c775751392c58003a896a0c2741cb134343ce9d..21d076c5089e9646418113fb9d27d30e4ba109f7 100644 (file)
@@ -1,7 +1,10 @@
 #ifndef __LINUX_PWM_H
 #define __LINUX_PWM_H
 
+#include <linux/of.h>
+
 struct pwm_device;
+struct seq_file;
 
 /*
  * pwm_request - request a PWM device
@@ -28,4 +31,118 @@ int pwm_enable(struct pwm_device *pwm);
  */
 void pwm_disable(struct pwm_device *pwm);
 
+#ifdef CONFIG_PWM
+struct pwm_chip;
+
+enum {
+       PWMF_REQUESTED = 1 << 0,
+       PWMF_ENABLED = 1 << 1,
+};
+
+struct pwm_device {
+       const char              *label;
+       unsigned long           flags;
+       unsigned int            hwpwm;
+       unsigned int            pwm;
+       struct pwm_chip         *chip;
+       void                    *chip_data;
+
+       unsigned int            period; /* in nanoseconds */
+};
+
+static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
+{
+       if (pwm)
+               pwm->period = period;
+}
+
+static inline unsigned int pwm_get_period(struct pwm_device *pwm)
+{
+       return pwm ? pwm->period : 0;
+}
+
+/**
+ * struct pwm_ops - PWM controller operations
+ * @request: optional hook for requesting a PWM
+ * @free: optional hook for freeing a PWM
+ * @config: configure duty cycles and period length for this PWM
+ * @enable: enable PWM output toggling
+ * @disable: disable PWM output toggling
+ * @dbg_show: optional routine to show contents in debugfs
+ * @owner: helps prevent removal of modules exporting active PWMs
+ */
+struct pwm_ops {
+       int                     (*request)(struct pwm_chip *chip,
+                                          struct pwm_device *pwm);
+       void                    (*free)(struct pwm_chip *chip,
+                                       struct pwm_device *pwm);
+       int                     (*config)(struct pwm_chip *chip,
+                                         struct pwm_device *pwm,
+                                         int duty_ns, int period_ns);
+       int                     (*enable)(struct pwm_chip *chip,
+                                         struct pwm_device *pwm);
+       void                    (*disable)(struct pwm_chip *chip,
+                                          struct pwm_device *pwm);
+#ifdef CONFIG_DEBUG_FS
+       void                    (*dbg_show)(struct pwm_chip *chip,
+                                           struct seq_file *s);
+#endif
+       struct module           *owner;
+};
+
+/**
+ * struct pwm_chip - abstract a PWM controller
+ * @dev: device providing the PWMs
+ * @list: list node for internal use
+ * @ops: callbacks for this PWM controller
+ * @base: number of first PWM controlled by this chip
+ * @npwm: number of PWMs controlled by this chip
+ * @pwms: array of PWM devices allocated by the framework
+ */
+struct pwm_chip {
+       struct device           *dev;
+       struct list_head        list;
+       const struct pwm_ops    *ops;
+       int                     base;
+       unsigned int            npwm;
+
+       struct pwm_device       *pwms;
+
+       struct pwm_device *     (*of_xlate)(struct pwm_chip *pc,
+                                           const struct of_phandle_args *args);
+       unsigned int            of_pwm_n_cells;
+};
+
+int pwm_set_chip_data(struct pwm_device *pwm, void *data);
+void *pwm_get_chip_data(struct pwm_device *pwm);
+
+int pwmchip_add(struct pwm_chip *chip);
+int pwmchip_remove(struct pwm_chip *chip);
+struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
+                                        unsigned int index,
+                                        const char *label);
+
+struct pwm_device *pwm_get(struct device *dev, const char *consumer);
+void pwm_put(struct pwm_device *pwm);
+
+struct pwm_lookup {
+       struct list_head list;
+       const char *provider;
+       unsigned int index;
+       const char *dev_id;
+       const char *con_id;
+};
+
+#define PWM_LOOKUP(_provider, _index, _dev_id, _con_id)        \
+       {                                               \
+               .provider = _provider,                  \
+               .index = _index,                        \
+               .dev_id = _dev_id,                      \
+               .con_id = _con_id,                      \
+       }
+
+void pwm_add_table(struct pwm_lookup *table, size_t num);
+
+#endif
+
 #endif /* __LINUX_PWM_H */
index 63d2df43e61a1999206d15b6d06f3567b9ac8f9e..56f4a866539ad7b66476fc3d1c09d15ab8ad2be1 100644 (file)
@@ -12,6 +12,7 @@ struct platform_pwm_backlight_data {
        unsigned int dft_brightness;
        unsigned int lth_brightness;
        unsigned int pwm_period_ns;
+       unsigned int *levels;
        int (*init)(struct device *dev);
        int (*notify)(struct device *dev, int brightness);
        void (*notify_after)(struct device *dev, int brightness);
index ac9586dadfa58bdbade8fbb8391ea023d6d491aa..7b600da9a635027393368715a43e0a2a44827db0 100644 (file)
@@ -214,6 +214,10 @@ void sg_free_table(struct sg_table *);
 int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int, gfp_t,
                     sg_alloc_fn *);
 int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
+int sg_alloc_table_from_pages(struct sg_table *sgt,
+       struct page **pages, unsigned int n_pages,
+       unsigned long offset, unsigned long size,
+       gfp_t gfp_mask);
 
 size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
                           void *buf, size_t buflen);
index a721cef7e2d47eb2059540c9224fa882adaa7428..68dcffaa62a032728284c40f991f33e0266e4461 100644 (file)
@@ -334,6 +334,14 @@ static inline void lockup_detector_init(void)
 }
 #endif
 
+#if defined(CONFIG_LOCKUP_DETECTOR) && defined(CONFIG_SUSPEND)
+void lockup_detector_bootcpu_resume(void);
+#else
+static inline void lockup_detector_bootcpu_resume(void)
+{
+}
+#endif
+
 #ifdef CONFIG_DETECT_HUNG_TASK
 extern unsigned int  sysctl_hung_task_panic;
 extern unsigned long sysctl_hung_task_check_count;
@@ -406,6 +414,11 @@ static inline void arch_pick_mmap_layout(struct mm_struct *mm) {}
 extern void set_dumpable(struct mm_struct *mm, int value);
 extern int get_dumpable(struct mm_struct *mm);
 
+/* get/set_dumpable() values */
+#define SUID_DUMPABLE_DISABLED 0
+#define SUID_DUMPABLE_ENABLED  1
+#define SUID_DUMPABLE_SAFE     2
+
 /* mm flags */
 /* dumpable bits */
 #define MMF_DUMPABLE      0  /* core dump is permitted */
index 92808b86703ba7a63f786407144ec28f10ad13bc..edd086883ccbed5a84f2d44e0212d06b1af315a4 100644 (file)
@@ -107,12 +107,14 @@ struct shmid_kernel /* private to the kernel */
 #define SHM_NORESERVE   010000  /* don't check for reservations */
 
 #ifdef CONFIG_SYSVIPC
-long do_shmat(int shmid, char __user *shmaddr, int shmflg, unsigned long *addr);
+long do_shmat(int shmid, char __user *shmaddr, int shmflg, unsigned long *addr,
+             unsigned long shmlba);
 extern int is_file_shm_hugepages(struct file *file);
 extern void exit_shm(struct task_struct *task);
 #else
 static inline long do_shmat(int shmid, char __user *shmaddr,
-                               int shmflg, unsigned long *addr)
+                           int shmflg, unsigned long *addr,
+                           unsigned long shmlba)
 {
        return -ENOSYS;
 }
index 67d5d94b783a4b4ba97b53fc9d0adf9fd885af34..0dd2dfa7becadd196849e0d9ff003a7dcd7f9b45 100644 (file)
 #define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= \
                                (unsigned long)ZERO_SIZE_PTR)
 
+/*
+ * Common fields provided in kmem_cache by all slab allocators
+ * This struct is either used directly by the allocator (SLOB)
+ * or the allocator must include definitions for all fields
+ * provided in kmem_cache_common in their definition of kmem_cache.
+ *
+ * Once we can do anonymous structs (C11 standard) we could put a
+ * anonymous struct definition in these allocators so that the
+ * separate allocations in the kmem_cache structure of SLAB and
+ * SLUB is no longer needed.
+ */
+#ifdef CONFIG_SLOB
+struct kmem_cache {
+       unsigned int object_size;/* The original size of the object */
+       unsigned int size;      /* The aligned/padded/added on size  */
+       unsigned int align;     /* Alignment as calculated */
+       unsigned long flags;    /* Active flags on the slab */
+       const char *name;       /* Slab name for sysfs */
+       int refcount;           /* Use counter */
+       void (*ctor)(void *);   /* Called on object slot creation */
+       struct list_head list;  /* List of all slab caches on the system */
+};
+#endif
+
 /*
  * struct kmem_cache related prototypes
  */
index fbd1117fdfde9fce2b059a4e9283b803d14f43d6..0c634fa376c94b213bc295fb6372d60448623d83 100644 (file)
@@ -27,7 +27,7 @@ struct kmem_cache {
        unsigned int limit;
        unsigned int shared;
 
-       unsigned int buffer_size;
+       unsigned int size;
        u32 reciprocal_buffer_size;
 /* 2) touched by every alloc & free from the backend */
 
@@ -39,7 +39,7 @@ struct kmem_cache {
        unsigned int gfporder;
 
        /* force GFP flags, e.g. GFP_DMA */
-       gfp_t gfpflags;
+       gfp_t allocflags;
 
        size_t colour;                  /* cache colouring range */
        unsigned int colour_off;        /* colour offset */
@@ -52,7 +52,10 @@ struct kmem_cache {
 
 /* 4) cache creation/removal */
        const char *name;
-       struct list_head next;
+       struct list_head list;
+       int refcount;
+       int object_size;
+       int align;
 
 /* 5) statistics */
 #ifdef CONFIG_DEBUG_SLAB
@@ -73,12 +76,11 @@ struct kmem_cache {
 
        /*
         * If debugging is enabled, then the allocator can add additional
-        * fields and/or padding to every object. buffer_size contains the total
+        * fields and/or padding to every object. size contains the total
         * object size including these internal fields, the following two
         * variables contain the offset to the user object and its size.
         */
        int obj_offset;
-       int obj_size;
 #endif /* CONFIG_DEBUG_SLAB */
 
 /* 6) per-cpu/per-node data, touched during every alloc/free */
index c2f8c8bc56edd08183dd0dd22b4f7d3b39f1c63d..df448adb7283fa534edf23656b1c90b6e27982b0 100644 (file)
@@ -48,7 +48,6 @@ struct kmem_cache_cpu {
        unsigned long tid;      /* Globally unique transaction id */
        struct page *page;      /* The slab from which we are allocating */
        struct page *partial;   /* Partially allocated frozen slabs */
-       int node;               /* The node of the page (or -1 for debug) */
 #ifdef CONFIG_SLUB_STATS
        unsigned stat[NR_SLUB_STAT_ITEMS];
 #endif
@@ -83,7 +82,7 @@ struct kmem_cache {
        unsigned long flags;
        unsigned long min_partial;
        int size;               /* The size of an object including meta data */
-       int objsize;            /* The size of an object without meta data */
+       int object_size;        /* The size of an object without meta data */
        int offset;             /* Free pointer offset. */
        int cpu_partial;        /* Number of per cpu partial objects to keep around */
        struct kmem_cache_order_objects oo;
index e033564f10baec5b9b39a75c29f956f5d512e7c4..ffe0442e18d2f4e2d7b8d8eb8f22ffbc532e67e4 100644 (file)
@@ -145,4 +145,7 @@ static inline bool strstarts(const char *str, const char *prefix)
        return strncmp(str, prefix, strlen(prefix)) == 0;
 }
 #endif
+
+extern size_t memweight(const void *ptr, size_t bytes);
+
 #endif /* _LINUX_STRING_H_ */
index 492a36d72829939c21f6c4ff3f5bd412956b2a95..f25ba922baaf022dc3814f9705a5fd51749d1422 100644 (file)
@@ -101,6 +101,7 @@ struct rpc_authops {
        struct rpc_cred *       (*crcreate)(struct rpc_auth*, struct auth_cred *, int);
        int                     (*pipes_create)(struct rpc_auth *);
        void                    (*pipes_destroy)(struct rpc_auth *);
+       int                     (*list_pseudoflavors)(rpc_authflavor_t *, int);
 };
 
 struct rpc_credops {
@@ -135,6 +136,7 @@ int                 rpcauth_register(const struct rpc_authops *);
 int                    rpcauth_unregister(const struct rpc_authops *);
 struct rpc_auth *      rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
 void                   rpcauth_release(struct rpc_auth *);
+int                    rpcauth_list_flavors(rpc_authflavor_t *, int);
 struct rpc_cred *      rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int);
 void                   rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
 struct rpc_cred *      rpcauth_lookupcred(struct rpc_auth *, int);
index f5fd6160dbca396835773609586e65071f9c78ab..f792794f66341a5888136e6697322f445ba62197 100644 (file)
@@ -217,14 +217,32 @@ extern int qword_get(char **bpp, char *dest, int bufsize);
 static inline int get_int(char **bpp, int *anint)
 {
        char buf[50];
-       char *ep;
-       int rv;
-       int len = qword_get(bpp, buf, 50);
-       if (len < 0) return -EINVAL;
-       if (len ==0) return -ENOENT;
-       rv = simple_strtol(buf, &ep, 0);
-       if (*ep) return -EINVAL;
-       *anint = rv;
+       int len = qword_get(bpp, buf, sizeof(buf));
+
+       if (len < 0)
+               return -EINVAL;
+       if (len == 0)
+               return -ENOENT;
+
+       if (kstrtoint(buf, 0, anint))
+               return -EINVAL;
+
+       return 0;
+}
+
+static inline int get_uint(char **bpp, unsigned int *anint)
+{
+       char buf[50];
+       int len = qword_get(bpp, buf, sizeof(buf));
+
+       if (len < 0)
+               return -EINVAL;
+       if (len == 0)
+               return -ENOENT;
+
+       if (kstrtouint(buf, 0, anint))
+               return -EINVAL;
+
        return 0;
 }
 
index 332da61cf8b71fc73d802b2609210f46641a9ea1..a19e2547ae6aba4481ba4cd01f5bdbbf7545de22 100644 (file)
@@ -14,6 +14,7 @@
 
 #ifdef __KERNEL__
 #include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/msg_prot.h>
 #include <linux/uio.h>
 
 /* The mechanism-independent gss-api context: */
@@ -127,7 +128,7 @@ struct gss_api_mech *gss_mech_get_by_name(const char *);
 struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32);
 
 /* Fill in an array with a list of supported pseudoflavors */
-int gss_mech_list_pseudoflavors(u32 *);
+int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int);
 
 /* Just increments the mechanism's reference count and returns its input: */
 struct gss_api_mech * gss_mech_get(struct gss_api_mech *);
index 40e0a273faea3c07470e19fd23673fda89543f9b..d83db800fe02eeabbfc96f76e56a2662cce7c0cf 100644 (file)
@@ -278,6 +278,8 @@ struct svc_rqst {
        struct task_struct      *rq_task;       /* service thread */
 };
 
+#define SVC_NET(svc_rqst)      (svc_rqst->rq_xprt->xpt_net)
+
 /*
  * Rigorous type checking on sockaddr type conversions
  */
index af70af3335461ee587d23a8567a9abdb9cc23eb9..63988990bd36d5c81e8537cd1ef1ef2961c30ed6 100644 (file)
@@ -104,8 +104,6 @@ __be32 *xdr_decode_string_inplace(__be32 *p, char **sp, unsigned int *lenp,
 __be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *);
 __be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *);
 
-void   xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int,
-                        unsigned int);
 void   xdr_inline_pages(struct xdr_buf *, unsigned int,
                         struct page **, unsigned int, unsigned int);
 void   xdr_terminate_string(struct xdr_buf *, const u32);
@@ -205,6 +203,7 @@ struct xdr_stream {
        struct kvec *iov;       /* pointer to the current kvec */
        struct kvec scratch;    /* Scratch buffer */
        struct page **page_ptr; /* pointer to the current page */
+       unsigned int nwords;    /* Remaining decode buffer length */
 };
 
 /*
@@ -217,12 +216,13 @@ extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32
 extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
 extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
                unsigned int base, unsigned int len);
+extern unsigned int xdr_stream_pos(const struct xdr_stream *xdr);
 extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
 extern void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
                struct page **pages, unsigned int len);
 extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen);
 extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
-extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
+extern unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
 extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
 extern int xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data);
 
index cfc8d908892e849a3bb8a3336a8225bae554d0eb..4b94a61955df361934984992b37e185b8d933f87 100644 (file)
@@ -151,7 +151,7 @@ enum {
 };
 #define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)
 
-struct thermal_zone_device *thermal_zone_device_register(char *, int, int,
+struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
                void *, const struct thermal_zone_device_ops *, int tc1,
                int tc2, int passive_freq, int polling_freq);
 void thermal_zone_device_unregister(struct thermal_zone_device *);
index f46a53f060d7dd976b6767123d92a6f039a5ce0d..3b081862b9e89dcf50ab324fc77dd71ab2dfcdf6 100644 (file)
@@ -58,7 +58,8 @@ struct uvc_xu_control_mapping {
 struct uvc_xu_control_query {
        __u8 unit;
        __u8 selector;
-       __u8 query;
+       __u8 query;             /* Video Class-Specific Request Code, */
+                               /* defined in linux/usb/video.h A.8.  */
        __u16 size;
        __u8 __user *data;
 };
diff --git a/include/linux/v4l2-common.h b/include/linux/v4l2-common.h
new file mode 100644 (file)
index 0000000..0fa8b64
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * include/linux/v4l2-common.h
+ *
+ * Common V4L2 and V4L2 subdev definitions.
+ *
+ * Users are advised to #include this file either through videodev2.h
+ * (V4L2) or through v4l2-subdev.h (V4L2 subdev) rather than to refer
+ * to this file directly.
+ *
+ * Copyright (C) 2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __V4L2_COMMON__
+#define __V4L2_COMMON__
+
+/*
+ *
+ * Selection interface definitions
+ *
+ */
+
+/* Current cropping area */
+#define V4L2_SEL_TGT_CROP              0x0000
+/* Default cropping area */
+#define V4L2_SEL_TGT_CROP_DEFAULT      0x0001
+/* Cropping bounds */
+#define V4L2_SEL_TGT_CROP_BOUNDS       0x0002
+/* Current composing area */
+#define V4L2_SEL_TGT_COMPOSE           0x0100
+/* Default composing area */
+#define V4L2_SEL_TGT_COMPOSE_DEFAULT   0x0101
+/* Composing bounds */
+#define V4L2_SEL_TGT_COMPOSE_BOUNDS    0x0102
+/* Current composing area plus all padding pixels */
+#define V4L2_SEL_TGT_COMPOSE_PADDED    0x0103
+
+/* Backward compatibility target definitions --- to be removed. */
+#define V4L2_SEL_TGT_CROP_ACTIVE       V4L2_SEL_TGT_CROP
+#define V4L2_SEL_TGT_COMPOSE_ACTIVE    V4L2_SEL_TGT_COMPOSE
+#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL \
+       V4L2_SEL_TGT_CROP
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL \
+       V4L2_SEL_TGT_COMPOSE
+
+/* Selection flags */
+#define V4L2_SEL_FLAG_GE               (1 << 0)
+#define V4L2_SEL_FLAG_LE               (1 << 1)
+#define V4L2_SEL_FLAG_KEEP_CONFIG      (1 << 2)
+
+/* Backward compatibility flag definitions --- to be removed. */
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_GE   V4L2_SEL_FLAG_GE
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_LE   V4L2_SEL_FLAG_LE
+#define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG V4L2_SEL_FLAG_KEEP_CONFIG
+
+#endif /* __V4L2_COMMON__ */
index 812019ee1e0665b58079ef90072655b3406a07a5..8c57ee9872bb429ea6e27cbe839326e9281ecd1f 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/ioctl.h>
 #include <linux/types.h>
+#include <linux/v4l2-common.h>
 #include <linux/v4l2-mediabus.h>
 
 /**
@@ -123,27 +124,14 @@ struct v4l2_subdev_frame_interval_enum {
        __u32 reserved[9];
 };
 
-#define V4L2_SUBDEV_SEL_FLAG_SIZE_GE                   (1 << 0)
-#define V4L2_SUBDEV_SEL_FLAG_SIZE_LE                   (1 << 1)
-#define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG               (1 << 2)
-
-/* active cropping area */
-#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL                        0x0000
-/* cropping bounds */
-#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS                        0x0002
-/* current composing area */
-#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL             0x0100
-/* composing bounds */
-#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS             0x0102
-
-
 /**
  * struct v4l2_subdev_selection - selection info
  *
  * @which: either V4L2_SUBDEV_FORMAT_ACTIVE or V4L2_SUBDEV_FORMAT_TRY
  * @pad: pad number, as reported by the media API
- * @target: selection target, used to choose one of possible rectangles
- * @flags: constraint flags
+ * @target: Selection target, used to choose one of possible rectangles,
+ *         defined in v4l2-common.h; V4L2_SEL_TGT_* .
+ * @flags: constraint flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
  * @r: coordinates of the selection window
  * @reserved: for future use, set to zero for now
  *
index 2039c5d3292e801c0abb8c770c99cdfe287ce9bf..5d78910f926cbdaad3bfe01132e10f0cb8a7cac2 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/compiler.h>
 #include <linux/ioctl.h>
 #include <linux/types.h>
+#include <linux/v4l2-common.h>
 
 /*
  * Common stuff for both V4L1 and V4L2
@@ -657,7 +658,7 @@ struct v4l2_buffer {
                struct v4l2_plane *planes;
        } m;
        __u32                   length;
-       __u32                   input;
+       __u32                   reserved2;
        __u32                   reserved;
 };
 
@@ -671,7 +672,6 @@ struct v4l2_buffer {
 /* Buffer is ready, but the data contained within is corrupted. */
 #define V4L2_BUF_FLAG_ERROR    0x0040
 #define V4L2_BUF_FLAG_TIMECODE 0x0100  /* timecode field is valid */
-#define V4L2_BUF_FLAG_INPUT     0x0200  /* input field is valid */
 #define V4L2_BUF_FLAG_PREPARED 0x0400  /* Buffer is prepared for queuing */
 /* Cache handling flags */
 #define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE      0x0800
@@ -761,32 +761,12 @@ struct v4l2_crop {
        struct v4l2_rect        c;
 };
 
-/* Hints for adjustments of selection rectangle */
-#define V4L2_SEL_FLAG_GE       0x00000001
-#define V4L2_SEL_FLAG_LE       0x00000002
-
-/* Selection targets */
-
-/* Current cropping area */
-#define V4L2_SEL_TGT_CROP_ACTIVE       0x0000
-/* Default cropping area */
-#define V4L2_SEL_TGT_CROP_DEFAULT      0x0001
-/* Cropping bounds */
-#define V4L2_SEL_TGT_CROP_BOUNDS       0x0002
-/* Current composing area */
-#define V4L2_SEL_TGT_COMPOSE_ACTIVE    0x0100
-/* Default composing area */
-#define V4L2_SEL_TGT_COMPOSE_DEFAULT   0x0101
-/* Composing bounds */
-#define V4L2_SEL_TGT_COMPOSE_BOUNDS    0x0102
-/* Current composing area plus all padding pixels */
-#define V4L2_SEL_TGT_COMPOSE_PADDED    0x0103
-
 /**
  * struct v4l2_selection - selection info
  * @type:      buffer type (do not use *_MPLANE types)
- * @target:    selection target, used to choose one of possible rectangles
- * @flags:     constraints flags
+ * @target:    Selection target, used to choose one of possible rectangles;
+ *             defined in v4l2-common.h; V4L2_SEL_TGT_* .
+ * @flags:     constraints flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
  * @r:         coordinates of selection window
  * @reserved:  for future use, rounds structure size to 64 bytes, set to zero
  *
@@ -2039,6 +2019,8 @@ struct v4l2_modulator {
 /*  Flags for the 'capability' field */
 #define V4L2_TUNER_CAP_LOW             0x0001
 #define V4L2_TUNER_CAP_NORM            0x0002
+#define V4L2_TUNER_CAP_HWSEEK_BOUNDED  0x0004
+#define V4L2_TUNER_CAP_HWSEEK_WRAP     0x0008
 #define V4L2_TUNER_CAP_STEREO          0x0010
 #define V4L2_TUNER_CAP_LANG2           0x0020
 #define V4L2_TUNER_CAP_SAP             0x0020
index e0edb40ca7aaca3ffeeb9261fa017eedd6548291..6d8e61c48563a41a56379643585d610cff7f096a 100644 (file)
 #define VIRTIO_BLK_F_RO                5       /* Disk is read-only */
 #define VIRTIO_BLK_F_BLK_SIZE  6       /* Block size of disk is available*/
 #define VIRTIO_BLK_F_SCSI      7       /* Supports scsi command passthru */
-#define VIRTIO_BLK_F_FLUSH     9       /* Cache flush command support */
+#define VIRTIO_BLK_F_WCE       9       /* Writeback mode enabled after reset */
 #define VIRTIO_BLK_F_TOPOLOGY  10      /* Topology information is available */
+#define VIRTIO_BLK_F_CONFIG_WCE        11      /* Writeback mode available in config */
+
+#ifndef __KERNEL__
+/* Old (deprecated) name for VIRTIO_BLK_F_WCE. */
+#define VIRTIO_BLK_F_FLUSH VIRTIO_BLK_F_WCE
+#endif
 
 #define VIRTIO_BLK_ID_BYTES    20      /* ID string length */
 
@@ -69,6 +75,8 @@ struct virtio_blk_config {
        /* optimal sustained I/O size in logical blocks. */
        __u32 opt_io_size;
 
+       /* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */
+       __u8 wce;
 } __attribute__((packed));
 
 /*
index 7529b854b7fd96ff11608f41313454e658ee25f8..270fb22c58112870fc848fac55d9102397897b65 100644 (file)
@@ -32,7 +32,7 @@
 #define VIRTIO_ID_NET          1 /* virtio net */
 #define VIRTIO_ID_BLOCK                2 /* virtio block */
 #define VIRTIO_ID_CONSOLE      3 /* virtio console */
-#define VIRTIO_ID_RNG          4 /* virtio ring */
+#define VIRTIO_ID_RNG          4 /* virtio rng */
 #define VIRTIO_ID_BALLOON      5 /* virtio balloon */
 #define VIRTIO_ID_RPMSG                7 /* virtio remote processor messaging */
 #define VIRTIO_ID_SCSI         8 /* virtio scsi */
index dcdfc2bda922eb7012d59fe7eb330aabd1a5c24e..6071e911c7f4deff2258ea404416f133c4b6ec36 100644 (file)
@@ -32,7 +32,7 @@ struct vm_struct {
        struct page             **pages;
        unsigned int            nr_pages;
        phys_addr_t             phys_addr;
-       void                    *caller;
+       const void              *caller;
 };
 
 /*
@@ -62,7 +62,7 @@ extern void *vmalloc_32_user(unsigned long size);
 extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot);
 extern void *__vmalloc_node_range(unsigned long size, unsigned long align,
                        unsigned long start, unsigned long end, gfp_t gfp_mask,
-                       pgprot_t prot, int node, void *caller);
+                       pgprot_t prot, int node, const void *caller);
 extern void vfree(const void *addr);
 
 extern void *vmap(struct page **pages, unsigned int count,
@@ -85,14 +85,15 @@ static inline size_t get_vm_area_size(const struct vm_struct *area)
 
 extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
 extern struct vm_struct *get_vm_area_caller(unsigned long size,
-                                       unsigned long flags, void *caller);
+                                       unsigned long flags, const void *caller);
 extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
                                        unsigned long start, unsigned long end);
 extern struct vm_struct *__get_vm_area_caller(unsigned long size,
                                        unsigned long flags,
                                        unsigned long start, unsigned long end,
-                                       void *caller);
+                                       const void *caller);
 extern struct vm_struct *remove_vm_area(const void *addr);
+extern struct vm_struct *find_vm_area(const void *addr);
 
 extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
                        struct page ***pages);
diff --git a/include/media/adv7393.h b/include/media/adv7393.h
new file mode 100644 (file)
index 0000000..b28edf3
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * ADV7393 header file
+ *
+ * Copyright (C) 2010-2012 ADVANSEE - http://www.advansee.com/
+ * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
+ *
+ * Based on ADV7343 driver,
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef ADV7393_H
+#define ADV7393_H
+
+#define ADV7393_COMPOSITE_ID   (0)
+#define ADV7393_COMPONENT_ID   (1)
+#define ADV7393_SVIDEO_ID      (2)
+
+#endif                         /* End of #ifndef ADV7393_H */
index 67797bf5d432f6a648961c742d70ed1d008d0199..0142736a59db86a3dff4c9592793c6f6f6193e72 100644 (file)
 #define __GPIO_IR_RECV_H__
 
 struct gpio_ir_recv_platform_data {
-       int gpio_nr;
-       bool active_low;
+       int             gpio_nr;
+       bool            active_low;
+       u64             allowed_protos;
+       const char      *map_name;
 };
 
 #endif /* __GPIO_IR_RECV_H__ */
index e839a78bb9c58ade07ab0733b8c6ed0349e2ff6b..03fd63edd133264b99c38b650b473e4eb5b97df6 100644 (file)
@@ -3,6 +3,7 @@
 
 struct mt9t001_platform_data {
        unsigned int clk_pol:1;
+       unsigned int ext_clk;
 };
 
 #endif
index 7395c815939df242bf02aa23bd19928b04590909..58f914a40b208586db30c85cf83346703a3220fe 100644 (file)
@@ -180,6 +180,9 @@ enum {
        /* module adv7343: just ident 7343 */
        V4L2_IDENT_ADV7343 = 7343,
 
+       /* module adv7393: just ident 7393 */
+       V4L2_IDENT_ADV7393 = 7393,
+
        /* module saa7706h: just ident 7706 */
        V4L2_IDENT_SAA7706H = 7706,
 
index a056e6ee1b6820c05d87ae6e178cc0a6008dc814..5c416cdc88d5d44eae38ce5e8445d5c2de6d2c78 100644 (file)
@@ -100,6 +100,9 @@ struct video_device
        /* Control handler associated with this device node. May be NULL. */
        struct v4l2_ctrl_handler *ctrl_handler;
 
+       /* vb2_queue associated with this device node. May be NULL. */
+       struct vb2_queue *queue;
+
        /* Priority state. If NULL, then v4l2_dev->prio will be used. */
        struct v4l2_prio_state *prio;
 
index d8b76f7392f8d793c6abdf0a2a1a46b53fa115bc..19e93523c2d82ed5e7f3883149c8875591d87694 100644 (file)
@@ -295,28 +295,19 @@ struct v4l2_ioctl_ops {
 #define V4L2_DEBUG_IOCTL     0x01
 #define V4L2_DEBUG_IOCTL_ARG 0x02
 
-/* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */
-#define v4l_print_ioctl(name, cmd)              \
-       do {                                     \
-               printk(KERN_DEBUG "%s: ", name); \
-               v4l_printk_ioctl(cmd);           \
-       } while (0)
-
-/* Use this macro in I2C drivers where 'client' is the struct i2c_client
-   pointer */
-#define v4l_i2c_print_ioctl(client, cmd)                  \
-       do {                                               \
-               v4l_client_printk(KERN_DEBUG, client, ""); \
-               v4l_printk_ioctl(cmd);                     \
-       } while (0)
-
 /*  Video standard functions  */
 extern const char *v4l2_norm_to_name(v4l2_std_id id);
 extern void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod);
 extern int v4l2_video_std_construct(struct v4l2_standard *vs,
                                    int id, const char *name);
-/* Prints the ioctl in a human-readable format */
-extern void v4l_printk_ioctl(unsigned int cmd);
+/* Prints the ioctl in a human-readable format. If prefix != NULL,
+   then do printk(KERN_DEBUG "%s: ", prefix) first. */
+extern void v4l_printk_ioctl(const char *prefix, unsigned int cmd);
+
+/* Internal use only: get the mutex (if any) that we need to lock for the
+   given command. */
+struct video_device;
+extern struct mutex *v4l2_ioctl_get_lock(struct video_device *vdev, unsigned cmd);
 
 /* names for fancy debug output */
 extern const char *v4l2_field_names[];
index 90ed895e217d3b04eea44269ee9fc9d35da05f69..8c6e825940e59c0258f9e37cf685dddd750a64ce 100644 (file)
@@ -72,7 +72,6 @@ struct videobuf_buffer {
        unsigned int            height;
        unsigned int            bytesperline; /* use only if != 0 */
        unsigned long           size;
-       unsigned int            input;
        enum v4l2_field         field;
        enum videobuf_state     state;
        struct list_head        stream;  /* QBUF/DQBUF list */
@@ -142,7 +141,6 @@ struct videobuf_queue {
        wait_queue_head_t          wait; /* wait if queue is empty */
 
        enum v4l2_buf_type         type;
-       unsigned int               inputs; /* for V4L2_BUF_FLAG_INPUT */
        unsigned int               msize;
        enum v4l2_field            field;
        enum v4l2_field            last;   /* for field=V4L2_FIELD_ALTERNATE */
index a15d1f1b319effd43a404af98bcff323bfa798e5..8dd9b6cc296b57c2ee2b37612f796d6cb975aca1 100644 (file)
@@ -244,12 +244,23 @@ struct vb2_ops {
        void (*buf_queue)(struct vb2_buffer *vb);
 };
 
+struct v4l2_fh;
+
 /**
  * struct vb2_queue - a videobuf queue
  *
  * @type:      queue type (see V4L2_BUF_TYPE_* in linux/videodev2.h
  * @io_modes:  supported io methods (see vb2_io_modes enum)
  * @io_flags:  additional io flags (see vb2_fileio_flags enum)
+ * @lock:      pointer to a mutex that protects the vb2_queue struct. The
+ *             driver can set this to a mutex to let the v4l2 core serialize
+ *             the queuing ioctls. If the driver wants to handle locking
+ *             itself, then this should be set to NULL. This lock is not used
+ *             by the videobuf2 core API.
+ * @owner:     The filehandle that 'owns' the buffers, i.e. the filehandle
+ *             that called reqbufs, create_buffers or started fileio.
+ *             This field is not used by the videobuf2 core API, but it allows
+ *             drivers to easily associate an owner filehandle with the queue.
  * @ops:       driver-specific callbacks
  * @mem_ops:   memory allocator specific callbacks
  * @drv_priv:  driver private data
@@ -273,6 +284,8 @@ struct vb2_queue {
        enum v4l2_buf_type              type;
        unsigned int                    io_modes;
        unsigned int                    io_flags;
+       struct mutex                    *lock;
+       struct v4l2_fh                  *owner;
 
        const struct vb2_ops            *ops;
        const struct vb2_mem_ops        *mem_ops;
@@ -404,4 +417,45 @@ vb2_plane_size(struct vb2_buffer *vb, unsigned int plane_no)
        return 0;
 }
 
+/*
+ * The following functions are not part of the vb2 core API, but are simple
+ * helper functions that you can use in your struct v4l2_file_operations,
+ * struct v4l2_ioctl_ops and struct vb2_ops. They will serialize if vb2_queue->lock
+ * or video_device->lock is set, and they will set and test vb2_queue->owner
+ * to check if the calling filehandle is permitted to do the queuing operation.
+ */
+
+/* struct v4l2_ioctl_ops helpers */
+
+int vb2_ioctl_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *p);
+int vb2_ioctl_create_bufs(struct file *file, void *priv,
+                         struct v4l2_create_buffers *p);
+int vb2_ioctl_prepare_buf(struct file *file, void *priv,
+                         struct v4l2_buffer *p);
+int vb2_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *p);
+int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p);
+int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p);
+int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i);
+int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i);
+
+/* struct v4l2_file_operations helpers */
+
+int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma);
+int vb2_fop_release(struct file *file);
+ssize_t vb2_fop_write(struct file *file, char __user *buf,
+               size_t count, loff_t *ppos);
+ssize_t vb2_fop_read(struct file *file, char __user *buf,
+               size_t count, loff_t *ppos);
+unsigned int vb2_fop_poll(struct file *file, poll_table *wait);
+#ifndef CONFIG_MMU
+unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr,
+               unsigned long len, unsigned long pgoff, unsigned long flags);
+#endif
+
+/* struct vb2_ops helpers, only use if vq->lock is non-NULL. */
+
+void vb2_ops_wait_prepare(struct vb2_queue *vq);
+void vb2_ops_wait_finish(struct vb2_queue *vq);
+
 #endif /* _MEDIA_VIDEOBUF2_CORE_H */
index 19ae1e3505678bb32aa810823d619b06b88993d4..8197f87d6c617ccfec71b4113b01e11064e3b529 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * videobuf2-dma-coherent.h - DMA coherent memory allocator for videobuf2
+ * videobuf2-dma-contig.h - DMA contig memory allocator for videobuf2
  *
  * Copyright (C) 2010 Samsung Electronics
  *
@@ -10,8 +10,8 @@
  * the Free Software Foundation.
  */
 
-#ifndef _MEDIA_VIDEOBUF2_DMA_COHERENT_H
-#define _MEDIA_VIDEOBUF2_DMA_COHERENT_H
+#ifndef _MEDIA_VIDEOBUF2_DMA_CONTIG_H
+#define _MEDIA_VIDEOBUF2_DMA_CONTIG_H
 
 #include <media/videobuf2-core.h>
 #include <linux/dma-mapping.h>
diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
new file mode 100644 (file)
index 0000000..260470e
--- /dev/null
@@ -0,0 +1,102 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ras
+#define TRACE_INCLUDE_FILE ras_event
+
+#if !defined(_TRACE_HW_EVENT_MC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_HW_EVENT_MC_H
+
+#include <linux/tracepoint.h>
+#include <linux/edac.h>
+#include <linux/ktime.h>
+
+/*
+ * Hardware Events Report
+ *
+ * Those events are generated when hardware detected a corrected or
+ * uncorrected event, and are meant to replace the current API to report
+ * errors defined on both EDAC and MCE subsystems.
+ *
+ * FIXME: Add events for handling memory errors originated from the
+ *        MCE subsystem.
+ */
+
+/*
+ * Hardware-independent Memory Controller specific events
+ */
+
+/*
+ * Default error mechanisms for Memory Controller errors (CE and UE)
+ */
+TRACE_EVENT(mc_event,
+
+       TP_PROTO(const unsigned int err_type,
+                const char *error_msg,
+                const char *label,
+                const int error_count,
+                const u8 mc_index,
+                const s8 top_layer,
+                const s8 mid_layer,
+                const s8 low_layer,
+                unsigned long address,
+                const u8 grain_bits,
+                unsigned long syndrome,
+                const char *driver_detail),
+
+       TP_ARGS(err_type, error_msg, label, error_count, mc_index,
+               top_layer, mid_layer, low_layer, address, grain_bits,
+               syndrome, driver_detail),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   error_type              )
+               __string(       msg,            error_msg               )
+               __string(       label,          label                   )
+               __field(        u16,            error_count             )
+               __field(        u8,             mc_index                )
+               __field(        s8,             top_layer               )
+               __field(        s8,             middle_layer            )
+               __field(        s8,             lower_layer             )
+               __field(        long,           address                 )
+               __field(        u8,             grain_bits              )
+               __field(        long,           syndrome                )
+               __string(       driver_detail,  driver_detail           )
+       ),
+
+       TP_fast_assign(
+               __entry->error_type             = err_type;
+               __assign_str(msg, error_msg);
+               __assign_str(label, label);
+               __entry->error_count            = error_count;
+               __entry->mc_index               = mc_index;
+               __entry->top_layer              = top_layer;
+               __entry->middle_layer           = mid_layer;
+               __entry->lower_layer            = low_layer;
+               __entry->address                = address;
+               __entry->grain_bits             = grain_bits;
+               __entry->syndrome               = syndrome;
+               __assign_str(driver_detail, driver_detail);
+       ),
+
+       TP_printk("%d %s error%s:%s%s on %s (mc:%d location:%d:%d:%d address:0x%08lx grain:%d syndrome:0x%08lx%s%s)",
+                 __entry->error_count,
+                 (__entry->error_type == HW_EVENT_ERR_CORRECTED) ? "Corrected" :
+                       ((__entry->error_type == HW_EVENT_ERR_FATAL) ?
+                       "Fatal" : "Uncorrected"),
+                 __entry->error_count > 1 ? "s" : "",
+                 ((char *)__get_str(msg))[0] ? " " : "",
+                 __get_str(msg),
+                 __get_str(label),
+                 __entry->mc_index,
+                 __entry->top_layer,
+                 __entry->middle_layer,
+                 __entry->lower_layer,
+                 __entry->address,
+                 1 << __entry->grain_bits,
+                 __entry->syndrome,
+                 ((char *)__get_str(driver_detail))[0] ? " " : "",
+                 __get_str(driver_detail))
+);
+
+#endif /* _TRACE_HW_EVENT_MC_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index a6df704f521e01f628def526e97b38cca92bb3ed..ad9518eb26e06e648c6044b95de41d39e9b076d0 100644 (file)
@@ -118,7 +118,7 @@ extern int sem_ctls[];
 
 static inline int compat_ipc_parse_version(int *cmd)
 {
-#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
+#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
        int version = *cmd & IPC_64;
 
        /* this is tricky: architectures that have support for the old
@@ -373,21 +373,21 @@ long compat_sys_semctl(int semid, int semnum, int cmd, int arg)
 }
 
 long compat_sys_msgsnd(int msqid, struct compat_msgbuf __user *msgp,
-                      size_t msgsz, int msgflg)
+                      compat_ssize_t msgsz, int msgflg)
 {
        compat_long_t mtype;
 
        if (get_user(mtype, &msgp->mtype))
                return -EFAULT;
-       return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
+       return do_msgsnd(msqid, mtype, msgp->mtext, (ssize_t)msgsz, msgflg);
 }
 
 long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp,
-                      size_t msgsz, long msgtyp, int msgflg)
+                      compat_ssize_t msgsz, long msgtyp, int msgflg)
 {
        long err, mtype;
 
-       err =  do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg);
+       err =  do_msgrcv(msqid, &mtype, msgp->mtext, (ssize_t)msgsz, msgtyp, msgflg);
        if (err < 0)
                goto out;
 
@@ -514,6 +514,10 @@ long compat_sys_msgctl(int first, int second, void __user *uptr)
        return err;
 }
 
+#ifndef COMPAT_SHMLBA
+#define COMPAT_SHMLBA  SHMLBA
+#endif
+
 #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
 long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
                        void __user *uptr)
@@ -524,7 +528,7 @@ long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
 
        if (version == 1)
                return -EINVAL;
-       err = do_shmat(first, uptr, second, &raddr);
+       err = do_shmat(first, uptr, second, &raddr, COMPAT_SHMLBA);
        if (err < 0)
                return err;
        uaddr = compat_ptr(third);
@@ -536,7 +540,7 @@ long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg)
        unsigned long ret;
        long err;
 
-       err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret);
+       err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);
        if (err)
                return err;
        force_successful_syscall_return();
index 41c1285d697a6f19a3c9b945691346c9b45ade47..00faa05cf72adf914bc40a41113182da964eec31 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -953,7 +953,8 @@ out:
  * "raddr" thing points to kernel space, and there has to be a wrapper around
  * this.
  */
-long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
+long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
+             unsigned long shmlba)
 {
        struct shmid_kernel *shp;
        unsigned long addr;
@@ -973,9 +974,9 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
        if (shmid < 0)
                goto out;
        else if ((addr = (ulong)shmaddr)) {
-               if (addr & (SHMLBA-1)) {
+               if (addr & (shmlba - 1)) {
                        if (shmflg & SHM_RND)
-                               addr &= ~(SHMLBA-1);       /* round down */
+                               addr &= ~(shmlba - 1);     /* round down */
                        else
 #ifndef __ARCH_FORCE_SHMLBA
                                if (addr & ~PAGE_MASK)
@@ -1107,7 +1108,7 @@ SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg)
        unsigned long ret;
        long err;
 
-       err = do_shmat(shmid, shmaddr, shmflg, &ret);
+       err = do_shmat(shmid, shmaddr, shmflg, &ret, SHMLBA);
        if (err)
                return err;
        force_successful_syscall_return();
index 1d6f53f6b562441bcf5ef99c85067275eecf6c5a..0d1e32ce048eeb0ab0d8341519aedd7ead76db62 100644 (file)
@@ -73,7 +73,7 @@ SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
                default: {
                        unsigned long raddr;
                        ret = do_shmat(first, (char __user *)ptr,
-                                      second, &raddr);
+                                      second, &raddr, SHMLBA);
                        if (ret)
                                return ret;
                        return put_user(raddr, (unsigned long __user *) third);
index 75261a31d48da6ce865ffacb3e180b2708906678..eb07fd356f2759c74a74206a441bf3928ba95f5b 100644 (file)
@@ -804,7 +804,7 @@ out_up:
        return ERR_PTR(err);
 }
 
-#ifdef __ARCH_WANT_IPC_PARSE_VERSION
+#ifdef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
 
 
 /**
@@ -826,7 +826,7 @@ int ipc_parse_version (int *cmd)
        }
 }
 
-#endif /* __ARCH_WANT_IPC_PARSE_VERSION */
+#endif /* CONFIG_ARCH_WANT_IPC_PARSE_VERSION */
 
 #ifdef CONFIG_PROC_FS
 struct ipc_proc_iter {
index 6f5c20bedaab21ff1dd0e05ad90ae0ecadeb82aa..850ef3e962cb36a13b2cdcd560f6bbccb8fcb489 100644 (file)
@@ -130,7 +130,7 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
                                      struct ipc_ids *ids, int id, int cmd,
                                      struct ipc64_perm *perm, int extra_perm);
 
-#ifndef __ARCH_WANT_IPC_PARSE_VERSION
+#ifndef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
   /* On IA-64, we always use the "64-bit version" of the IPC structures.  */ 
 # define ipc_parse_version(cmd)        IPC_64
 #else
index f93532748bca38340f0f2d196b54324a03590480..c08a22d02f7268ffd5e5516fb9d67182d22e5de8 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/swap.h>                /* try_to_free_swap */
 #include <linux/ptrace.h>      /* user_enable_single_step */
 #include <linux/kdebug.h>      /* notifier mechanism */
+#include "../../mm/internal.h" /* munlock_vma_page */
 
 #include <linux/uprobes.h>
 
@@ -112,14 +113,14 @@ static bool valid_vma(struct vm_area_struct *vma, bool is_register)
        return false;
 }
 
-static loff_t vma_address(struct vm_area_struct *vma, loff_t offset)
+static unsigned long offset_to_vaddr(struct vm_area_struct *vma, loff_t offset)
 {
-       loff_t vaddr;
-
-       vaddr = vma->vm_start + offset;
-       vaddr -= vma->vm_pgoff << PAGE_SHIFT;
+       return vma->vm_start + offset - ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
+}
 
-       return vaddr;
+static loff_t vaddr_to_offset(struct vm_area_struct *vma, unsigned long vaddr)
+{
+       return ((loff_t)vma->vm_pgoff << PAGE_SHIFT) + (vaddr - vma->vm_start);
 }
 
 /**
@@ -127,25 +128,27 @@ static loff_t vma_address(struct vm_area_struct *vma, loff_t offset)
  * based on replace_page in mm/ksm.c
  *
  * @vma:      vma that holds the pte pointing to page
+ * @addr:     address the old @page is mapped at
  * @page:     the cowed page we are replacing by kpage
  * @kpage:    the modified page we replace page by
  *
  * Returns 0 on success, -EFAULT on failure.
  */
-static int __replace_page(struct vm_area_struct *vma, struct page *page, struct page *kpage)
+static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
+                               struct page *page, struct page *kpage)
 {
        struct mm_struct *mm = vma->vm_mm;
-       unsigned long addr;
        spinlock_t *ptl;
        pte_t *ptep;
+       int err;
 
-       addr = page_address_in_vma(page, vma);
-       if (addr == -EFAULT)
-               return -EFAULT;
+       /* For try_to_free_swap() and munlock_vma_page() below */
+       lock_page(page);
 
+       err = -EAGAIN;
        ptep = page_check_address(page, mm, addr, &ptl, 0);
        if (!ptep)
-               return -EAGAIN;
+               goto unlock;
 
        get_page(kpage);
        page_add_new_anon_rmap(kpage, vma, addr);
@@ -162,10 +165,16 @@ static int __replace_page(struct vm_area_struct *vma, struct page *page, struct
        page_remove_rmap(page);
        if (!page_mapped(page))
                try_to_free_swap(page);
-       put_page(page);
        pte_unmap_unlock(ptep, ptl);
 
-       return 0;
+       if (vma->vm_flags & VM_LOCKED)
+               munlock_vma_page(page);
+       put_page(page);
+
+       err = 0;
+ unlock:
+       unlock_page(page);
+       return err;
 }
 
 /**
@@ -206,45 +215,23 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
                        unsigned long vaddr, uprobe_opcode_t opcode)
 {
        struct page *old_page, *new_page;
-       struct address_space *mapping;
        void *vaddr_old, *vaddr_new;
        struct vm_area_struct *vma;
-       struct uprobe *uprobe;
        int ret;
+
 retry:
        /* Read the page with vaddr into memory */
        ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma);
        if (ret <= 0)
                return ret;
 
-       ret = -EINVAL;
-
-       /*
-        * We are interested in text pages only. Our pages of interest
-        * should be mapped for read and execute only. We desist from
-        * adding probes in write mapped pages since the breakpoints
-        * might end up in the file copy.
-        */
-       if (!valid_vma(vma, is_swbp_insn(&opcode)))
-               goto put_out;
-
-       uprobe = container_of(auprobe, struct uprobe, arch);
-       mapping = uprobe->inode->i_mapping;
-       if (mapping != vma->vm_file->f_mapping)
-               goto put_out;
-
        ret = -ENOMEM;
        new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
        if (!new_page)
-               goto put_out;
+               goto put_old;
 
        __SetPageUptodate(new_page);
 
-       /*
-        * lock page will serialize against do_wp_page()'s
-        * PageAnon() handling
-        */
-       lock_page(old_page);
        /* copy the page now that we've got it stable */
        vaddr_old = kmap_atomic(old_page);
        vaddr_new = kmap_atomic(new_page);
@@ -257,17 +244,13 @@ retry:
 
        ret = anon_vma_prepare(vma);
        if (ret)
-               goto unlock_out;
+               goto put_new;
 
-       lock_page(new_page);
-       ret = __replace_page(vma, old_page, new_page);
-       unlock_page(new_page);
+       ret = __replace_page(vma, vaddr, old_page, new_page);
 
-unlock_out:
-       unlock_page(old_page);
+put_new:
        page_cache_release(new_page);
-
-put_out:
+put_old:
        put_page(old_page);
 
        if (unlikely(ret == -EAGAIN))
@@ -791,7 +774,7 @@ build_map_info(struct address_space *mapping, loff_t offset, bool is_register)
                curr = info;
 
                info->mm = vma->vm_mm;
-               info->vaddr = vma_address(vma, offset);
+               info->vaddr = offset_to_vaddr(vma, offset);
        }
        mutex_unlock(&mapping->i_mmap_mutex);
 
@@ -839,12 +822,13 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
                        goto free;
 
                down_write(&mm->mmap_sem);
-               vma = find_vma(mm, (unsigned long)info->vaddr);
-               if (!vma || !valid_vma(vma, is_register))
+               vma = find_vma(mm, info->vaddr);
+               if (!vma || !valid_vma(vma, is_register) ||
+                   vma->vm_file->f_mapping->host != uprobe->inode)
                        goto unlock;
 
-               if (vma->vm_file->f_mapping->host != uprobe->inode ||
-                   vma_address(vma, uprobe->offset) != info->vaddr)
+               if (vma->vm_start > info->vaddr ||
+                   vaddr_to_offset(vma, info->vaddr) != uprobe->offset)
                        goto unlock;
 
                if (is_register) {
@@ -960,59 +944,66 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume
                put_uprobe(uprobe);
 }
 
-/*
- * Of all the nodes that correspond to the given inode, return the node
- * with the least offset.
- */
-static struct rb_node *find_least_offset_node(struct inode *inode)
+static struct rb_node *
+find_node_in_range(struct inode *inode, loff_t min, loff_t max)
 {
-       struct uprobe u = { .inode = inode, .offset = 0};
        struct rb_node *n = uprobes_tree.rb_node;
-       struct rb_node *close_node = NULL;
-       struct uprobe *uprobe;
-       int match;
 
        while (n) {
-               uprobe = rb_entry(n, struct uprobe, rb_node);
-               match = match_uprobe(&u, uprobe);
-
-               if (uprobe->inode == inode)
-                       close_node = n;
-
-               if (!match)
-                       return close_node;
+               struct uprobe *u = rb_entry(n, struct uprobe, rb_node);
 
-               if (match < 0)
+               if (inode < u->inode) {
                        n = n->rb_left;
-               else
+               } else if (inode > u->inode) {
                        n = n->rb_right;
+               } else {
+                       if (max < u->offset)
+                               n = n->rb_left;
+                       else if (min > u->offset)
+                               n = n->rb_right;
+                       else
+                               break;
+               }
        }
 
-       return close_node;
+       return n;
 }
 
 /*
- * For a given inode, build a list of probes that need to be inserted.
+ * For a given range in vma, build a list of probes that need to be inserted.
  */
-static void build_probe_list(struct inode *inode, struct list_head *head)
+static void build_probe_list(struct inode *inode,
+                               struct vm_area_struct *vma,
+                               unsigned long start, unsigned long end,
+                               struct list_head *head)
 {
-       struct uprobe *uprobe;
+       loff_t min, max;
        unsigned long flags;
-       struct rb_node *n;
-
-       spin_lock_irqsave(&uprobes_treelock, flags);
-
-       n = find_least_offset_node(inode);
+       struct rb_node *n, *t;
+       struct uprobe *u;
 
-       for (; n; n = rb_next(n)) {
-               uprobe = rb_entry(n, struct uprobe, rb_node);
-               if (uprobe->inode != inode)
-                       break;
+       INIT_LIST_HEAD(head);
+       min = vaddr_to_offset(vma, start);
+       max = min + (end - start) - 1;
 
-               list_add(&uprobe->pending_list, head);
-               atomic_inc(&uprobe->ref);
+       spin_lock_irqsave(&uprobes_treelock, flags);
+       n = find_node_in_range(inode, min, max);
+       if (n) {
+               for (t = n; t; t = rb_prev(t)) {
+                       u = rb_entry(t, struct uprobe, rb_node);
+                       if (u->inode != inode || u->offset < min)
+                               break;
+                       list_add(&u->pending_list, head);
+                       atomic_inc(&u->ref);
+               }
+               for (t = n; (t = rb_next(t)); ) {
+                       u = rb_entry(t, struct uprobe, rb_node);
+                       if (u->inode != inode || u->offset > max)
+                               break;
+                       list_add(&u->pending_list, head);
+                       atomic_inc(&u->ref);
+               }
        }
-
        spin_unlock_irqrestore(&uprobes_treelock, flags);
 }
 
@@ -1031,7 +1022,7 @@ static void build_probe_list(struct inode *inode, struct list_head *head)
 int uprobe_mmap(struct vm_area_struct *vma)
 {
        struct list_head tmp_list;
-       struct uprobe *uprobe;
+       struct uprobe *uprobe, *u;
        struct inode *inode;
        int ret, count;
 
@@ -1042,21 +1033,15 @@ int uprobe_mmap(struct vm_area_struct *vma)
        if (!inode)
                return 0;
 
-       INIT_LIST_HEAD(&tmp_list);
        mutex_lock(uprobes_mmap_hash(inode));
-       build_probe_list(inode, &tmp_list);
+       build_probe_list(inode, vma, vma->vm_start, vma->vm_end, &tmp_list);
 
        ret = 0;
        count = 0;
 
-       list_for_each_entry(uprobe, &tmp_list, pending_list) {
+       list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
                if (!ret) {
-                       loff_t vaddr = vma_address(vma, uprobe->offset);
-
-                       if (vaddr < vma->vm_start || vaddr >= vma->vm_end) {
-                               put_uprobe(uprobe);
-                               continue;
-                       }
+                       unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset);
 
                        ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
                        /*
@@ -1097,12 +1082,15 @@ int uprobe_mmap(struct vm_area_struct *vma)
 void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
        struct list_head tmp_list;
-       struct uprobe *uprobe;
+       struct uprobe *uprobe, *u;
        struct inode *inode;
 
        if (!atomic_read(&uprobe_events) || !valid_vma(vma, false))
                return;
 
+       if (!atomic_read(&vma->vm_mm->mm_users)) /* called by mmput() ? */
+               return;
+
        if (!atomic_read(&vma->vm_mm->uprobes_state.count))
                return;
 
@@ -1110,21 +1098,17 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon
        if (!inode)
                return;
 
-       INIT_LIST_HEAD(&tmp_list);
        mutex_lock(uprobes_mmap_hash(inode));
-       build_probe_list(inode, &tmp_list);
-
-       list_for_each_entry(uprobe, &tmp_list, pending_list) {
-               loff_t vaddr = vma_address(vma, uprobe->offset);
-
-               if (vaddr >= start && vaddr < end) {
-                       /*
-                        * An unregister could have removed the probe before
-                        * unmap. So check before we decrement the count.
-                        */
-                       if (is_swbp_at_addr(vma->vm_mm, vaddr) == 1)
-                               atomic_dec(&vma->vm_mm->uprobes_state.count);
-               }
+       build_probe_list(inode, vma, start, end, &tmp_list);
+
+       list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
+               unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset);
+               /*
+                * An unregister could have removed the probe before
+                * unmap. So check before we decrement the count.
+                */
+               if (is_swbp_at_addr(vma->vm_mm, vaddr) == 1)
+                       atomic_dec(&vma->vm_mm->uprobes_state.count);
                put_uprobe(uprobe);
        }
        mutex_unlock(uprobes_mmap_hash(inode));
@@ -1463,12 +1447,9 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
        vma = find_vma(mm, bp_vaddr);
        if (vma && vma->vm_start <= bp_vaddr) {
                if (valid_vma(vma, false)) {
-                       struct inode *inode;
-                       loff_t offset;
+                       struct inode *inode = vma->vm_file->f_mapping->host;
+                       loff_t offset = vaddr_to_offset(vma, bp_vaddr);
 
-                       inode = vma->vm_file->f_mapping->host;
-                       offset = bp_vaddr - vma->vm_start;
-                       offset += (vma->vm_pgoff << PAGE_SHIFT);
                        uprobe = find_uprobe(inode, offset);
                }
 
index ff1cad3b7bdc5eda7d525c165c6aaa4cfe659aec..8efac1fe56bc984655c096170ce42c68fdc6a897 100644 (file)
@@ -114,6 +114,10 @@ int nr_processes(void)
        return total;
 }
 
+void __weak arch_release_task_struct(struct task_struct *tsk)
+{
+}
+
 #ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR
 static struct kmem_cache *task_struct_cachep;
 
@@ -122,17 +126,17 @@ static inline struct task_struct *alloc_task_struct_node(int node)
        return kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node);
 }
 
-void __weak arch_release_task_struct(struct task_struct *tsk) { }
-
 static inline void free_task_struct(struct task_struct *tsk)
 {
-       arch_release_task_struct(tsk);
        kmem_cache_free(task_struct_cachep, tsk);
 }
 #endif
 
+void __weak arch_release_thread_info(struct thread_info *ti)
+{
+}
+
 #ifndef CONFIG_ARCH_THREAD_INFO_ALLOCATOR
-void __weak arch_release_thread_info(struct thread_info *ti) { }
 
 /*
  * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a
@@ -150,7 +154,6 @@ static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,
 
 static inline void free_thread_info(struct thread_info *ti)
 {
-       arch_release_thread_info(ti);
        free_pages((unsigned long)ti, THREAD_SIZE_ORDER);
 }
 # else
@@ -164,7 +167,6 @@ static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,
 
 static void free_thread_info(struct thread_info *ti)
 {
-       arch_release_thread_info(ti);
        kmem_cache_free(thread_info_cache, ti);
 }
 
@@ -205,10 +207,12 @@ static void account_kernel_stack(struct thread_info *ti, int account)
 void free_task(struct task_struct *tsk)
 {
        account_kernel_stack(tsk->stack, -1);
+       arch_release_thread_info(tsk->stack);
        free_thread_info(tsk->stack);
        rt_mutex_debug_task_free(tsk);
        ftrace_graph_exit_task(tsk);
        put_seccomp_filter(tsk);
+       arch_release_task_struct(tsk);
        free_task_struct(tsk);
 }
 EXPORT_SYMBOL(free_task);
@@ -298,23 +302,16 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
                return NULL;
 
        ti = alloc_thread_info_node(tsk, node);
-       if (!ti) {
-               free_task_struct(tsk);
-               return NULL;
-       }
+       if (!ti)
+               goto free_tsk;
 
        err = arch_dup_task_struct(tsk, orig);
+       if (err)
+               goto free_ti;
 
-       /*
-        * We defer looking at err, because we will need this setup
-        * for the clean up path to work correctly.
-        */
        tsk->stack = ti;
-       setup_thread_stack(tsk, orig);
-
-       if (err)
-               goto out;
 
+       setup_thread_stack(tsk, orig);
        clear_user_return_notifier(tsk);
        clear_tsk_need_resched(tsk);
        stackend = end_of_stack(tsk);
@@ -338,8 +335,9 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
 
        return tsk;
 
-out:
+free_ti:
        free_thread_info(ti);
+free_tsk:
        free_task_struct(tsk);
        return NULL;
 }
@@ -391,8 +389,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
                }
                charge = 0;
                if (mpnt->vm_flags & VM_ACCOUNT) {
-                       unsigned long len;
-                       len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
+                       unsigned long len = vma_pages(mpnt);
+
                        if (security_vm_enough_memory_mm(oldmm, len)) /* sic */
                                goto fail_nomem;
                        charge = len;
index 4e2e472f6aeb35e5fb78e9a6ccdcc4c08fae57e3..0668d58d6413e8eeb8736b234be6d8d7378a4bea 100644 (file)
@@ -1424,7 +1424,7 @@ static void update_vmcoreinfo_note(void)
 
 void crash_save_vmcoreinfo(void)
 {
-       vmcoreinfo_append_str("CRASHTIME=%ld", get_seconds());
+       vmcoreinfo_append_str("CRASHTIME=%ld\n", get_seconds());
        update_vmcoreinfo_note();
 }
 
index ff2c7cb86d770aaf51712e330dc0f1e8a72a26e6..6f99aead66c6b897fbe14b9fb03b2a77bd17bc47 100644 (file)
@@ -45,6 +45,13 @@ extern int max_threads;
 
 static struct workqueue_struct *khelper_wq;
 
+/*
+ * kmod_thread_locker is used for deadlock avoidance.  There is no explicit
+ * locking to protect this global - it is private to the singleton khelper
+ * thread and should only ever be modified by that thread.
+ */
+static const struct task_struct *kmod_thread_locker;
+
 #define CAP_BSET       (void *)1
 #define CAP_PI         (void *)2
 
@@ -221,6 +228,13 @@ fail:
        return 0;
 }
 
+static int call_helper(void *data)
+{
+       /* Worker thread started blocking khelper thread. */
+       kmod_thread_locker = current;
+       return ____call_usermodehelper(data);
+}
+
 static void call_usermodehelper_freeinfo(struct subprocess_info *info)
 {
        if (info->cleanup)
@@ -295,9 +309,12 @@ static void __call_usermodehelper(struct work_struct *work)
        if (wait == UMH_WAIT_PROC)
                pid = kernel_thread(wait_for_helper, sub_info,
                                    CLONE_FS | CLONE_FILES | SIGCHLD);
-       else
-               pid = kernel_thread(____call_usermodehelper, sub_info,
+       else {
+               pid = kernel_thread(call_helper, sub_info,
                                    CLONE_VFORK | SIGCHLD);
+               /* Worker thread stopped blocking khelper thread. */
+               kmod_thread_locker = NULL;
+       }
 
        switch (wait) {
        case UMH_NO_WAIT:
@@ -548,6 +565,16 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
                retval = -EBUSY;
                goto out;
        }
+       /*
+        * Worker thread must not wait for khelper thread at below
+        * wait_for_completion() if the thread was created with CLONE_VFORK
+        * flag, for khelper thread is already waiting for the thread at
+        * wait_for_completion() in do_fork().
+        */
+       if (wait != UMH_NO_WAIT && current == kmod_thread_locker) {
+               retval = -EBUSY;
+               goto out;
+       }
 
        sub_info->complete = &done;
        sub_info->wait = wait;
@@ -577,6 +604,12 @@ unlock:
        return retval;
 }
 
+/*
+ * call_usermodehelper_fns() will not run the caller-provided cleanup function
+ * if a memory allocation failure is experienced.  So the caller might need to
+ * check the call_usermodehelper_fns() return value: if it is -ENOMEM, perform
+ * the necessaary cleanup within the caller.
+ */
 int call_usermodehelper_fns(
        char *path, char **argv, char **envp, int wait,
        int (*init)(struct subprocess_info *info, struct cred *new),
index d2a5f4ecc6ddd2ebc2da68764da646c7b96d9fc9..e1b2822fff97b8164ffae96e8a17ace02060a0c1 100644 (file)
@@ -74,6 +74,14 @@ void panic(const char *fmt, ...)
        long i, i_next = 0;
        int state = 0;
 
+       /*
+        * Disable local interrupts. This will prevent panic_smp_self_stop
+        * from deadlocking the first cpu that invokes the panic, since
+        * there is nothing to prevent an interrupt handler (that runs
+        * after the panic_lock is acquired) from invoking panic again.
+        */
+       local_irq_disable();
+
        /*
         * It's possible to come here directly from a panic-assertion and
         * not have preempt disabled. Some functions called from here want
index c8b7446b27dfc21add10f610e1692a2f3acee7ed..1da39ea248fdf3bee6f16f536693b0daad10afbe 100644 (file)
@@ -178,6 +178,9 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
        arch_suspend_enable_irqs();
        BUG_ON(irqs_disabled());
 
+       /* Kick the lockup detector */
+       lockup_detector_bootcpu_resume();
+
  Enable_cpus:
        enable_nonboot_cpus();
 
index 50c96b5651b696766c915b57dec92b5629a78866..6a76ab9d4476466b5ba3b3e37d38aadbb2e02644 100644 (file)
@@ -389,8 +389,10 @@ static ssize_t devkmsg_writev(struct kiocb *iocb, const struct iovec *iv,
 
        line = buf;
        for (i = 0; i < count; i++) {
-               if (copy_from_user(line, iv[i].iov_base, iv[i].iov_len))
+               if (copy_from_user(line, iv[i].iov_base, iv[i].iov_len)) {
+                       ret = -EFAULT;
                        goto out;
+               }
                line += iv[i].iov_len;
        }
 
@@ -1540,17 +1542,23 @@ asmlinkage int vprintk_emit(int facility, int level,
                lflags |= LOG_NEWLINE;
        }
 
-       /* strip syslog prefix and extract log level or control flags */
-       if (text[0] == '<' && text[1] && text[2] == '>') {
-               switch (text[1]) {
-               case '0' ... '7':
-                       if (level == -1)
-                               level = text[1] - '0';
-               case 'd':       /* KERN_DEFAULT */
-                       lflags |= LOG_PREFIX;
-               case 'c':       /* KERN_CONT */
-                       text += 3;
-                       text_len -= 3;
+       /* strip kernel syslog prefix and extract log level or control flags */
+       if (facility == 0) {
+               int kern_level = printk_get_level(text);
+
+               if (kern_level) {
+                       const char *end_of_header = printk_skip_level(text);
+                       switch (kern_level) {
+                       case '0' ... '7':
+                               if (level == -1)
+                                       level = kern_level - '0';
+                       case 'd':       /* KERN_DEFAULT */
+                               lflags |= LOG_PREFIX;
+                       case 'c':       /* KERN_CONT */
+                               break;
+                       }
+                       text_len -= end_of_header - text;
+                       text = (char *)end_of_header;
                }
        }
 
index dc8b477644436730bea0165a1ca6fd7f179b3144..34d45886ee8429acc7197c8ceaca18ef215fb2ae 100644 (file)
@@ -7,6 +7,8 @@
  * Arbitrary resource management.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/export.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
@@ -791,8 +793,28 @@ void __init reserve_region_with_split(struct resource *root,
                resource_size_t start, resource_size_t end,
                const char *name)
 {
+       int abort = 0;
+
        write_lock(&resource_lock);
-       __reserve_region_with_split(root, start, end, name);
+       if (root->start > start || root->end < end) {
+               pr_err("requested range [0x%llx-0x%llx] not in root %pr\n",
+                      (unsigned long long)start, (unsigned long long)end,
+                      root);
+               if (start > root->end || end < root->start)
+                       abort = 1;
+               else {
+                       if (end > root->end)
+                               end = root->end;
+                       if (start < root->start)
+                               start = root->start;
+                       pr_err("fixing request to [0x%llx-0x%llx]\n",
+                              (unsigned long long)start,
+                              (unsigned long long)end);
+               }
+               dump_stack();
+       }
+       if (!abort)
+               __reserve_region_with_split(root, start, end, name);
        write_unlock(&resource_lock);
 }
 
index 5d011ef4c0df37ee859ac3d3871fcabd2164316a..d325c4b2dcbb0c5995a903d76e3035129d1590c3 100644 (file)
@@ -1910,12 +1910,12 @@ static inline void
 prepare_task_switch(struct rq *rq, struct task_struct *prev,
                    struct task_struct *next)
 {
+       trace_sched_switch(prev, next);
        sched_info_switch(prev, next);
        perf_event_task_sched_out(prev, next);
        fire_sched_out_preempt_notifiers(prev, next);
        prepare_lock_switch(rq, next);
        prepare_arch_switch(next);
-       trace_sched_switch(prev, next);
 }
 
 /**
index 2d39a84cd8575e6295f666421cee01b41652b3b1..241507f23eca097871bec58f5976476f352f3d75 100644 (file)
@@ -2015,7 +2015,6 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                                break;
                        }
                        me->pdeath_signal = arg2;
-                       error = 0;
                        break;
                case PR_GET_PDEATHSIG:
                        error = put_user(me->pdeath_signal, (int __user *)arg2);
@@ -2029,7 +2028,6 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                                break;
                        }
                        set_dumpable(me->mm, arg2);
-                       error = 0;
                        break;
 
                case PR_SET_UNALIGN:
@@ -2056,10 +2054,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                case PR_SET_TIMING:
                        if (arg2 != PR_TIMING_STATISTICAL)
                                error = -EINVAL;
-                       else
-                               error = 0;
                        break;
-
                case PR_SET_NAME:
                        comm[sizeof(me->comm)-1] = 0;
                        if (strncpy_from_user(comm, (char __user *)arg2,
@@ -2067,20 +2062,19 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                                return -EFAULT;
                        set_task_comm(me, comm);
                        proc_comm_connector(me);
-                       return 0;
+                       break;
                case PR_GET_NAME:
                        get_task_comm(comm, me);
                        if (copy_to_user((char __user *)arg2, comm,
                                         sizeof(comm)))
                                return -EFAULT;
-                       return 0;
+                       break;
                case PR_GET_ENDIAN:
                        error = GET_ENDIAN(me, arg2);
                        break;
                case PR_SET_ENDIAN:
                        error = SET_ENDIAN(me, arg2);
                        break;
-
                case PR_GET_SECCOMP:
                        error = prctl_get_seccomp();
                        break;
@@ -2108,7 +2102,6 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                                        current->default_timer_slack_ns;
                        else
                                current->timer_slack_ns = arg2;
-                       error = 0;
                        break;
                case PR_MCE_KILL:
                        if (arg4 | arg5)
@@ -2134,7 +2127,6 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                        default:
                                return -EINVAL;
                        }
-                       error = 0;
                        break;
                case PR_MCE_KILL_GET:
                        if (arg2 | arg3 | arg4 | arg5)
@@ -2153,7 +2145,6 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                        break;
                case PR_SET_CHILD_SUBREAPER:
                        me->signal->is_child_subreaper = !!arg2;
-                       error = 0;
                        break;
                case PR_GET_CHILD_SUBREAPER:
                        error = put_user(me->signal->is_child_subreaper,
@@ -2195,46 +2186,52 @@ static void argv_cleanup(struct subprocess_info *info)
        argv_free(info->argv);
 }
 
-/**
- * orderly_poweroff - Trigger an orderly system poweroff
- * @force: force poweroff if command execution fails
- *
- * This may be called from any context to trigger a system shutdown.
- * If the orderly shutdown fails, it will force an immediate shutdown.
- */
-int orderly_poweroff(bool force)
+static int __orderly_poweroff(void)
 {
        int argc;
-       char **argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc);
+       char **argv;
        static char *envp[] = {
                "HOME=/",
                "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
                NULL
        };
-       int ret = -ENOMEM;
+       int ret;
 
+       argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc);
        if (argv == NULL) {
                printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n",
                       __func__, poweroff_cmd);
-               goto out;
+               return -ENOMEM;
        }
 
        ret = call_usermodehelper_fns(argv[0], argv, envp, UMH_NO_WAIT,
                                      NULL, argv_cleanup, NULL);
-out:
-       if (likely(!ret))
-               return 0;
-
        if (ret == -ENOMEM)
                argv_free(argv);
 
-       if (force) {
+       return ret;
+}
+
+/**
+ * orderly_poweroff - Trigger an orderly system poweroff
+ * @force: force poweroff if command execution fails
+ *
+ * This may be called from any context to trigger a system shutdown.
+ * If the orderly shutdown fails, it will force an immediate shutdown.
+ */
+int orderly_poweroff(bool force)
+{
+       int ret = __orderly_poweroff();
+
+       if (ret && force) {
                printk(KERN_WARNING "Failed to start orderly shutdown: "
                       "forcing the issue\n");
 
-               /* I guess this should try to kick off some daemon to
-                  sync and poweroff asap.  Or not even bother syncing
-                  if we're doing an emergency shutdown? */
+               /*
+                * I guess this should try to kick off some daemon to sync and
+                * poweroff asap.  Or not even bother syncing if we're doing an
+                * emergency shutdown?
+                */
                emergency_sync();
                kernel_power_off();
        }
index 4ab11879aeb4d15baa3d8d25fa753725084ed809..97186b99b0e40326a739e8b086abb4859f6d1eab 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/security.h>
 #include <linux/ctype.h>
 #include <linux/kmemcheck.h>
+#include <linux/kmemleak.h>
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -174,6 +175,11 @@ static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
                                void __user *buffer, size_t *lenp, loff_t *ppos);
 #endif
 
+static int proc_dointvec_minmax_coredump(struct ctl_table *table, int write,
+               void __user *buffer, size_t *lenp, loff_t *ppos);
+static int proc_dostring_coredump(struct ctl_table *table, int write,
+               void __user *buffer, size_t *lenp, loff_t *ppos);
+
 #ifdef CONFIG_MAGIC_SYSRQ
 /* Note: sysrq code uses it's own private copy */
 static int __sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
@@ -410,7 +416,7 @@ static struct ctl_table kern_table[] = {
                .data           = core_pattern,
                .maxlen         = CORENAME_MAX_SIZE,
                .mode           = 0644,
-               .proc_handler   = proc_dostring,
+               .proc_handler   = proc_dostring_coredump,
        },
        {
                .procname       = "core_pipe_limit",
@@ -1498,7 +1504,7 @@ static struct ctl_table fs_table[] = {
                .data           = &suid_dumpable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
+               .proc_handler   = proc_dointvec_minmax_coredump,
                .extra1         = &zero,
                .extra2         = &two,
        },
@@ -1551,7 +1557,10 @@ static struct ctl_table dev_table[] = {
 
 int __init sysctl_init(void)
 {
-       register_sysctl_table(sysctl_base_table);
+       struct ctl_table_header *hdr;
+
+       hdr = register_sysctl_table(sysctl_base_table);
+       kmemleak_not_leak(hdr);
        return 0;
 }
 
@@ -2009,6 +2018,34 @@ int proc_dointvec_minmax(struct ctl_table *table, int write,
                                do_proc_dointvec_minmax_conv, &param);
 }
 
+static void validate_coredump_safety(void)
+{
+       if (suid_dumpable == SUID_DUMPABLE_SAFE &&
+           core_pattern[0] != '/' && core_pattern[0] != '|') {
+               printk(KERN_WARNING "Unsafe core_pattern used with "\
+                       "suid_dumpable=2. Pipe handler or fully qualified "\
+                       "core dump path required.\n");
+       }
+}
+
+static int proc_dointvec_minmax_coredump(struct ctl_table *table, int write,
+               void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int error = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+       if (!error)
+               validate_coredump_safety();
+       return error;
+}
+
+static int proc_dostring_coredump(struct ctl_table *table, int write,
+                 void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int error = proc_dostring(table, write, buffer, lenp, ppos);
+       if (!error)
+               validate_coredump_safety();
+       return error;
+}
+
 static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int write,
                                     void __user *buffer,
                                     size_t *lenp, loff_t *ppos,
index e66046456f4ffebab2ec0300e0537a1fb1911e56..d0a32796550fcdf81e40d18cda31a3b353d332d5 100644 (file)
@@ -436,6 +436,11 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
 
        na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS,
                                sizeof(struct cgroupstats));
+       if (na == NULL) {
+               rc = -EMSGSIZE;
+               goto err;
+       }
+
        stats = nla_data(na);
        memset(stats, 0, sizeof(*stats));
 
index 4b1dfba70f7cf8ae7397623656a9b695028f702a..69add8a9da686a326be90e45aa09ab8427a24875 100644 (file)
@@ -575,7 +575,7 @@ out:
 /*
  * Create/destroy watchdog threads as CPUs come and go:
  */
-static int __cpuinit
+static int
 cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
        int hotcpu = (unsigned long)hcpu;
@@ -610,10 +610,27 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata cpu_nfb = {
+static struct notifier_block cpu_nfb = {
        .notifier_call = cpu_callback
 };
 
+#ifdef CONFIG_SUSPEND
+/*
+ * On exit from suspend we force an offline->online transition on the boot CPU
+ * so that the PMU state that was lost while in suspended state gets set up
+ * properly for the boot CPU.  This information is required for restarting the
+ * NMI watchdog.
+ */
+void lockup_detector_bootcpu_resume(void)
+{
+       void *cpu = (void *)(long)smp_processor_id();
+
+       cpu_callback(&cpu_nfb, CPU_DEAD_FROZEN, cpu);
+       cpu_callback(&cpu_nfb, CPU_UP_PREPARE_FROZEN, cpu);
+       cpu_callback(&cpu_nfb, CPU_ONLINE_FROZEN, cpu);
+}
+#endif
+
 void __init lockup_detector_init(void)
 {
        void *cpu = (void *)(long)smp_processor_id();
index 8269d56dcdaa38a2af895777bfb1a2d873df5f84..bb94c1ba616a4213bc11521adef4310387032353 100644 (file)
@@ -340,6 +340,9 @@ config NLATTR
 config GENERIC_ATOMIC64
        bool
 
+config ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+       def_bool y if GENERIC_ATOMIC64
+
 config LRU_CACHE
        tristate
 
@@ -387,4 +390,10 @@ config SIGNATURE
          Digital signature verification. Currently only RSA is supported.
          Implementation is done using GnuPG MPI library
 
+#
+# libfdt files, only selected if needed.
+#
+config LIBFDT
+       bool
+
 endmenu
index 4a186508bf8b98de56872d254cc405f3a47c0cb2..2403a63b5da5bcf4e978d5dc2dfe8682cebef453 100644 (file)
@@ -1084,18 +1084,105 @@ config LKDTM
        Documentation on how to use the module can be found in
        Documentation/fault-injection/provoke-crashes.txt
 
+config NOTIFIER_ERROR_INJECTION
+       tristate "Notifier error injection"
+       depends on DEBUG_KERNEL
+       select DEBUG_FS
+       help
+         This option provides the ability to inject artifical errors to
+         specified notifier chain callbacks. It is useful to test the error
+         handling of notifier call chain failures.
+
+         Say N if unsure.
+
 config CPU_NOTIFIER_ERROR_INJECT
        tristate "CPU notifier error injection module"
-       depends on HOTPLUG_CPU && DEBUG_KERNEL
+       depends on HOTPLUG_CPU && NOTIFIER_ERROR_INJECTION
        help
          This option provides a kernel module that can be used to test
-         the error handling of the cpu notifiers
+         the error handling of the cpu notifiers by injecting artifical
+         errors to CPU notifier chain callbacks.  It is controlled through
+         debugfs interface under /sys/kernel/debug/notifier-error-inject/cpu
+
+         If the notifier call chain should be failed with some events
+         notified, write the error code to "actions/<notifier event>/error".
+
+         Example: Inject CPU offline error (-1 == -EPERM)
+
+         # cd /sys/kernel/debug/notifier-error-inject/cpu
+         # echo -1 > actions/CPU_DOWN_PREPARE/error
+         # echo 0 > /sys/devices/system/cpu/cpu1/online
+         bash: echo: write error: Operation not permitted
 
          To compile this code as a module, choose M here: the module will
          be called cpu-notifier-error-inject.
 
          If unsure, say N.
 
+config PM_NOTIFIER_ERROR_INJECT
+       tristate "PM notifier error injection module"
+       depends on PM && NOTIFIER_ERROR_INJECTION
+       default m if PM_DEBUG
+       help
+         This option provides the ability to inject artifical errors to
+         PM notifier chain callbacks.  It is controlled through debugfs
+         interface /sys/kernel/debug/notifier-error-inject/pm
+
+         If the notifier call chain should be failed with some events
+         notified, write the error code to "actions/<notifier event>/error".
+
+         Example: Inject PM suspend error (-12 = -ENOMEM)
+
+         # cd /sys/kernel/debug/notifier-error-inject/pm/
+         # echo -12 > actions/PM_SUSPEND_PREPARE/error
+         # echo mem > /sys/power/state
+         bash: echo: write error: Cannot allocate memory
+
+         To compile this code as a module, choose M here: the module will
+         be called pm-notifier-error-inject.
+
+         If unsure, say N.
+
+config MEMORY_NOTIFIER_ERROR_INJECT
+       tristate "Memory hotplug notifier error injection module"
+       depends on MEMORY_HOTPLUG_SPARSE && NOTIFIER_ERROR_INJECTION
+       help
+         This option provides the ability to inject artifical errors to
+         memory hotplug notifier chain callbacks.  It is controlled through
+         debugfs interface under /sys/kernel/debug/notifier-error-inject/memory
+
+         If the notifier call chain should be failed with some events
+         notified, write the error code to "actions/<notifier event>/error".
+
+         Example: Inject memory hotplug offline error (-12 == -ENOMEM)
+
+         # cd /sys/kernel/debug/notifier-error-inject/memory
+         # echo -12 > actions/MEM_GOING_OFFLINE/error
+         # echo offline > /sys/devices/system/memory/memoryXXX/state
+         bash: echo: write error: Cannot allocate memory
+
+         To compile this code as a module, choose M here: the module will
+         be called pSeries-reconfig-notifier-error-inject.
+
+         If unsure, say N.
+
+config PSERIES_RECONFIG_NOTIFIER_ERROR_INJECT
+       tristate "pSeries reconfig notifier error injection module"
+       depends on PPC_PSERIES && NOTIFIER_ERROR_INJECTION
+       help
+         This option provides the ability to inject artifical errors to
+         pSeries reconfig notifier chain callbacks.  It is controlled
+         through debugfs interface under
+         /sys/kernel/debug/notifier-error-inject/pSeries-reconfig/
+
+         If the notifier call chain should be failed with some events
+         notified, write the error code to "actions/<notifier event>/error".
+
+         To compile this code as a module, choose M here: the module will
+         be called memory-notifier-error-inject.
+
+         If unsure, say N.
+
 config FAULT_INJECTION
        bool "Fault-injection framework"
        depends on DEBUG_KERNEL
index 8c31a0cb75e97746af1cd02906ac149105250cc2..42d283edc4d3157cc81f897c51fd4ee20a615b62 100644 (file)
@@ -11,7 +11,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
         rbtree.o radix-tree.o dump_stack.o timerqueue.o\
         idr.o int_sqrt.o extable.o prio_tree.o \
         sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
-        proportions.o prio_heap.o ratelimit.o show_mem.o \
+        proportions.o flex_proportions.o prio_heap.o ratelimit.o show_mem.o \
         is_single_threaded.o plist.o decompress.o
 
 lib-$(CONFIG_MMU) += ioremap.o
@@ -22,7 +22,7 @@ lib-y += kobject.o klist.o
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
         bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
         string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o \
-        bsearch.o find_last_bit.o find_next_bit.o llist.o
+        bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o
 obj-y += kstrtox.o
 obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
 
@@ -90,7 +90,12 @@ obj-$(CONFIG_AUDIT_GENERIC) += audit.o
 obj-$(CONFIG_SWIOTLB) += swiotlb.o
 obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
 obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
+obj-$(CONFIG_NOTIFIER_ERROR_INJECTION) += notifier-error-inject.o
 obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o
+obj-$(CONFIG_PM_NOTIFIER_ERROR_INJECT) += pm-notifier-error-inject.o
+obj-$(CONFIG_MEMORY_NOTIFIER_ERROR_INJECT) += memory-notifier-error-inject.o
+obj-$(CONFIG_PSERIES_RECONFIG_NOTIFIER_ERROR_INJECT) += \
+       pSeries-reconfig-notifier-error-inject.o
 
 lib-$(CONFIG_GENERIC_BUG) += bug.o
 
@@ -130,6 +135,11 @@ obj-$(CONFIG_GENERIC_STRNLEN_USER) += strnlen_user.o
 
 obj-$(CONFIG_STMP_DEVICE) += stmp_device.o
 
+libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o
+$(foreach file, $(libfdt_files), \
+       $(eval CFLAGS_$(file) = -I$(src)/../scripts/dtc/libfdt))
+lib-$(CONFIG_LIBFDT) += $(libfdt_files)
+
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
 
index cb99b91c3a1d3af01b012fc421d69c8935733556..00bca223d1e1e6552bbdd0dd7c69fef2ff48c60d 100644 (file)
@@ -114,8 +114,7 @@ static __init int test_atomic64(void)
        r += one;
        BUG_ON(v.counter != r);
 
-#if defined(CONFIG_X86) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || \
-    defined(CONFIG_S390) || defined(_ASM_GENERIC_ATOMIC64_H) || defined(CONFIG_ARM)
+#ifdef CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        INIT(onestwos);
        BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1));
        r -= one;
@@ -129,7 +128,7 @@ static __init int test_atomic64(void)
        BUG_ON(atomic64_dec_if_positive(&v) != (-one - one));
        BUG_ON(v.counter != r);
 #else
-#warning Please implement atomic64_dec_if_positive for your architecture, and add it to the IF above
+#warning Please implement atomic64_dec_if_positive for your architecture and select the above Kconfig symbol
 #endif
 
        INIT(onestwos);
index 4dc20321b0d59e41cd14059eadf76e035df7a8f3..707ca24f7b187f4c2f18f590e1eee298fcdadcb3 100644 (file)
@@ -1,58 +1,45 @@
 #include <linux/kernel.h>
-#include <linux/cpu.h>
 #include <linux/module.h>
-#include <linux/notifier.h>
+#include <linux/cpu.h>
 
-static int priority;
-static int cpu_up_prepare_error;
-static int cpu_down_prepare_error;
+#include "notifier-error-inject.h"
 
+static int priority;
 module_param(priority, int, 0);
 MODULE_PARM_DESC(priority, "specify cpu notifier priority");
 
-module_param(cpu_up_prepare_error, int, 0644);
-MODULE_PARM_DESC(cpu_up_prepare_error,
-               "specify error code to inject CPU_UP_PREPARE action");
-
-module_param(cpu_down_prepare_error, int, 0644);
-MODULE_PARM_DESC(cpu_down_prepare_error,
-               "specify error code to inject CPU_DOWN_PREPARE action");
-
-static int err_inject_cpu_callback(struct notifier_block *nfb,
-                               unsigned long action, void *hcpu)
-{
-       int err = 0;
-
-       switch (action) {
-       case CPU_UP_PREPARE:
-       case CPU_UP_PREPARE_FROZEN:
-               err = cpu_up_prepare_error;
-               break;
-       case CPU_DOWN_PREPARE:
-       case CPU_DOWN_PREPARE_FROZEN:
-               err = cpu_down_prepare_error;
-               break;
+static struct notifier_err_inject cpu_notifier_err_inject = {
+       .actions = {
+               { NOTIFIER_ERR_INJECT_ACTION(CPU_UP_PREPARE) },
+               { NOTIFIER_ERR_INJECT_ACTION(CPU_UP_PREPARE_FROZEN) },
+               { NOTIFIER_ERR_INJECT_ACTION(CPU_DOWN_PREPARE) },
+               { NOTIFIER_ERR_INJECT_ACTION(CPU_DOWN_PREPARE_FROZEN) },
+               {}
        }
-       if (err)
-               printk(KERN_INFO "Injecting error (%d) at cpu notifier\n", err);
-
-       return notifier_from_errno(err);
-}
-
-static struct notifier_block err_inject_cpu_notifier = {
-       .notifier_call = err_inject_cpu_callback,
 };
 
+static struct dentry *dir;
+
 static int err_inject_init(void)
 {
-       err_inject_cpu_notifier.priority = priority;
+       int err;
+
+       dir = notifier_err_inject_init("cpu", notifier_err_inject_dir,
+                                       &cpu_notifier_err_inject, priority);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+
+       err = register_hotcpu_notifier(&cpu_notifier_err_inject.nb);
+       if (err)
+               debugfs_remove_recursive(dir);
 
-       return register_hotcpu_notifier(&err_inject_cpu_notifier);
+       return err;
 }
 
 static void err_inject_exit(void)
 {
-       unregister_hotcpu_notifier(&err_inject_cpu_notifier);
+       unregister_hotcpu_notifier(&cpu_notifier_err_inject.nb);
+       debugfs_remove_recursive(dir);
 }
 
 module_init(err_inject_init);
index b0d278fb1d911a5112db498873071cd64c368ad4..61774b8db4de6911453ccd383df7d38dd2f2b42f 100644 (file)
@@ -74,7 +74,9 @@ crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256])
        size_t i;
 # endif
        const u32 *t0=tab[0], *t1=tab[1], *t2=tab[2], *t3=tab[3];
+# if CRC_LE_BITS != 32
        const u32 *t4 = tab[4], *t5 = tab[5], *t6 = tab[6], *t7 = tab[7];
+# endif
        u32 q;
 
        /* Align it */
diff --git a/lib/fdt.c b/lib/fdt.c
new file mode 100644 (file)
index 0000000..97f2006
--- /dev/null
+++ b/lib/fdt.c
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt.c"
diff --git a/lib/fdt_ro.c b/lib/fdt_ro.c
new file mode 100644 (file)
index 0000000..f73c04e
--- /dev/null
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt_ro.c"
diff --git a/lib/fdt_rw.c b/lib/fdt_rw.c
new file mode 100644 (file)
index 0000000..0c1f0f4
--- /dev/null
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt_rw.c"
diff --git a/lib/fdt_strerror.c b/lib/fdt_strerror.c
new file mode 100644 (file)
index 0000000..8713e3f
--- /dev/null
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt_strerror.c"
diff --git a/lib/fdt_sw.c b/lib/fdt_sw.c
new file mode 100644 (file)
index 0000000..9ac7e50
--- /dev/null
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt_sw.c"
diff --git a/lib/fdt_wip.c b/lib/fdt_wip.c
new file mode 100644 (file)
index 0000000..45b3fc3
--- /dev/null
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt_wip.c"
diff --git a/lib/flex_proportions.c b/lib/flex_proportions.c
new file mode 100644 (file)
index 0000000..c785554
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ *  Floating proportions with flexible aging period
+ *
+ *   Copyright (C) 2011, SUSE, Jan Kara <jack@suse.cz>
+ *
+ * The goal of this code is: Given different types of event, measure proportion
+ * of each type of event over time. The proportions are measured with
+ * exponentially decaying history to give smooth transitions. A formula
+ * expressing proportion of event of type 'j' is:
+ *
+ *   p_{j} = (\Sum_{i>=0} x_{i,j}/2^{i+1})/(\Sum_{i>=0} x_i/2^{i+1})
+ *
+ * Where x_{i,j} is j's number of events in i-th last time period and x_i is
+ * total number of events in i-th last time period.
+ *
+ * Note that p_{j}'s are normalised, i.e.
+ *
+ *   \Sum_{j} p_{j} = 1,
+ *
+ * This formula can be straightforwardly computed by maintaing denominator
+ * (let's call it 'd') and for each event type its numerator (let's call it
+ * 'n_j'). When an event of type 'j' happens, we simply need to do:
+ *   n_j++; d++;
+ *
+ * When a new period is declared, we could do:
+ *   d /= 2
+ *   for each j
+ *     n_j /= 2
+ *
+ * To avoid iteration over all event types, we instead shift numerator of event
+ * j lazily when someone asks for a proportion of event j or when event j
+ * occurs. This can bit trivially implemented by remembering last period in
+ * which something happened with proportion of type j.
+ */
+#include <linux/flex_proportions.h>
+
+int fprop_global_init(struct fprop_global *p)
+{
+       int err;
+
+       p->period = 0;
+       /* Use 1 to avoid dealing with periods with 0 events... */
+       err = percpu_counter_init(&p->events, 1);
+       if (err)
+               return err;
+       seqcount_init(&p->sequence);
+       return 0;
+}
+
+void fprop_global_destroy(struct fprop_global *p)
+{
+       percpu_counter_destroy(&p->events);
+}
+
+/*
+ * Declare @periods new periods. It is upto the caller to make sure period
+ * transitions cannot happen in parallel.
+ *
+ * The function returns true if the proportions are still defined and false
+ * if aging zeroed out all events. This can be used to detect whether declaring
+ * further periods has any effect.
+ */
+bool fprop_new_period(struct fprop_global *p, int periods)
+{
+       u64 events;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       events = percpu_counter_sum(&p->events);
+       /*
+        * Don't do anything if there are no events.
+        */
+       if (events <= 1) {
+               local_irq_restore(flags);
+               return false;
+       }
+       write_seqcount_begin(&p->sequence);
+       if (periods < 64)
+               events -= events >> periods;
+       /* Use addition to avoid losing events happening between sum and set */
+       percpu_counter_add(&p->events, -events);
+       p->period += periods;
+       write_seqcount_end(&p->sequence);
+       local_irq_restore(flags);
+
+       return true;
+}
+
+/*
+ * ---- SINGLE ----
+ */
+
+int fprop_local_init_single(struct fprop_local_single *pl)
+{
+       pl->events = 0;
+       pl->period = 0;
+       raw_spin_lock_init(&pl->lock);
+       return 0;
+}
+
+void fprop_local_destroy_single(struct fprop_local_single *pl)
+{
+}
+
+static void fprop_reflect_period_single(struct fprop_global *p,
+                                       struct fprop_local_single *pl)
+{
+       unsigned int period = p->period;
+       unsigned long flags;
+
+       /* Fast path - period didn't change */
+       if (pl->period == period)
+               return;
+       raw_spin_lock_irqsave(&pl->lock, flags);
+       /* Someone updated pl->period while we were spinning? */
+       if (pl->period >= period) {
+               raw_spin_unlock_irqrestore(&pl->lock, flags);
+               return;
+       }
+       /* Aging zeroed our fraction? */
+       if (period - pl->period < BITS_PER_LONG)
+               pl->events >>= period - pl->period;
+       else
+               pl->events = 0;
+       pl->period = period;
+       raw_spin_unlock_irqrestore(&pl->lock, flags);
+}
+
+/* Event of type pl happened */
+void __fprop_inc_single(struct fprop_global *p, struct fprop_local_single *pl)
+{
+       fprop_reflect_period_single(p, pl);
+       pl->events++;
+       percpu_counter_add(&p->events, 1);
+}
+
+/* Return fraction of events of type pl */
+void fprop_fraction_single(struct fprop_global *p,
+                          struct fprop_local_single *pl,
+                          unsigned long *numerator, unsigned long *denominator)
+{
+       unsigned int seq;
+       s64 num, den;
+
+       do {
+               seq = read_seqcount_begin(&p->sequence);
+               fprop_reflect_period_single(p, pl);
+               num = pl->events;
+               den = percpu_counter_read_positive(&p->events);
+       } while (read_seqcount_retry(&p->sequence, seq));
+
+       /*
+        * Make fraction <= 1 and denominator > 0 even in presence of percpu
+        * counter errors
+        */
+       if (den <= num) {
+               if (num)
+                       den = num;
+               else
+                       den = 1;
+       }
+       *denominator = den;
+       *numerator = num;
+}
+
+/*
+ * ---- PERCPU ----
+ */
+#define PROP_BATCH (8*(1+ilog2(nr_cpu_ids)))
+
+int fprop_local_init_percpu(struct fprop_local_percpu *pl)
+{
+       int err;
+
+       err = percpu_counter_init(&pl->events, 0);
+       if (err)
+               return err;
+       pl->period = 0;
+       raw_spin_lock_init(&pl->lock);
+       return 0;
+}
+
+void fprop_local_destroy_percpu(struct fprop_local_percpu *pl)
+{
+       percpu_counter_destroy(&pl->events);
+}
+
+static void fprop_reflect_period_percpu(struct fprop_global *p,
+                                       struct fprop_local_percpu *pl)
+{
+       unsigned int period = p->period;
+       unsigned long flags;
+
+       /* Fast path - period didn't change */
+       if (pl->period == period)
+               return;
+       raw_spin_lock_irqsave(&pl->lock, flags);
+       /* Someone updated pl->period while we were spinning? */
+       if (pl->period >= period) {
+               raw_spin_unlock_irqrestore(&pl->lock, flags);
+               return;
+       }
+       /* Aging zeroed our fraction? */
+       if (period - pl->period < BITS_PER_LONG) {
+               s64 val = percpu_counter_read(&pl->events);
+
+               if (val < (nr_cpu_ids * PROP_BATCH))
+                       val = percpu_counter_sum(&pl->events);
+
+               __percpu_counter_add(&pl->events,
+                       -val + (val >> (period-pl->period)), PROP_BATCH);
+       } else
+               percpu_counter_set(&pl->events, 0);
+       pl->period = period;
+       raw_spin_unlock_irqrestore(&pl->lock, flags);
+}
+
+/* Event of type pl happened */
+void __fprop_inc_percpu(struct fprop_global *p, struct fprop_local_percpu *pl)
+{
+       fprop_reflect_period_percpu(p, pl);
+       __percpu_counter_add(&pl->events, 1, PROP_BATCH);
+       percpu_counter_add(&p->events, 1);
+}
+
+void fprop_fraction_percpu(struct fprop_global *p,
+                          struct fprop_local_percpu *pl,
+                          unsigned long *numerator, unsigned long *denominator)
+{
+       unsigned int seq;
+       s64 num, den;
+
+       do {
+               seq = read_seqcount_begin(&p->sequence);
+               fprop_reflect_period_percpu(p, pl);
+               num = percpu_counter_read_positive(&pl->events);
+               den = percpu_counter_read_positive(&p->events);
+       } while (read_seqcount_retry(&p->sequence, seq));
+
+       /*
+        * Make fraction <= 1 and denominator > 0 even in presence of percpu
+        * counter errors
+        */
+       if (den <= num) {
+               if (num)
+                       den = num;
+               else
+                       den = 1;
+       }
+       *denominator = den;
+       *numerator = num;
+}
+
+/*
+ * Like __fprop_inc_percpu() except that event is counted only if the given
+ * type has fraction smaller than @max_frac/FPROP_FRAC_BASE
+ */
+void __fprop_inc_percpu_max(struct fprop_global *p,
+                           struct fprop_local_percpu *pl, int max_frac)
+{
+       if (unlikely(max_frac < FPROP_FRAC_BASE)) {
+               unsigned long numerator, denominator;
+
+               fprop_fraction_percpu(p, pl, &numerator, &denominator);
+               if (numerator >
+                   (((u64)denominator) * max_frac) >> FPROP_FRAC_SHIFT)
+                       return;
+       } else
+               fprop_reflect_period_percpu(p, pl);
+       __percpu_counter_add(&pl->events, 1, PROP_BATCH);
+       percpu_counter_add(&p->events, 1);
+}
diff --git a/lib/memory-notifier-error-inject.c b/lib/memory-notifier-error-inject.c
new file mode 100644 (file)
index 0000000..e6239bf
--- /dev/null
@@ -0,0 +1,48 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/memory.h>
+
+#include "notifier-error-inject.h"
+
+static int priority;
+module_param(priority, int, 0);
+MODULE_PARM_DESC(priority, "specify memory notifier priority");
+
+static struct notifier_err_inject memory_notifier_err_inject = {
+       .actions = {
+               { NOTIFIER_ERR_INJECT_ACTION(MEM_GOING_ONLINE) },
+               { NOTIFIER_ERR_INJECT_ACTION(MEM_GOING_OFFLINE) },
+               {}
+       }
+};
+
+static struct dentry *dir;
+
+static int err_inject_init(void)
+{
+       int err;
+
+       dir = notifier_err_inject_init("memory", notifier_err_inject_dir,
+                                       &memory_notifier_err_inject, priority);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+
+       err = register_memory_notifier(&memory_notifier_err_inject.nb);
+       if (err)
+               debugfs_remove_recursive(dir);
+
+       return err;
+}
+
+static void err_inject_exit(void)
+{
+       unregister_memory_notifier(&memory_notifier_err_inject.nb);
+       debugfs_remove_recursive(dir);
+}
+
+module_init(err_inject_init);
+module_exit(err_inject_exit);
+
+MODULE_DESCRIPTION("memory notifier error injection module");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
diff --git a/lib/memweight.c b/lib/memweight.c
new file mode 100644 (file)
index 0000000..e35fc87
--- /dev/null
@@ -0,0 +1,38 @@
+#include <linux/export.h>
+#include <linux/bug.h>
+#include <linux/bitmap.h>
+
+/**
+ * memweight - count the total number of bits set in memory area
+ * @ptr: pointer to the start of the area
+ * @bytes: the size of the area
+ */
+size_t memweight(const void *ptr, size_t bytes)
+{
+       size_t ret = 0;
+       size_t longs;
+       const unsigned char *bitmap = ptr;
+
+       for (; bytes > 0 && ((unsigned long)bitmap) % sizeof(long);
+                       bytes--, bitmap++)
+               ret += hweight8(*bitmap);
+
+       longs = bytes / sizeof(long);
+       if (longs) {
+               BUG_ON(longs >= INT_MAX / BITS_PER_LONG);
+               ret += bitmap_weight((unsigned long *)bitmap,
+                               longs * BITS_PER_LONG);
+               bytes -= longs * sizeof(long);
+               bitmap += longs * sizeof(long);
+       }
+       /*
+        * The reason that this last loop is distinct from the preceding
+        * bitmap_weight() call is to compute 1-bits in the last region smaller
+        * than sizeof(long) properly on big-endian systems.
+        */
+       for (; bytes > 0; bytes--, bitmap++)
+               ret += hweight8(*bitmap);
+
+       return ret;
+}
+EXPORT_SYMBOL(memweight);
diff --git a/lib/notifier-error-inject.c b/lib/notifier-error-inject.c
new file mode 100644 (file)
index 0000000..44b92cb
--- /dev/null
@@ -0,0 +1,112 @@
+#include <linux/module.h>
+
+#include "notifier-error-inject.h"
+
+static int debugfs_errno_set(void *data, u64 val)
+{
+       *(int *)data = clamp_t(int, val, -MAX_ERRNO, 0);
+       return 0;
+}
+
+static int debugfs_errno_get(void *data, u64 *val)
+{
+       *val = *(int *)data;
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_errno, debugfs_errno_get, debugfs_errno_set,
+                       "%lld\n");
+
+static struct dentry *debugfs_create_errno(const char *name, mode_t mode,
+                               struct dentry *parent, int *value)
+{
+       return debugfs_create_file(name, mode, parent, value, &fops_errno);
+}
+
+static int notifier_err_inject_callback(struct notifier_block *nb,
+                               unsigned long val, void *p)
+{
+       int err = 0;
+       struct notifier_err_inject *err_inject =
+               container_of(nb, struct notifier_err_inject, nb);
+       struct notifier_err_inject_action *action;
+
+       for (action = err_inject->actions; action->name; action++) {
+               if (action->val == val) {
+                       err = action->error;
+                       break;
+               }
+       }
+       if (err)
+               pr_info("Injecting error (%d) to %s\n", err, action->name);
+
+       return notifier_from_errno(err);
+}
+
+struct dentry *notifier_err_inject_dir;
+EXPORT_SYMBOL_GPL(notifier_err_inject_dir);
+
+struct dentry *notifier_err_inject_init(const char *name, struct dentry *parent,
+                       struct notifier_err_inject *err_inject, int priority)
+{
+       struct notifier_err_inject_action *action;
+       mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+       struct dentry *dir;
+       struct dentry *actions_dir;
+
+       err_inject->nb.notifier_call = notifier_err_inject_callback;
+       err_inject->nb.priority = priority;
+
+       dir = debugfs_create_dir(name, parent);
+       if (!dir)
+               return ERR_PTR(-ENOMEM);
+
+       actions_dir = debugfs_create_dir("actions", dir);
+       if (!actions_dir)
+               goto fail;
+
+       for (action = err_inject->actions; action->name; action++) {
+               struct dentry *action_dir;
+
+               action_dir = debugfs_create_dir(action->name, actions_dir);
+               if (!action_dir)
+                       goto fail;
+
+               /*
+                * Create debugfs r/w file containing action->error. If
+                * notifier call chain is called with action->val, it will
+                * fail with the error code
+                */
+               if (!debugfs_create_errno("error", mode, action_dir,
+                                       &action->error))
+                       goto fail;
+       }
+       return dir;
+fail:
+       debugfs_remove_recursive(dir);
+       return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL_GPL(notifier_err_inject_init);
+
+static int __init err_inject_init(void)
+{
+       notifier_err_inject_dir =
+               debugfs_create_dir("notifier-error-inject", NULL);
+
+       if (!notifier_err_inject_dir)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void __exit err_inject_exit(void)
+{
+       debugfs_remove_recursive(notifier_err_inject_dir);
+}
+
+module_init(err_inject_init);
+module_exit(err_inject_exit);
+
+MODULE_DESCRIPTION("Notifier error injection module");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
diff --git a/lib/notifier-error-inject.h b/lib/notifier-error-inject.h
new file mode 100644 (file)
index 0000000..99b3b6f
--- /dev/null
@@ -0,0 +1,24 @@
+#include <linux/atomic.h>
+#include <linux/debugfs.h>
+#include <linux/notifier.h>
+
+struct notifier_err_inject_action {
+       unsigned long val;
+       int error;
+       const char *name;
+};
+
+#define NOTIFIER_ERR_INJECT_ACTION(action)     \
+       .name = #action, .val = (action),
+
+struct notifier_err_inject {
+       struct notifier_block nb;
+       struct notifier_err_inject_action actions[];
+       /* The last slot must be terminated with zero sentinel */
+};
+
+extern struct dentry *notifier_err_inject_dir;
+
+extern struct dentry *notifier_err_inject_init(const char *name,
+               struct dentry *parent, struct notifier_err_inject *err_inject,
+               int priority);
diff --git a/lib/pSeries-reconfig-notifier-error-inject.c b/lib/pSeries-reconfig-notifier-error-inject.c
new file mode 100644 (file)
index 0000000..7f7c98d
--- /dev/null
@@ -0,0 +1,51 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/pSeries_reconfig.h>
+
+#include "notifier-error-inject.h"
+
+static int priority;
+module_param(priority, int, 0);
+MODULE_PARM_DESC(priority, "specify pSeries reconfig notifier priority");
+
+static struct notifier_err_inject reconfig_err_inject = {
+       .actions = {
+               { NOTIFIER_ERR_INJECT_ACTION(PSERIES_RECONFIG_ADD) },
+               { NOTIFIER_ERR_INJECT_ACTION(PSERIES_RECONFIG_REMOVE) },
+               { NOTIFIER_ERR_INJECT_ACTION(PSERIES_DRCONF_MEM_ADD) },
+               { NOTIFIER_ERR_INJECT_ACTION(PSERIES_DRCONF_MEM_REMOVE) },
+               {}
+       }
+};
+
+static struct dentry *dir;
+
+static int err_inject_init(void)
+{
+       int err;
+
+       dir = notifier_err_inject_init("pSeries-reconfig",
+               notifier_err_inject_dir, &reconfig_err_inject, priority);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+
+       err = pSeries_reconfig_notifier_register(&reconfig_err_inject.nb);
+       if (err)
+               debugfs_remove_recursive(dir);
+
+       return err;
+}
+
+static void err_inject_exit(void)
+{
+       pSeries_reconfig_notifier_unregister(&reconfig_err_inject.nb);
+       debugfs_remove_recursive(dir);
+}
+
+module_init(err_inject_init);
+module_exit(err_inject_exit);
+
+MODULE_DESCRIPTION("pSeries reconfig notifier error injection module");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
diff --git a/lib/pm-notifier-error-inject.c b/lib/pm-notifier-error-inject.c
new file mode 100644 (file)
index 0000000..c094b2d
--- /dev/null
@@ -0,0 +1,49 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/suspend.h>
+
+#include "notifier-error-inject.h"
+
+static int priority;
+module_param(priority, int, 0);
+MODULE_PARM_DESC(priority, "specify PM notifier priority");
+
+static struct notifier_err_inject pm_notifier_err_inject = {
+       .actions = {
+               { NOTIFIER_ERR_INJECT_ACTION(PM_HIBERNATION_PREPARE) },
+               { NOTIFIER_ERR_INJECT_ACTION(PM_SUSPEND_PREPARE) },
+               { NOTIFIER_ERR_INJECT_ACTION(PM_RESTORE_PREPARE) },
+               {}
+       }
+};
+
+static struct dentry *dir;
+
+static int err_inject_init(void)
+{
+       int err;
+
+       dir = notifier_err_inject_init("pm", notifier_err_inject_dir,
+                                       &pm_notifier_err_inject, priority);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+
+       err = register_pm_notifier(&pm_notifier_err_inject.nb);
+       if (err)
+               debugfs_remove_recursive(dir);
+
+       return err;
+}
+
+static void err_inject_exit(void)
+{
+       unregister_pm_notifier(&pm_notifier_err_inject.nb);
+       debugfs_remove_recursive(dir);
+}
+
+module_init(err_inject_init);
+module_exit(err_inject_exit);
+
+MODULE_DESCRIPTION("PM notifier error injection module");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
index 6096e89bee552ea79ed1ae5410f3b3ee9327cc0f..fadae774a20cc6abb0226ee4c3bfbc6cb4cd4eeb 100644 (file)
@@ -279,14 +279,6 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents,
                if (!left)
                        sg_mark_end(&sg[sg_size - 1]);
 
-               /*
-                * only really needed for mempool backed sg allocations (like
-                * SCSI), a possible improvement here would be to pass the
-                * table pointer into the allocator and let that clear these
-                * flags
-                */
-               gfp_mask &= ~__GFP_WAIT;
-               gfp_mask |= __GFP_HIGH;
                prv = sg;
        } while (left);
 
@@ -318,6 +310,70 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
 }
 EXPORT_SYMBOL(sg_alloc_table);
 
+/**
+ * sg_alloc_table_from_pages - Allocate and initialize an sg table from
+ *                            an array of pages
+ * @sgt:       The sg table header to use
+ * @pages:     Pointer to an array of page pointers
+ * @n_pages:   Number of pages in the pages array
+ * @offset:     Offset from start of the first page to the start of a buffer
+ * @size:       Number of valid bytes in the buffer (after offset)
+ * @gfp_mask:  GFP allocation mask
+ *
+ *  Description:
+ *    Allocate and initialize an sg table from a list of pages. Contiguous
+ *    ranges of the pages are squashed into a single scatterlist node. A user
+ *    may provide an offset at a start and a size of valid data in a buffer
+ *    specified by the page array. The returned sg table is released by
+ *    sg_free_table.
+ *
+ * Returns:
+ *   0 on success, negative error on failure
+ */
+int sg_alloc_table_from_pages(struct sg_table *sgt,
+       struct page **pages, unsigned int n_pages,
+       unsigned long offset, unsigned long size,
+       gfp_t gfp_mask)
+{
+       unsigned int chunks;
+       unsigned int i;
+       unsigned int cur_page;
+       int ret;
+       struct scatterlist *s;
+
+       /* compute number of contiguous chunks */
+       chunks = 1;
+       for (i = 1; i < n_pages; ++i)
+               if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1)
+                       ++chunks;
+
+       ret = sg_alloc_table(sgt, chunks, gfp_mask);
+       if (unlikely(ret))
+               return ret;
+
+       /* merging chunks and putting them into the scatterlist */
+       cur_page = 0;
+       for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
+               unsigned long chunk_size;
+               unsigned int j;
+
+               /* look for the end of the current chunk */
+               for (j = cur_page + 1; j < n_pages; ++j)
+                       if (page_to_pfn(pages[j]) !=
+                           page_to_pfn(pages[j - 1]) + 1)
+                               break;
+
+               chunk_size = ((j - cur_page) << PAGE_SHIFT) - offset;
+               sg_set_page(s, pages[cur_page], min(size, chunk_size), offset);
+               size -= chunk_size;
+               offset = 0;
+               cur_page = j;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(sg_alloc_table_from_pages);
+
 /**
  * sg_miter_start - start mapping iteration over a sg list
  * @miter: sg mapping iter to be started
index e91fbc23fff121915217a8e5c53c29a2b52aeba4..eb10578ae055947d2cd39c9e4c8e9f7c1c76477e 100644 (file)
@@ -58,7 +58,7 @@ static void spin_dump(raw_spinlock_t *lock, const char *msg)
        printk(KERN_EMERG "BUG: spinlock %s on CPU#%d, %s/%d\n",
                msg, raw_smp_processor_id(),
                current->comm, task_pid_nr(current));
-       printk(KERN_EMERG " lock: %ps, .magic: %08x, .owner: %s/%d, "
+       printk(KERN_EMERG " lock: %pS, .magic: %08x, .owner: %s/%d, "
                        ".owner_cpu: %d\n",
                lock, lock->magic,
                owner ? owner->comm : "<none>",
index c3f36d415bdf43034415c801b8e3f922f5e5b928..0e337541f005d8f29a36434dae555b7477d12164 100644 (file)
@@ -654,6 +654,50 @@ char *resource_string(char *buf, char *end, struct resource *res,
        return string(buf, end, sym, spec);
 }
 
+static noinline_for_stack
+char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
+                const char *fmt)
+{
+       int i, len = 1;         /* if we pass '%ph[CDN]', field witdh remains
+                                  negative value, fallback to the default */
+       char separator;
+
+       if (spec.field_width == 0)
+               /* nothing to print */
+               return buf;
+
+       if (ZERO_OR_NULL_PTR(addr))
+               /* NULL pointer */
+               return string(buf, end, NULL, spec);
+
+       switch (fmt[1]) {
+       case 'C':
+               separator = ':';
+               break;
+       case 'D':
+               separator = '-';
+               break;
+       case 'N':
+               separator = 0;
+               break;
+       default:
+               separator = ' ';
+               break;
+       }
+
+       if (spec.field_width > 0)
+               len = min_t(int, spec.field_width, 64);
+
+       for (i = 0; i < len && buf < end - 1; i++) {
+               buf = hex_byte_pack(buf, addr[i]);
+
+               if (buf < end && separator && i != len - 1)
+                       *buf++ = separator;
+       }
+
+       return buf;
+}
+
 static noinline_for_stack
 char *mac_address_string(char *buf, char *end, u8 *addr,
                         struct printf_spec spec, const char *fmt)
@@ -662,15 +706,28 @@ char *mac_address_string(char *buf, char *end, u8 *addr,
        char *p = mac_addr;
        int i;
        char separator;
+       bool reversed = false;
 
-       if (fmt[1] == 'F') {            /* FDDI canonical format */
+       switch (fmt[1]) {
+       case 'F':
                separator = '-';
-       } else {
+               break;
+
+       case 'R':
+               reversed = true;
+               /* fall through */
+
+       default:
                separator = ':';
+               break;
        }
 
        for (i = 0; i < 6; i++) {
-               p = hex_byte_pack(p, addr[i]);
+               if (reversed)
+                       p = hex_byte_pack(p, addr[5 - i]);
+               else
+                       p = hex_byte_pack(p, addr[i]);
+
                if (fmt[0] == 'M' && i != 5)
                        *p++ = separator;
        }
@@ -933,6 +990,7 @@ int kptr_restrict __read_mostly;
  * - 'm' For a 6-byte MAC address, it prints the hex address without colons
  * - 'MF' For a 6-byte MAC FDDI address, it prints the address
  *       with a dash-separated hex notation
+ * - '[mM]R For a 6-byte MAC address, Reverse order (Bluetooth)
  * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
  *       IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
  *       IPv6 uses colon separated network-order 16 bit hex with leading 0's
@@ -960,6 +1018,13 @@ int kptr_restrict __read_mostly;
  *       correctness of the format string and va_list arguments.
  * - 'K' For a kernel pointer that should be hidden from unprivileged users
  * - 'NF' For a netdev_features_t
+ * - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with
+ *            a certain separator (' ' by default):
+ *              C colon
+ *              D dash
+ *              N no separator
+ *            The maximum supported length is 64 bytes of the input. Consider
+ *            to use print_hex_dump() for the larger input.
  *
  * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
  * function pointers are really function descriptors, which contain a
@@ -993,9 +1058,12 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
        case 'R':
        case 'r':
                return resource_string(buf, end, ptr, spec, fmt);
+       case 'h':
+               return hex_string(buf, end, ptr, spec, fmt);
        case 'M':                       /* Colon separated: 00:01:02:03:04:05 */
        case 'm':                       /* Contiguous: 000102030405 */
-                                       /* [mM]F (FDDI, bit reversed) */
+                                       /* [mM]F (FDDI) */
+                                       /* [mM]R (Reverse order; Bluetooth) */
                return mac_address_string(buf, end, ptr, spec, fmt);
        case 'I':                       /* Formatted IP supported
                                         * 4:   1.2.3.4
@@ -1030,7 +1098,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                 * %pK cannot be used in IRQ context because its test
                 * for CAP_SYSLOG would be meaningless.
                 */
-               if (in_irq() || in_serving_softirq() || in_nmi()) {
+               if (kptr_restrict && (in_irq() || in_serving_softirq() ||
+                                     in_nmi())) {
                        if (spec.field_width == -1)
                                spec.field_width = default_width;
                        return string(buf, end, "pK-error", spec);
@@ -1280,8 +1349,12 @@ qualifier:
  * %pI6c print an IPv6 address as specified by RFC 5952
  * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
  *   case.
+ * %*ph[CDN] a variable-length hex string with a separator (supports up to 64
+ *           bytes of the input)
  * %n is ignored
  *
+ * ** Please update Documentation/printk-formats.txt when making changes **
+ *
  * The return value is the number of characters which would
  * be generated for the given input, excluding the trailing
  * '\0', as per ISO C99. If you want to have the exact
index 2e2fbbefb99fa94c97be13aa8fa71da823455409..8e81fe263c94f63dcf3700fd63828a58d0c963af 100644 (file)
@@ -16,7 +16,8 @@ obj-y                 := filemap.o mempool.o oom_kill.o fadvise.o \
                           readahead.o swap.o truncate.o vmscan.o shmem.o \
                           prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
                           page_isolation.o mm_init.o mmu_context.o percpu.o \
-                          compaction.o $(mmu-y)
+                          compaction.o slab_common.o $(mmu-y)
+
 obj-y += init-mm.o
 
 ifdef CONFIG_NO_BOOTMEM
index dd8e2aafb07e1aecae5e42ac403d9915caa7e698..3387aea112092f5ae0bcbba872f08db487bc1f2c 100644 (file)
@@ -677,7 +677,7 @@ int bdi_init(struct backing_dev_info *bdi)
 
        bdi->min_ratio = 0;
        bdi->max_ratio = 100;
-       bdi->max_prop_frac = PROP_FRAC_BASE;
+       bdi->max_prop_frac = FPROP_FRAC_BASE;
        spin_lock_init(&bdi->wb_lock);
        INIT_LIST_HEAD(&bdi->bdi_list);
        INIT_LIST_HEAD(&bdi->work_list);
@@ -700,7 +700,7 @@ int bdi_init(struct backing_dev_info *bdi)
        bdi->write_bandwidth = INIT_BW;
        bdi->avg_write_bandwidth = INIT_BW;
 
-       err = prop_local_init_percpu(&bdi->completions);
+       err = fprop_local_init_percpu(&bdi->completions);
 
        if (err) {
 err:
@@ -744,7 +744,7 @@ void bdi_destroy(struct backing_dev_info *bdi)
        for (i = 0; i < NR_BDI_STAT_ITEMS; i++)
                percpu_counter_destroy(&bdi->bdi_stat[i]);
 
-       prop_local_destroy_percpu(&bdi->completions);
+       fprop_local_destroy_percpu(&bdi->completions);
 }
 EXPORT_SYMBOL(bdi_destroy);
 
index de4ce70584508edfa95eec5827271511052af102..6de0d613bbe6a49448259ac0ae317b669751f748 100644 (file)
@@ -1433,8 +1433,8 @@ static int soft_offline_huge_page(struct page *page, int flags)
        /* Keep page count to indicate a given hugepage is isolated. */
 
        list_add(&hpage->lru, &pagelist);
-       ret = migrate_huge_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, 0,
-                               true);
+       ret = migrate_huge_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, false,
+                               MIGRATE_SYNC);
        if (ret) {
                struct page *page1, *page2;
                list_for_each_entry_safe(page1, page2, &pagelist, lru)
@@ -1563,7 +1563,7 @@ int soft_offline_page(struct page *page, int flags)
                                            page_is_file_cache(page));
                list_add(&page->lru, &pagelist);
                ret = migrate_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL,
-                                                       0, MIGRATE_SYNC);
+                                                       false, MIGRATE_SYNC);
                if (ret) {
                        putback_lru_pages(&pagelist);
                        pr_info("soft offline: %#lx: migration failed %d, type %lx\n",
index 1d771e4200d222eea46458bdd6089279a78ffeb5..bd92431d4c49a8e29f4b46d50d6d0e66c69098d5 100644 (file)
@@ -1602,8 +1602,14 @@ static unsigned interleave_nodes(struct mempolicy *policy)
  * task can change it's policy.  The system default policy requires no
  * such protection.
  */
-unsigned slab_node(struct mempolicy *policy)
+unsigned slab_node(void)
 {
+       struct mempolicy *policy;
+
+       if (in_interrupt())
+               return numa_node_id();
+
+       policy = current->mempolicy;
        if (!policy || policy->flags & MPOL_F_LOCAL)
                return numa_node_id();
 
index 3edfcdfa42d9f27a5238780065220ec3b4fc702a..4fe2697339ed479296d9fb9b54553e32b8f8fe7f 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2345,9 +2345,6 @@ int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
             security_vm_enough_memory_mm(mm, vma_pages(vma)))
                return -ENOMEM;
 
-       if (vma->vm_file && uprobe_mmap(vma))
-               return -EINVAL;
-
        vma_link(mm, vma, prev, rb_link, rb_parent);
        return 0;
 }
@@ -2418,9 +2415,6 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
                        if (new_vma->vm_file) {
                                get_file(new_vma->vm_file);
 
-                               if (uprobe_mmap(new_vma))
-                                       goto out_free_mempol;
-
                                if (vma->vm_flags & VM_EXECUTABLE)
                                        added_exe_file_vma(mm);
                        }
index 93d8d2f7108ccb8b3c5a73de42361f23d98049c1..e5363f34e0250656c357d965a2e8949577cfb607 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/syscalls.h>
 #include <linux/buffer_head.h> /* __set_page_dirty_buffers */
 #include <linux/pagevec.h>
+#include <linux/timer.h>
 #include <trace/events/writeback.h>
 
 /*
@@ -135,7 +136,20 @@ unsigned long global_dirty_limit;
  * measured in page writeback completions.
  *
  */
-static struct prop_descriptor vm_completions;
+static struct fprop_global writeout_completions;
+
+static void writeout_period(unsigned long t);
+/* Timer for aging of writeout_completions */
+static struct timer_list writeout_period_timer =
+               TIMER_DEFERRED_INITIALIZER(writeout_period, 0, 0);
+static unsigned long writeout_period_time = 0;
+
+/*
+ * Length of period for aging writeout fractions of bdis. This is an
+ * arbitrarily chosen number. The longer the period, the slower fractions will
+ * reflect changes in current writeout rate.
+ */
+#define VM_COMPLETIONS_PERIOD_LEN (3*HZ)
 
 /*
  * Work out the current dirty-memory clamping and background writeout
@@ -322,34 +336,6 @@ bool zone_dirty_ok(struct zone *zone)
               zone_page_state(zone, NR_WRITEBACK) <= limit;
 }
 
-/*
- * couple the period to the dirty_ratio:
- *
- *   period/2 ~ roundup_pow_of_two(dirty limit)
- */
-static int calc_period_shift(void)
-{
-       unsigned long dirty_total;
-
-       if (vm_dirty_bytes)
-               dirty_total = vm_dirty_bytes / PAGE_SIZE;
-       else
-               dirty_total = (vm_dirty_ratio * global_dirtyable_memory()) /
-                               100;
-       return 2 + ilog2(dirty_total - 1);
-}
-
-/*
- * update the period when the dirty threshold changes.
- */
-static void update_completion_period(void)
-{
-       int shift = calc_period_shift();
-       prop_change_shift(&vm_completions, shift);
-
-       writeback_set_ratelimit();
-}
-
 int dirty_background_ratio_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
                loff_t *ppos)
@@ -383,7 +369,7 @@ int dirty_ratio_handler(struct ctl_table *table, int write,
 
        ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
        if (ret == 0 && write && vm_dirty_ratio != old_ratio) {
-               update_completion_period();
+               writeback_set_ratelimit();
                vm_dirty_bytes = 0;
        }
        return ret;
@@ -398,12 +384,21 @@ int dirty_bytes_handler(struct ctl_table *table, int write,
 
        ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
        if (ret == 0 && write && vm_dirty_bytes != old_bytes) {
-               update_completion_period();
+               writeback_set_ratelimit();
                vm_dirty_ratio = 0;
        }
        return ret;
 }
 
+static unsigned long wp_next_time(unsigned long cur_time)
+{
+       cur_time += VM_COMPLETIONS_PERIOD_LEN;
+       /* 0 has a special meaning... */
+       if (!cur_time)
+               return 1;
+       return cur_time;
+}
+
 /*
  * Increment the BDI's writeout completion count and the global writeout
  * completion count. Called from test_clear_page_writeback().
@@ -411,8 +406,19 @@ int dirty_bytes_handler(struct ctl_table *table, int write,
 static inline void __bdi_writeout_inc(struct backing_dev_info *bdi)
 {
        __inc_bdi_stat(bdi, BDI_WRITTEN);
-       __prop_inc_percpu_max(&vm_completions, &bdi->completions,
-                             bdi->max_prop_frac);
+       __fprop_inc_percpu_max(&writeout_completions, &bdi->completions,
+                              bdi->max_prop_frac);
+       /* First event after period switching was turned off? */
+       if (!unlikely(writeout_period_time)) {
+               /*
+                * We can race with other __bdi_writeout_inc calls here but
+                * it does not cause any harm since the resulting time when
+                * timer will fire and what is in writeout_period_time will be
+                * roughly the same.
+                */
+               writeout_period_time = wp_next_time(jiffies);
+               mod_timer(&writeout_period_timer, writeout_period_time);
+       }
 }
 
 void bdi_writeout_inc(struct backing_dev_info *bdi)
@@ -431,10 +437,32 @@ EXPORT_SYMBOL_GPL(bdi_writeout_inc);
 static void bdi_writeout_fraction(struct backing_dev_info *bdi,
                long *numerator, long *denominator)
 {
-       prop_fraction_percpu(&vm_completions, &bdi->completions,
+       fprop_fraction_percpu(&writeout_completions, &bdi->completions,
                                numerator, denominator);
 }
 
+/*
+ * On idle system, we can be called long after we scheduled because we use
+ * deferred timers so count with missed periods.
+ */
+static void writeout_period(unsigned long t)
+{
+       int miss_periods = (jiffies - writeout_period_time) /
+                                                VM_COMPLETIONS_PERIOD_LEN;
+
+       if (fprop_new_period(&writeout_completions, miss_periods + 1)) {
+               writeout_period_time = wp_next_time(writeout_period_time +
+                               miss_periods * VM_COMPLETIONS_PERIOD_LEN);
+               mod_timer(&writeout_period_timer, writeout_period_time);
+       } else {
+               /*
+                * Aging has zeroed all fractions. Stop wasting CPU on period
+                * updates.
+                */
+               writeout_period_time = 0;
+       }
+}
+
 /*
  * bdi_min_ratio keeps the sum of the minimum dirty shares of all
  * registered backing devices, which, for obvious reasons, can not
@@ -475,7 +503,7 @@ int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned max_ratio)
                ret = -EINVAL;
        } else {
                bdi->max_ratio = max_ratio;
-               bdi->max_prop_frac = (PROP_FRAC_BASE * max_ratio) / 100;
+               bdi->max_prop_frac = (FPROP_FRAC_BASE * max_ratio) / 100;
        }
        spin_unlock_bh(&bdi_lock);
 
@@ -918,7 +946,7 @@ static void bdi_update_dirty_ratelimit(struct backing_dev_info *bdi,
         *      bdi->dirty_ratelimit = balanced_dirty_ratelimit;
         *
         * However to get a more stable dirty_ratelimit, the below elaborated
-        * code makes use of task_ratelimit to filter out sigular points and
+        * code makes use of task_ratelimit to filter out singular points and
         * limit the step size.
         *
         * The below code essentially only uses the relative value of
@@ -941,7 +969,7 @@ static void bdi_update_dirty_ratelimit(struct backing_dev_info *bdi,
         * feel and care are stable dirty rate and small position error.
         *
         * |task_ratelimit - dirty_ratelimit| is used to limit the step size
-        * and filter out the sigular points of balanced_dirty_ratelimit. Which
+        * and filter out the singular points of balanced_dirty_ratelimit. Which
         * keeps jumping around randomly and can even leap far away at times
         * due to the small 200ms estimation period of dirty_rate (we want to
         * keep that period small to reduce time lags).
@@ -1606,13 +1634,10 @@ static struct notifier_block __cpuinitdata ratelimit_nb = {
  */
 void __init page_writeback_init(void)
 {
-       int shift;
-
        writeback_set_ratelimit();
        register_cpu_notifier(&ratelimit_nb);
 
-       shift = calc_period_shift();
-       prop_descriptor_init(&vm_completions, shift);
+       fprop_global_init(&writeout_completions);
 }
 
 /**
index e901a36e2520c2b7aa5123ddcd0553415b764397..1fcf3ac94b6ccd3e085c5a0c6ba35a59fe553e8e 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -68,7 +68,7 @@
  * Further notes from the original documentation:
  *
  * 11 April '97.  Started multi-threading - markhe
- *     The global cache-chain is protected by the mutex 'cache_chain_mutex'.
+ *     The global cache-chain is protected by the mutex 'slab_mutex'.
  *     The sem is only needed when accessing/extending the cache-chain, which
  *     can never happen inside an interrupt (kmem_cache_create(),
  *     kmem_cache_shrink() and kmem_cache_reap()).
@@ -87,6 +87,7 @@
  */
 
 #include       <linux/slab.h>
+#include       "slab.h"
 #include       <linux/mm.h>
 #include       <linux/poison.h>
 #include       <linux/swap.h>
@@ -424,8 +425,8 @@ static void kmem_list3_init(struct kmem_list3 *parent)
  * cachep->obj_offset - BYTES_PER_WORD .. cachep->obj_offset - 1:
  *             redzone word.
  * cachep->obj_offset: The real object.
- * cachep->buffer_size - 2* BYTES_PER_WORD: redzone word [BYTES_PER_WORD long]
- * cachep->buffer_size - 1* BYTES_PER_WORD: last caller address
+ * cachep->size - 2* BYTES_PER_WORD: redzone word [BYTES_PER_WORD long]
+ * cachep->size - 1* BYTES_PER_WORD: last caller address
  *                                     [BYTES_PER_WORD long]
  */
 static int obj_offset(struct kmem_cache *cachep)
@@ -433,11 +434,6 @@ static int obj_offset(struct kmem_cache *cachep)
        return cachep->obj_offset;
 }
 
-static int obj_size(struct kmem_cache *cachep)
-{
-       return cachep->obj_size;
-}
-
 static unsigned long long *dbg_redzone1(struct kmem_cache *cachep, void *objp)
 {
        BUG_ON(!(cachep->flags & SLAB_RED_ZONE));
@@ -449,23 +445,22 @@ static unsigned long long *dbg_redzone2(struct kmem_cache *cachep, void *objp)
 {
        BUG_ON(!(cachep->flags & SLAB_RED_ZONE));
        if (cachep->flags & SLAB_STORE_USER)
-               return (unsigned long long *)(objp + cachep->buffer_size -
+               return (unsigned long long *)(objp + cachep->size -
                                              sizeof(unsigned long long) -
                                              REDZONE_ALIGN);
-       return (unsigned long long *) (objp + cachep->buffer_size -
+       return (unsigned long long *) (objp + cachep->size -
                                       sizeof(unsigned long long));
 }
 
 static void **dbg_userword(struct kmem_cache *cachep, void *objp)
 {
        BUG_ON(!(cachep->flags & SLAB_STORE_USER));
-       return (void **)(objp + cachep->buffer_size - BYTES_PER_WORD);
+       return (void **)(objp + cachep->size - BYTES_PER_WORD);
 }
 
 #else
 
 #define obj_offset(x)                  0
-#define obj_size(cachep)               (cachep->buffer_size)
 #define dbg_redzone1(cachep, objp)     ({BUG(); (unsigned long long *)NULL;})
 #define dbg_redzone2(cachep, objp)     ({BUG(); (unsigned long long *)NULL;})
 #define dbg_userword(cachep, objp)     ({BUG(); (void **)NULL;})
@@ -475,7 +470,7 @@ static void **dbg_userword(struct kmem_cache *cachep, void *objp)
 #ifdef CONFIG_TRACING
 size_t slab_buffer_size(struct kmem_cache *cachep)
 {
-       return cachep->buffer_size;
+       return cachep->size;
 }
 EXPORT_SYMBOL(slab_buffer_size);
 #endif
@@ -489,56 +484,37 @@ EXPORT_SYMBOL(slab_buffer_size);
 static int slab_max_order = SLAB_MAX_ORDER_LO;
 static bool slab_max_order_set __initdata;
 
-/*
- * Functions for storing/retrieving the cachep and or slab from the page
- * allocator.  These are used to find the slab an obj belongs to.  With kfree(),
- * these are used to find the cache which an obj belongs to.
- */
-static inline void page_set_cache(struct page *page, struct kmem_cache *cache)
-{
-       page->lru.next = (struct list_head *)cache;
-}
-
 static inline struct kmem_cache *page_get_cache(struct page *page)
 {
        page = compound_head(page);
        BUG_ON(!PageSlab(page));
-       return (struct kmem_cache *)page->lru.next;
-}
-
-static inline void page_set_slab(struct page *page, struct slab *slab)
-{
-       page->lru.prev = (struct list_head *)slab;
-}
-
-static inline struct slab *page_get_slab(struct page *page)
-{
-       BUG_ON(!PageSlab(page));
-       return (struct slab *)page->lru.prev;
+       return page->slab_cache;
 }
 
 static inline struct kmem_cache *virt_to_cache(const void *obj)
 {
        struct page *page = virt_to_head_page(obj);
-       return page_get_cache(page);
+       return page->slab_cache;
 }
 
 static inline struct slab *virt_to_slab(const void *obj)
 {
        struct page *page = virt_to_head_page(obj);
-       return page_get_slab(page);
+
+       VM_BUG_ON(!PageSlab(page));
+       return page->slab_page;
 }
 
 static inline void *index_to_obj(struct kmem_cache *cache, struct slab *slab,
                                 unsigned int idx)
 {
-       return slab->s_mem + cache->buffer_size * idx;
+       return slab->s_mem + cache->size * idx;
 }
 
 /*
- * We want to avoid an expensive divide : (offset / cache->buffer_size)
- *   Using the fact that buffer_size is a constant for a particular cache,
- *   we can replace (offset / cache->buffer_size) by
+ * We want to avoid an expensive divide : (offset / cache->size)
+ *   Using the fact that size is a constant for a particular cache,
+ *   we can replace (offset / cache->size) by
  *   reciprocal_divide(offset, cache->reciprocal_buffer_size)
  */
 static inline unsigned int obj_to_index(const struct kmem_cache *cache,
@@ -584,33 +560,12 @@ static struct kmem_cache cache_cache = {
        .batchcount = 1,
        .limit = BOOT_CPUCACHE_ENTRIES,
        .shared = 1,
-       .buffer_size = sizeof(struct kmem_cache),
+       .size = sizeof(struct kmem_cache),
        .name = "kmem_cache",
 };
 
 #define BAD_ALIEN_MAGIC 0x01020304ul
 
-/*
- * chicken and egg problem: delay the per-cpu array allocation
- * until the general caches are up.
- */
-static enum {
-       NONE,
-       PARTIAL_AC,
-       PARTIAL_L3,
-       EARLY,
-       LATE,
-       FULL
-} g_cpucache_up;
-
-/*
- * used by boot code to determine if it can use slab based allocator
- */
-int slab_is_available(void)
-{
-       return g_cpucache_up >= EARLY;
-}
-
 #ifdef CONFIG_LOCKDEP
 
 /*
@@ -676,7 +631,7 @@ static void init_node_lock_keys(int q)
 {
        struct cache_sizes *s = malloc_sizes;
 
-       if (g_cpucache_up < LATE)
+       if (slab_state < UP)
                return;
 
        for (s = malloc_sizes; s->cs_size != ULONG_MAX; s++) {
@@ -716,12 +671,6 @@ static void slab_set_debugobj_lock_classes(struct kmem_cache *cachep)
 }
 #endif
 
-/*
- * Guard access to the cache-chain.
- */
-static DEFINE_MUTEX(cache_chain_mutex);
-static struct list_head cache_chain;
-
 static DEFINE_PER_CPU(struct delayed_work, slab_reap_work);
 
 static inline struct array_cache *cpu_cache_get(struct kmem_cache *cachep)
@@ -1145,7 +1094,7 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
  * When hotplugging memory or a cpu, existing nodelists are not replaced if
  * already in use.
  *
- * Must hold cache_chain_mutex.
+ * Must hold slab_mutex.
  */
 static int init_cache_nodelists_node(int node)
 {
@@ -1153,7 +1102,7 @@ static int init_cache_nodelists_node(int node)
        struct kmem_list3 *l3;
        const int memsize = sizeof(struct kmem_list3);
 
-       list_for_each_entry(cachep, &cache_chain, next) {
+       list_for_each_entry(cachep, &slab_caches, list) {
                /*
                 * Set up the size64 kmemlist for cpu before we can
                 * begin anything. Make sure some other cpu on this
@@ -1169,7 +1118,7 @@ static int init_cache_nodelists_node(int node)
 
                        /*
                         * The l3s don't come and go as CPUs come and
-                        * go.  cache_chain_mutex is sufficient
+                        * go.  slab_mutex is sufficient
                         * protection here.
                         */
                        cachep->nodelists[node] = l3;
@@ -1191,7 +1140,7 @@ static void __cpuinit cpuup_canceled(long cpu)
        int node = cpu_to_mem(cpu);
        const struct cpumask *mask = cpumask_of_node(node);
 
-       list_for_each_entry(cachep, &cache_chain, next) {
+       list_for_each_entry(cachep, &slab_caches, list) {
                struct array_cache *nc;
                struct array_cache *shared;
                struct array_cache **alien;
@@ -1241,7 +1190,7 @@ free_array_cache:
         * the respective cache's slabs,  now we can go ahead and
         * shrink each nodelist to its limit.
         */
-       list_for_each_entry(cachep, &cache_chain, next) {
+       list_for_each_entry(cachep, &slab_caches, list) {
                l3 = cachep->nodelists[node];
                if (!l3)
                        continue;
@@ -1270,7 +1219,7 @@ static int __cpuinit cpuup_prepare(long cpu)
         * Now we can go ahead with allocating the shared arrays and
         * array caches
         */
-       list_for_each_entry(cachep, &cache_chain, next) {
+       list_for_each_entry(cachep, &slab_caches, list) {
                struct array_cache *nc;
                struct array_cache *shared = NULL;
                struct array_cache **alien = NULL;
@@ -1338,9 +1287,9 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               mutex_lock(&cache_chain_mutex);
+               mutex_lock(&slab_mutex);
                err = cpuup_prepare(cpu);
-               mutex_unlock(&cache_chain_mutex);
+               mutex_unlock(&slab_mutex);
                break;
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
@@ -1350,7 +1299,7 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
        case CPU_DOWN_PREPARE:
        case CPU_DOWN_PREPARE_FROZEN:
                /*
-                * Shutdown cache reaper. Note that the cache_chain_mutex is
+                * Shutdown cache reaper. Note that the slab_mutex is
                 * held so that if cache_reap() is invoked it cannot do
                 * anything expensive but will only modify reap_work
                 * and reschedule the timer.
@@ -1377,9 +1326,9 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
 #endif
        case CPU_UP_CANCELED:
        case CPU_UP_CANCELED_FROZEN:
-               mutex_lock(&cache_chain_mutex);
+               mutex_lock(&slab_mutex);
                cpuup_canceled(cpu);
-               mutex_unlock(&cache_chain_mutex);
+               mutex_unlock(&slab_mutex);
                break;
        }
        return notifier_from_errno(err);
@@ -1395,14 +1344,14 @@ static struct notifier_block __cpuinitdata cpucache_notifier = {
  * Returns -EBUSY if all objects cannot be drained so that the node is not
  * removed.
  *
- * Must hold cache_chain_mutex.
+ * Must hold slab_mutex.
  */
 static int __meminit drain_cache_nodelists_node(int node)
 {
        struct kmem_cache *cachep;
        int ret = 0;
 
-       list_for_each_entry(cachep, &cache_chain, next) {
+       list_for_each_entry(cachep, &slab_caches, list) {
                struct kmem_list3 *l3;
 
                l3 = cachep->nodelists[node];
@@ -1433,14 +1382,14 @@ static int __meminit slab_memory_callback(struct notifier_block *self,
 
        switch (action) {
        case MEM_GOING_ONLINE:
-               mutex_lock(&cache_chain_mutex);
+               mutex_lock(&slab_mutex);
                ret = init_cache_nodelists_node(nid);
-               mutex_unlock(&cache_chain_mutex);
+               mutex_unlock(&slab_mutex);
                break;
        case MEM_GOING_OFFLINE:
-               mutex_lock(&cache_chain_mutex);
+               mutex_lock(&slab_mutex);
                ret = drain_cache_nodelists_node(nid);
-               mutex_unlock(&cache_chain_mutex);
+               mutex_unlock(&slab_mutex);
                break;
        case MEM_ONLINE:
        case MEM_OFFLINE:
@@ -1544,8 +1493,8 @@ void __init kmem_cache_init(void)
        node = numa_mem_id();
 
        /* 1) create the cache_cache */
-       INIT_LIST_HEAD(&cache_chain);
-       list_add(&cache_cache.next, &cache_chain);
+       INIT_LIST_HEAD(&slab_caches);
+       list_add(&cache_cache.list, &slab_caches);
        cache_cache.colour_off = cache_line_size();
        cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
        cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE + node];
@@ -1553,18 +1502,16 @@ void __init kmem_cache_init(void)
        /*
         * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids
         */
-       cache_cache.buffer_size = offsetof(struct kmem_cache, array[nr_cpu_ids]) +
+       cache_cache.size = offsetof(struct kmem_cache, array[nr_cpu_ids]) +
                                  nr_node_ids * sizeof(struct kmem_list3 *);
-#if DEBUG
-       cache_cache.obj_size = cache_cache.buffer_size;
-#endif
-       cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,
+       cache_cache.object_size = cache_cache.size;
+       cache_cache.size = ALIGN(cache_cache.size,
                                        cache_line_size());
        cache_cache.reciprocal_buffer_size =
-               reciprocal_value(cache_cache.buffer_size);
+               reciprocal_value(cache_cache.size);
 
        for (order = 0; order < MAX_ORDER; order++) {
-               cache_estimate(order, cache_cache.buffer_size,
+               cache_estimate(order, cache_cache.size,
                        cache_line_size(), 0, &left_over, &cache_cache.num);
                if (cache_cache.num)
                        break;
@@ -1585,7 +1532,7 @@ void __init kmem_cache_init(void)
         * bug.
         */
 
-       sizes[INDEX_AC].cs_cachep = kmem_cache_create(names[INDEX_AC].name,
+       sizes[INDEX_AC].cs_cachep = __kmem_cache_create(names[INDEX_AC].name,
                                        sizes[INDEX_AC].cs_size,
                                        ARCH_KMALLOC_MINALIGN,
                                        ARCH_KMALLOC_FLAGS|SLAB_PANIC,
@@ -1593,7 +1540,7 @@ void __init kmem_cache_init(void)
 
        if (INDEX_AC != INDEX_L3) {
                sizes[INDEX_L3].cs_cachep =
-                       kmem_cache_create(names[INDEX_L3].name,
+                       __kmem_cache_create(names[INDEX_L3].name,
                                sizes[INDEX_L3].cs_size,
                                ARCH_KMALLOC_MINALIGN,
                                ARCH_KMALLOC_FLAGS|SLAB_PANIC,
@@ -1611,14 +1558,14 @@ void __init kmem_cache_init(void)
                 * allow tighter packing of the smaller caches.
                 */
                if (!sizes->cs_cachep) {
-                       sizes->cs_cachep = kmem_cache_create(names->name,
+                       sizes->cs_cachep = __kmem_cache_create(names->name,
                                        sizes->cs_size,
                                        ARCH_KMALLOC_MINALIGN,
                                        ARCH_KMALLOC_FLAGS|SLAB_PANIC,
                                        NULL);
                }
 #ifdef CONFIG_ZONE_DMA
-               sizes->cs_dmacachep = kmem_cache_create(
+               sizes->cs_dmacachep = __kmem_cache_create(
                                        names->name_dma,
                                        sizes->cs_size,
                                        ARCH_KMALLOC_MINALIGN,
@@ -1676,27 +1623,27 @@ void __init kmem_cache_init(void)
                }
        }
 
-       g_cpucache_up = EARLY;
+       slab_state = UP;
 }
 
 void __init kmem_cache_init_late(void)
 {
        struct kmem_cache *cachep;
 
-       g_cpucache_up = LATE;
+       slab_state = UP;
 
        /* Annotate slab for lockdep -- annotate the malloc caches */
        init_lock_keys();
 
        /* 6) resize the head arrays to their final sizes */
-       mutex_lock(&cache_chain_mutex);
-       list_for_each_entry(cachep, &cache_chain, next)
+       mutex_lock(&slab_mutex);
+       list_for_each_entry(cachep, &slab_caches, list)
                if (enable_cpucache(cachep, GFP_NOWAIT))
                        BUG();
-       mutex_unlock(&cache_chain_mutex);
+       mutex_unlock(&slab_mutex);
 
        /* Done! */
-       g_cpucache_up = FULL;
+       slab_state = FULL;
 
        /*
         * Register a cpu startup notifier callback that initializes
@@ -1727,6 +1674,9 @@ static int __init cpucache_init(void)
         */
        for_each_online_cpu(cpu)
                start_cpu_timer(cpu);
+
+       /* Done! */
+       slab_state = FULL;
        return 0;
 }
 __initcall(cpucache_init);
@@ -1743,7 +1693,7 @@ slab_out_of_memory(struct kmem_cache *cachep, gfp_t gfpflags, int nodeid)
                "SLAB: Unable to allocate memory on node %d (gfp=0x%x)\n",
                nodeid, gfpflags);
        printk(KERN_WARNING "  cache: %s, object size: %d, order: %d\n",
-               cachep->name, cachep->buffer_size, cachep->gfporder);
+               cachep->name, cachep->size, cachep->gfporder);
 
        for_each_online_node(node) {
                unsigned long active_objs = 0, num_objs = 0, free_objects = 0;
@@ -1798,7 +1748,7 @@ static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid)
        flags |= __GFP_COMP;
 #endif
 
-       flags |= cachep->gfpflags;
+       flags |= cachep->allocflags;
        if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
                flags |= __GFP_RECLAIMABLE;
 
@@ -1874,7 +1824,7 @@ static void kmem_rcu_free(struct rcu_head *head)
 static void store_stackinfo(struct kmem_cache *cachep, unsigned long *addr,
                            unsigned long caller)
 {
-       int size = obj_size(cachep);
+       int size = cachep->object_size;
 
        addr = (unsigned long *)&((char *)addr)[obj_offset(cachep)];
 
@@ -1906,7 +1856,7 @@ static void store_stackinfo(struct kmem_cache *cachep, unsigned long *addr,
 
 static void poison_obj(struct kmem_cache *cachep, void *addr, unsigned char val)
 {
-       int size = obj_size(cachep);
+       int size = cachep->object_size;
        addr = &((char *)addr)[obj_offset(cachep)];
 
        memset(addr, val, size);
@@ -1966,7 +1916,7 @@ static void print_objinfo(struct kmem_cache *cachep, void *objp, int lines)
                printk("\n");
        }
        realobj = (char *)objp + obj_offset(cachep);
-       size = obj_size(cachep);
+       size = cachep->object_size;
        for (i = 0; i < size && lines; i += 16, lines--) {
                int limit;
                limit = 16;
@@ -1983,7 +1933,7 @@ static void check_poison_obj(struct kmem_cache *cachep, void *objp)
        int lines = 0;
 
        realobj = (char *)objp + obj_offset(cachep);
-       size = obj_size(cachep);
+       size = cachep->object_size;
 
        for (i = 0; i < size; i++) {
                char exp = POISON_FREE;
@@ -2047,10 +1997,10 @@ static void slab_destroy_debugcheck(struct kmem_cache *cachep, struct slab *slab
 
                if (cachep->flags & SLAB_POISON) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
-                       if (cachep->buffer_size % PAGE_SIZE == 0 &&
+                       if (cachep->size % PAGE_SIZE == 0 &&
                                        OFF_SLAB(cachep))
                                kernel_map_pages(virt_to_page(objp),
-                                       cachep->buffer_size / PAGE_SIZE, 1);
+                                       cachep->size / PAGE_SIZE, 1);
                        else
                                check_poison_obj(cachep, objp);
 #else
@@ -2194,10 +2144,10 @@ static size_t calculate_slab_order(struct kmem_cache *cachep,
 
 static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
 {
-       if (g_cpucache_up == FULL)
+       if (slab_state >= FULL)
                return enable_cpucache(cachep, gfp);
 
-       if (g_cpucache_up == NONE) {
+       if (slab_state == DOWN) {
                /*
                 * Note: the first kmem_cache_create must create the cache
                 * that's used by kmalloc(24), otherwise the creation of
@@ -2212,16 +2162,16 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
                 */
                set_up_list3s(cachep, SIZE_AC);
                if (INDEX_AC == INDEX_L3)
-                       g_cpucache_up = PARTIAL_L3;
+                       slab_state = PARTIAL_L3;
                else
-                       g_cpucache_up = PARTIAL_AC;
+                       slab_state = PARTIAL_ARRAYCACHE;
        } else {
                cachep->array[smp_processor_id()] =
                        kmalloc(sizeof(struct arraycache_init), gfp);
 
-               if (g_cpucache_up == PARTIAL_AC) {
+               if (slab_state == PARTIAL_ARRAYCACHE) {
                        set_up_list3s(cachep, SIZE_L3);
-                       g_cpucache_up = PARTIAL_L3;
+                       slab_state = PARTIAL_L3;
                } else {
                        int node;
                        for_each_online_node(node) {
@@ -2247,7 +2197,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
 }
 
 /**
- * kmem_cache_create - Create a cache.
+ * __kmem_cache_create - Create a cache.
  * @name: A string which is used in /proc/slabinfo to identify this cache.
  * @size: The size of objects to be created in this cache.
  * @align: The required alignment for the objects.
@@ -2274,59 +2224,14 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
  * as davem.
  */
 struct kmem_cache *
-kmem_cache_create (const char *name, size_t size, size_t align,
+__kmem_cache_create (const char *name, size_t size, size_t align,
        unsigned long flags, void (*ctor)(void *))
 {
        size_t left_over, slab_size, ralign;
-       struct kmem_cache *cachep = NULL, *pc;
+       struct kmem_cache *cachep = NULL;
        gfp_t gfp;
 
-       /*
-        * Sanity checks... these are all serious usage bugs.
-        */
-       if (!name || in_interrupt() || (size < BYTES_PER_WORD) ||
-           size > KMALLOC_MAX_SIZE) {
-               printk(KERN_ERR "%s: Early error in slab %s\n", __func__,
-                               name);
-               BUG();
-       }
-
-       /*
-        * We use cache_chain_mutex to ensure a consistent view of
-        * cpu_online_mask as well.  Please see cpuup_callback
-        */
-       if (slab_is_available()) {
-               get_online_cpus();
-               mutex_lock(&cache_chain_mutex);
-       }
-
-       list_for_each_entry(pc, &cache_chain, next) {
-               char tmp;
-               int res;
-
-               /*
-                * This happens when the module gets unloaded and doesn't
-                * destroy its slab cache and no-one else reuses the vmalloc
-                * area of the module.  Print a warning.
-                */
-               res = probe_kernel_address(pc->name, tmp);
-               if (res) {
-                       printk(KERN_ERR
-                              "SLAB: cache with size %d has lost its name\n",
-                              pc->buffer_size);
-                       continue;
-               }
-
-               if (!strcmp(pc->name, name)) {
-                       printk(KERN_ERR
-                              "kmem_cache_create: duplicate cache %s\n", name);
-                       dump_stack();
-                       goto oops;
-               }
-       }
-
 #if DEBUG
-       WARN_ON(strchr(name, ' '));     /* It confuses parsers */
 #if FORCED_DEBUG
        /*
         * Enable redzoning and last user accounting, except for caches with
@@ -2415,11 +2320,12 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        /* Get cache's description obj. */
        cachep = kmem_cache_zalloc(&cache_cache, gfp);
        if (!cachep)
-               goto oops;
+               return NULL;
 
        cachep->nodelists = (struct kmem_list3 **)&cachep->array[nr_cpu_ids];
+       cachep->object_size = size;
+       cachep->align = align;
 #if DEBUG
-       cachep->obj_size = size;
 
        /*
         * Both debugging options require word-alignment which is calculated
@@ -2442,7 +2348,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        }
 #if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC)
        if (size >= malloc_sizes[INDEX_L3 + 1].cs_size
-           && cachep->obj_size > cache_line_size() && ALIGN(size, align) < PAGE_SIZE) {
+           && cachep->object_size > cache_line_size() && ALIGN(size, align) < PAGE_SIZE) {
                cachep->obj_offset += PAGE_SIZE - ALIGN(size, align);
                size = PAGE_SIZE;
        }
@@ -2471,8 +2377,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
                printk(KERN_ERR
                       "kmem_cache_create: couldn't create cache %s.\n", name);
                kmem_cache_free(&cache_cache, cachep);
-               cachep = NULL;
-               goto oops;
+               return NULL;
        }
        slab_size = ALIGN(cachep->num * sizeof(kmem_bufctl_t)
                          + sizeof(struct slab), align);
@@ -2508,10 +2413,10 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        cachep->colour = left_over / cachep->colour_off;
        cachep->slab_size = slab_size;
        cachep->flags = flags;
-       cachep->gfpflags = 0;
+       cachep->allocflags = 0;
        if (CONFIG_ZONE_DMA_FLAG && (flags & SLAB_CACHE_DMA))
-               cachep->gfpflags |= GFP_DMA;
-       cachep->buffer_size = size;
+               cachep->allocflags |= GFP_DMA;
+       cachep->size = size;
        cachep->reciprocal_buffer_size = reciprocal_value(size);
 
        if (flags & CFLGS_OFF_SLAB) {
@@ -2530,8 +2435,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
 
        if (setup_cpu_cache(cachep, gfp)) {
                __kmem_cache_destroy(cachep);
-               cachep = NULL;
-               goto oops;
+               return NULL;
        }
 
        if (flags & SLAB_DEBUG_OBJECTS) {
@@ -2545,18 +2449,9 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        }
 
        /* cache setup completed, link it into the list */
-       list_add(&cachep->next, &cache_chain);
-oops:
-       if (!cachep && (flags & SLAB_PANIC))
-               panic("kmem_cache_create(): failed to create slab `%s'\n",
-                     name);
-       if (slab_is_available()) {
-               mutex_unlock(&cache_chain_mutex);
-               put_online_cpus();
-       }
+       list_add(&cachep->list, &slab_caches);
        return cachep;
 }
-EXPORT_SYMBOL(kmem_cache_create);
 
 #if DEBUG
 static void check_irq_off(void)
@@ -2671,7 +2566,7 @@ out:
        return nr_freed;
 }
 
-/* Called with cache_chain_mutex held to protect against cpu hotplug */
+/* Called with slab_mutex held to protect against cpu hotplug */
 static int __cache_shrink(struct kmem_cache *cachep)
 {
        int ret = 0, i = 0;
@@ -2706,9 +2601,9 @@ int kmem_cache_shrink(struct kmem_cache *cachep)
        BUG_ON(!cachep || in_interrupt());
 
        get_online_cpus();
-       mutex_lock(&cache_chain_mutex);
+       mutex_lock(&slab_mutex);
        ret = __cache_shrink(cachep);
-       mutex_unlock(&cache_chain_mutex);
+       mutex_unlock(&slab_mutex);
        put_online_cpus();
        return ret;
 }
@@ -2736,15 +2631,15 @@ void kmem_cache_destroy(struct kmem_cache *cachep)
 
        /* Find the cache in the chain of caches. */
        get_online_cpus();
-       mutex_lock(&cache_chain_mutex);
+       mutex_lock(&slab_mutex);
        /*
         * the chain is never empty, cache_cache is never destroyed
         */
-       list_del(&cachep->next);
+       list_del(&cachep->list);
        if (__cache_shrink(cachep)) {
                slab_error(cachep, "Can't free all objects");
-               list_add(&cachep->next, &cache_chain);
-               mutex_unlock(&cache_chain_mutex);
+               list_add(&cachep->list, &slab_caches);
+               mutex_unlock(&slab_mutex);
                put_online_cpus();
                return;
        }
@@ -2753,7 +2648,7 @@ void kmem_cache_destroy(struct kmem_cache *cachep)
                rcu_barrier();
 
        __kmem_cache_destroy(cachep);
-       mutex_unlock(&cache_chain_mutex);
+       mutex_unlock(&slab_mutex);
        put_online_cpus();
 }
 EXPORT_SYMBOL(kmem_cache_destroy);
@@ -2840,10 +2735,10 @@ static void cache_init_objs(struct kmem_cache *cachep,
                                slab_error(cachep, "constructor overwrote the"
                                           " start of an object");
                }
-               if ((cachep->buffer_size % PAGE_SIZE) == 0 &&
+               if ((cachep->size % PAGE_SIZE) == 0 &&
                            OFF_SLAB(cachep) && cachep->flags & SLAB_POISON)
                        kernel_map_pages(virt_to_page(objp),
-                                        cachep->buffer_size / PAGE_SIZE, 0);
+                                        cachep->size / PAGE_SIZE, 0);
 #else
                if (cachep->ctor)
                        cachep->ctor(objp);
@@ -2857,9 +2752,9 @@ static void kmem_flagcheck(struct kmem_cache *cachep, gfp_t flags)
 {
        if (CONFIG_ZONE_DMA_FLAG) {
                if (flags & GFP_DMA)
-                       BUG_ON(!(cachep->gfpflags & GFP_DMA));
+                       BUG_ON(!(cachep->allocflags & GFP_DMA));
                else
-                       BUG_ON(cachep->gfpflags & GFP_DMA);
+                       BUG_ON(cachep->allocflags & GFP_DMA);
        }
 }
 
@@ -2918,8 +2813,8 @@ static void slab_map_pages(struct kmem_cache *cache, struct slab *slab,
                nr_pages <<= cache->gfporder;
 
        do {
-               page_set_cache(page, cache);
-               page_set_slab(page, slab);
+               page->slab_cache = cache;
+               page->slab_page = slab;
                page++;
        } while (--nr_pages);
 }
@@ -3057,7 +2952,7 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
        kfree_debugcheck(objp);
        page = virt_to_head_page(objp);
 
-       slabp = page_get_slab(page);
+       slabp = page->slab_page;
 
        if (cachep->flags & SLAB_RED_ZONE) {
                verify_redzone_free(cachep, objp);
@@ -3077,10 +2972,10 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
 #endif
        if (cachep->flags & SLAB_POISON) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
-               if ((cachep->buffer_size % PAGE_SIZE)==0 && OFF_SLAB(cachep)) {
+               if ((cachep->size % PAGE_SIZE)==0 && OFF_SLAB(cachep)) {
                        store_stackinfo(cachep, objp, (unsigned long)caller);
                        kernel_map_pages(virt_to_page(objp),
-                                        cachep->buffer_size / PAGE_SIZE, 0);
+                                        cachep->size / PAGE_SIZE, 0);
                } else {
                        poison_obj(cachep, objp, POISON_FREE);
                }
@@ -3230,9 +3125,9 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
                return objp;
        if (cachep->flags & SLAB_POISON) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
-               if ((cachep->buffer_size % PAGE_SIZE) == 0 && OFF_SLAB(cachep))
+               if ((cachep->size % PAGE_SIZE) == 0 && OFF_SLAB(cachep))
                        kernel_map_pages(virt_to_page(objp),
-                                        cachep->buffer_size / PAGE_SIZE, 1);
+                                        cachep->size / PAGE_SIZE, 1);
                else
                        check_poison_obj(cachep, objp);
 #else
@@ -3261,8 +3156,8 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
                struct slab *slabp;
                unsigned objnr;
 
-               slabp = page_get_slab(virt_to_head_page(objp));
-               objnr = (unsigned)(objp - slabp->s_mem) / cachep->buffer_size;
+               slabp = virt_to_head_page(objp)->slab_page;
+               objnr = (unsigned)(objp - slabp->s_mem) / cachep->size;
                slab_bufctl(slabp)[objnr] = BUFCTL_ACTIVE;
        }
 #endif
@@ -3285,7 +3180,7 @@ static bool slab_should_failslab(struct kmem_cache *cachep, gfp_t flags)
        if (cachep == &cache_cache)
                return false;
 
-       return should_failslab(obj_size(cachep), flags, cachep->flags);
+       return should_failslab(cachep->object_size, flags, cachep->flags);
 }
 
 static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
@@ -3336,7 +3231,7 @@ static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags)
        if (cpuset_do_slab_mem_spread() && (cachep->flags & SLAB_MEM_SPREAD))
                nid_alloc = cpuset_slab_spread_node();
        else if (current->mempolicy)
-               nid_alloc = slab_node(current->mempolicy);
+               nid_alloc = slab_node();
        if (nid_alloc != nid_here)
                return ____cache_alloc_node(cachep, flags, nid_alloc);
        return NULL;
@@ -3368,7 +3263,7 @@ static void *fallback_alloc(struct kmem_cache *cache, gfp_t flags)
 
 retry_cpuset:
        cpuset_mems_cookie = get_mems_allowed();
-       zonelist = node_zonelist(slab_node(current->mempolicy), flags);
+       zonelist = node_zonelist(slab_node(), flags);
 
 retry:
        /*
@@ -3545,14 +3440,14 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
   out:
        local_irq_restore(save_flags);
        ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, caller);
-       kmemleak_alloc_recursive(ptr, obj_size(cachep), 1, cachep->flags,
+       kmemleak_alloc_recursive(ptr, cachep->object_size, 1, cachep->flags,
                                 flags);
 
        if (likely(ptr))
-               kmemcheck_slab_alloc(cachep, flags, ptr, obj_size(cachep));
+               kmemcheck_slab_alloc(cachep, flags, ptr, cachep->object_size);
 
        if (unlikely((flags & __GFP_ZERO) && ptr))
-               memset(ptr, 0, obj_size(cachep));
+               memset(ptr, 0, cachep->object_size);
 
        return ptr;
 }
@@ -3607,15 +3502,15 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller)
        objp = __do_cache_alloc(cachep, flags);
        local_irq_restore(save_flags);
        objp = cache_alloc_debugcheck_after(cachep, flags, objp, caller);
-       kmemleak_alloc_recursive(objp, obj_size(cachep), 1, cachep->flags,
+       kmemleak_alloc_recursive(objp, cachep->object_size, 1, cachep->flags,
                                 flags);
        prefetchw(objp);
 
        if (likely(objp))
-               kmemcheck_slab_alloc(cachep, flags, objp, obj_size(cachep));
+               kmemcheck_slab_alloc(cachep, flags, objp, cachep->object_size);
 
        if (unlikely((flags & __GFP_ZERO) && objp))
-               memset(objp, 0, obj_size(cachep));
+               memset(objp, 0, cachep->object_size);
 
        return objp;
 }
@@ -3731,7 +3626,7 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp,
        kmemleak_free_recursive(objp, cachep->flags);
        objp = cache_free_debugcheck(cachep, objp, caller);
 
-       kmemcheck_slab_free(cachep, objp, obj_size(cachep));
+       kmemcheck_slab_free(cachep, objp, cachep->object_size);
 
        /*
         * Skip calling cache_free_alien() when the platform is not numa.
@@ -3766,7 +3661,7 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
        void *ret = __cache_alloc(cachep, flags, __builtin_return_address(0));
 
        trace_kmem_cache_alloc(_RET_IP_, ret,
-                              obj_size(cachep), cachep->buffer_size, flags);
+                              cachep->object_size, cachep->size, flags);
 
        return ret;
 }
@@ -3794,7 +3689,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid)
                                       __builtin_return_address(0));
 
        trace_kmem_cache_alloc_node(_RET_IP_, ret,
-                                   obj_size(cachep), cachep->buffer_size,
+                                   cachep->object_size, cachep->size,
                                    flags, nodeid);
 
        return ret;
@@ -3876,7 +3771,7 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
        ret = __cache_alloc(cachep, flags, caller);
 
        trace_kmalloc((unsigned long) caller, ret,
-                     size, cachep->buffer_size, flags);
+                     size, cachep->size, flags);
 
        return ret;
 }
@@ -3916,9 +3811,9 @@ void kmem_cache_free(struct kmem_cache *cachep, void *objp)
        unsigned long flags;
 
        local_irq_save(flags);
-       debug_check_no_locks_freed(objp, obj_size(cachep));
+       debug_check_no_locks_freed(objp, cachep->object_size);
        if (!(cachep->flags & SLAB_DEBUG_OBJECTS))
-               debug_check_no_obj_freed(objp, obj_size(cachep));
+               debug_check_no_obj_freed(objp, cachep->object_size);
        __cache_free(cachep, objp, __builtin_return_address(0));
        local_irq_restore(flags);
 
@@ -3947,8 +3842,9 @@ void kfree(const void *objp)
        local_irq_save(flags);
        kfree_debugcheck(objp);
        c = virt_to_cache(objp);
-       debug_check_no_locks_freed(objp, obj_size(c));
-       debug_check_no_obj_freed(objp, obj_size(c));
+       debug_check_no_locks_freed(objp, c->object_size);
+
+       debug_check_no_obj_freed(objp, c->object_size);
        __cache_free(c, (void *)objp, __builtin_return_address(0));
        local_irq_restore(flags);
 }
@@ -3956,7 +3852,7 @@ EXPORT_SYMBOL(kfree);
 
 unsigned int kmem_cache_size(struct kmem_cache *cachep)
 {
-       return obj_size(cachep);
+       return cachep->object_size;
 }
 EXPORT_SYMBOL(kmem_cache_size);
 
@@ -4030,7 +3926,7 @@ static int alloc_kmemlist(struct kmem_cache *cachep, gfp_t gfp)
        return 0;
 
 fail:
-       if (!cachep->next.next) {
+       if (!cachep->list.next) {
                /* Cache is not active yet. Roll back what we did */
                node--;
                while (node >= 0) {
@@ -4065,7 +3961,7 @@ static void do_ccupdate_local(void *info)
        new->new[smp_processor_id()] = old;
 }
 
-/* Always called with the cache_chain_mutex held */
+/* Always called with the slab_mutex held */
 static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
                                int batchcount, int shared, gfp_t gfp)
 {
@@ -4109,7 +4005,7 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
        return alloc_kmemlist(cachep, gfp);
 }
 
-/* Called with cache_chain_mutex held always */
+/* Called with slab_mutex held always */
 static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp)
 {
        int err;
@@ -4124,13 +4020,13 @@ static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp)
         * The numbers are guessed, we should auto-tune as described by
         * Bonwick.
         */
-       if (cachep->buffer_size > 131072)
+       if (cachep->size > 131072)
                limit = 1;
-       else if (cachep->buffer_size > PAGE_SIZE)
+       else if (cachep->size > PAGE_SIZE)
                limit = 8;
-       else if (cachep->buffer_size > 1024)
+       else if (cachep->size > 1024)
                limit = 24;
-       else if (cachep->buffer_size > 256)
+       else if (cachep->size > 256)
                limit = 54;
        else
                limit = 120;
@@ -4145,7 +4041,7 @@ static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp)
         * to a larger limit. Thus disabled by default.
         */
        shared = 0;
-       if (cachep->buffer_size <= PAGE_SIZE && num_possible_cpus() > 1)
+       if (cachep->size <= PAGE_SIZE && num_possible_cpus() > 1)
                shared = 8;
 
 #if DEBUG
@@ -4211,11 +4107,11 @@ static void cache_reap(struct work_struct *w)
        int node = numa_mem_id();
        struct delayed_work *work = to_delayed_work(w);
 
-       if (!mutex_trylock(&cache_chain_mutex))
+       if (!mutex_trylock(&slab_mutex))
                /* Give up. Setup the next iteration. */
                goto out;
 
-       list_for_each_entry(searchp, &cache_chain, next) {
+       list_for_each_entry(searchp, &slab_caches, list) {
                check_irq_on();
 
                /*
@@ -4253,7 +4149,7 @@ next:
                cond_resched();
        }
        check_irq_on();
-       mutex_unlock(&cache_chain_mutex);
+       mutex_unlock(&slab_mutex);
        next_reap_node();
 out:
        /* Set up the next iteration */
@@ -4289,26 +4185,26 @@ static void *s_start(struct seq_file *m, loff_t *pos)
 {
        loff_t n = *pos;
 
-       mutex_lock(&cache_chain_mutex);
+       mutex_lock(&slab_mutex);
        if (!n)
                print_slabinfo_header(m);
 
-       return seq_list_start(&cache_chain, *pos);
+       return seq_list_start(&slab_caches, *pos);
 }
 
 static void *s_next(struct seq_file *m, void *p, loff_t *pos)
 {
-       return seq_list_next(p, &cache_chain, pos);
+       return seq_list_next(p, &slab_caches, pos);
 }
 
 static void s_stop(struct seq_file *m, void *p)
 {
-       mutex_unlock(&cache_chain_mutex);
+       mutex_unlock(&slab_mutex);
 }
 
 static int s_show(struct seq_file *m, void *p)
 {
-       struct kmem_cache *cachep = list_entry(p, struct kmem_cache, next);
+       struct kmem_cache *cachep = list_entry(p, struct kmem_cache, list);
        struct slab *slabp;
        unsigned long active_objs;
        unsigned long num_objs;
@@ -4364,7 +4260,7 @@ static int s_show(struct seq_file *m, void *p)
                printk(KERN_ERR "slab: cache %s error: %s\n", name, error);
 
        seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d",
-                  name, active_objs, num_objs, cachep->buffer_size,
+                  name, active_objs, num_objs, cachep->size,
                   cachep->num, (1 << cachep->gfporder));
        seq_printf(m, " : tunables %4u %4u %4u",
                   cachep->limit, cachep->batchcount, cachep->shared);
@@ -4454,9 +4350,9 @@ static ssize_t slabinfo_write(struct file *file, const char __user *buffer,
                return -EINVAL;
 
        /* Find the cache in the chain of caches. */
-       mutex_lock(&cache_chain_mutex);
+       mutex_lock(&slab_mutex);
        res = -EINVAL;
-       list_for_each_entry(cachep, &cache_chain, next) {
+       list_for_each_entry(cachep, &slab_caches, list) {
                if (!strcmp(cachep->name, kbuf)) {
                        if (limit < 1 || batchcount < 1 ||
                                        batchcount > limit || shared < 0) {
@@ -4469,7 +4365,7 @@ static ssize_t slabinfo_write(struct file *file, const char __user *buffer,
                        break;
                }
        }
-       mutex_unlock(&cache_chain_mutex);
+       mutex_unlock(&slab_mutex);
        if (res >= 0)
                res = count;
        return res;
@@ -4492,8 +4388,8 @@ static const struct file_operations proc_slabinfo_operations = {
 
 static void *leaks_start(struct seq_file *m, loff_t *pos)
 {
-       mutex_lock(&cache_chain_mutex);
-       return seq_list_start(&cache_chain, *pos);
+       mutex_lock(&slab_mutex);
+       return seq_list_start(&slab_caches, *pos);
 }
 
 static inline int add_caller(unsigned long *n, unsigned long v)
@@ -4532,7 +4428,7 @@ static void handle_slab(unsigned long *n, struct kmem_cache *c, struct slab *s)
        int i;
        if (n[0] == n[1])
                return;
-       for (i = 0, p = s->s_mem; i < c->num; i++, p += c->buffer_size) {
+       for (i = 0, p = s->s_mem; i < c->num; i++, p += c->size) {
                if (slab_bufctl(s)[i] != BUFCTL_ACTIVE)
                        continue;
                if (!add_caller(n, (unsigned long)*dbg_userword(c, p)))
@@ -4558,7 +4454,7 @@ static void show_symbol(struct seq_file *m, unsigned long address)
 
 static int leaks_show(struct seq_file *m, void *p)
 {
-       struct kmem_cache *cachep = list_entry(p, struct kmem_cache, next);
+       struct kmem_cache *cachep = list_entry(p, struct kmem_cache, list);
        struct slab *slabp;
        struct kmem_list3 *l3;
        const char *name;
@@ -4592,17 +4488,17 @@ static int leaks_show(struct seq_file *m, void *p)
        name = cachep->name;
        if (n[0] == n[1]) {
                /* Increase the buffer size */
-               mutex_unlock(&cache_chain_mutex);
+               mutex_unlock(&slab_mutex);
                m->private = kzalloc(n[0] * 4 * sizeof(unsigned long), GFP_KERNEL);
                if (!m->private) {
                        /* Too bad, we are really out */
                        m->private = n;
-                       mutex_lock(&cache_chain_mutex);
+                       mutex_lock(&slab_mutex);
                        return -ENOMEM;
                }
                *(unsigned long *)m->private = n[0] * 2;
                kfree(n);
-               mutex_lock(&cache_chain_mutex);
+               mutex_lock(&slab_mutex);
                /* Now make sure this entry will be retried */
                m->count = m->size;
                return 0;
@@ -4677,6 +4573,6 @@ size_t ksize(const void *objp)
        if (unlikely(objp == ZERO_SIZE_PTR))
                return 0;
 
-       return obj_size(virt_to_cache(objp));
+       return virt_to_cache(objp)->object_size;
 }
 EXPORT_SYMBOL(ksize);
diff --git a/mm/slab.h b/mm/slab.h
new file mode 100644 (file)
index 0000000..db7848c
--- /dev/null
+++ b/mm/slab.h
@@ -0,0 +1,33 @@
+#ifndef MM_SLAB_H
+#define MM_SLAB_H
+/*
+ * Internal slab definitions
+ */
+
+/*
+ * State of the slab allocator.
+ *
+ * This is used to describe the states of the allocator during bootup.
+ * Allocators use this to gradually bootstrap themselves. Most allocators
+ * have the problem that the structures used for managing slab caches are
+ * allocated from slab caches themselves.
+ */
+enum slab_state {
+       DOWN,                   /* No slab functionality yet */
+       PARTIAL,                /* SLUB: kmem_cache_node available */
+       PARTIAL_ARRAYCACHE,     /* SLAB: kmalloc size for arraycache available */
+       PARTIAL_L3,             /* SLAB: kmalloc size for l3 struct available */
+       UP,                     /* Slab caches usable but not all extras yet */
+       FULL                    /* Everything is working */
+};
+
+extern enum slab_state slab_state;
+
+/* The slab cache mutex protects the management structures during changes */
+extern struct mutex slab_mutex;
+extern struct list_head slab_caches;
+
+struct kmem_cache *__kmem_cache_create(const char *name, size_t size,
+       size_t align, unsigned long flags, void (*ctor)(void *));
+
+#endif
diff --git a/mm/slab_common.c b/mm/slab_common.c
new file mode 100644 (file)
index 0000000..aa3ca5b
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Slab allocator functions that are independent of the allocator strategy
+ *
+ * (C) 2012 Christoph Lameter <cl@linux.com>
+ */
+#include <linux/slab.h>
+
+#include <linux/mm.h>
+#include <linux/poison.h>
+#include <linux/interrupt.h>
+#include <linux/memory.h>
+#include <linux/compiler.h>
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/uaccess.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/page.h>
+
+#include "slab.h"
+
+enum slab_state slab_state;
+LIST_HEAD(slab_caches);
+DEFINE_MUTEX(slab_mutex);
+
+/*
+ * kmem_cache_create - Create a cache.
+ * @name: A string which is used in /proc/slabinfo to identify this cache.
+ * @size: The size of objects to be created in this cache.
+ * @align: The required alignment for the objects.
+ * @flags: SLAB flags
+ * @ctor: A constructor for the objects.
+ *
+ * Returns a ptr to the cache on success, NULL on failure.
+ * Cannot be called within a interrupt, but can be interrupted.
+ * The @ctor is run when new pages are allocated by the cache.
+ *
+ * The flags are
+ *
+ * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5)
+ * to catch references to uninitialised memory.
+ *
+ * %SLAB_RED_ZONE - Insert `Red' zones around the allocated memory to check
+ * for buffer overruns.
+ *
+ * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware
+ * cacheline.  This can be beneficial if you're counting cycles as closely
+ * as davem.
+ */
+
+struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,
+               unsigned long flags, void (*ctor)(void *))
+{
+       struct kmem_cache *s = NULL;
+
+#ifdef CONFIG_DEBUG_VM
+       if (!name || in_interrupt() || size < sizeof(void *) ||
+               size > KMALLOC_MAX_SIZE) {
+               printk(KERN_ERR "kmem_cache_create(%s) integrity check"
+                       " failed\n", name);
+               goto out;
+       }
+#endif
+
+       get_online_cpus();
+       mutex_lock(&slab_mutex);
+
+#ifdef CONFIG_DEBUG_VM
+       list_for_each_entry(s, &slab_caches, list) {
+               char tmp;
+               int res;
+
+               /*
+                * This happens when the module gets unloaded and doesn't
+                * destroy its slab cache and no-one else reuses the vmalloc
+                * area of the module.  Print a warning.
+                */
+               res = probe_kernel_address(s->name, tmp);
+               if (res) {
+                       printk(KERN_ERR
+                              "Slab cache with size %d has lost its name\n",
+                              s->object_size);
+                       continue;
+               }
+
+               if (!strcmp(s->name, name)) {
+                       printk(KERN_ERR "kmem_cache_create(%s): Cache name"
+                               " already exists.\n",
+                               name);
+                       dump_stack();
+                       s = NULL;
+                       goto oops;
+               }
+       }
+
+       WARN_ON(strchr(name, ' '));     /* It confuses parsers */
+#endif
+
+       s = __kmem_cache_create(name, size, align, flags, ctor);
+
+#ifdef CONFIG_DEBUG_VM
+oops:
+#endif
+       mutex_unlock(&slab_mutex);
+       put_online_cpus();
+
+#ifdef CONFIG_DEBUG_VM
+out:
+#endif
+       if (!s && (flags & SLAB_PANIC))
+               panic("kmem_cache_create: Failed to create slab '%s'\n", name);
+
+       return s;
+}
+EXPORT_SYMBOL(kmem_cache_create);
+
+int slab_is_available(void)
+{
+       return slab_state >= UP;
+}
index 8105be42cad13b9ba6d231de8fad5bf29af6de2f..45d4ca79933a84eec7e9e824f5d3117f3dc4dc64 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -59,6 +59,8 @@
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include "slab.h"
+
 #include <linux/mm.h>
 #include <linux/swap.h> /* struct reclaim_state */
 #include <linux/cache.h>
@@ -91,36 +93,6 @@ struct slob_block {
 };
 typedef struct slob_block slob_t;
 
-/*
- * We use struct page fields to manage some slob allocation aspects,
- * however to avoid the horrible mess in include/linux/mm_types.h, we'll
- * just define our own struct page type variant here.
- */
-struct slob_page {
-       union {
-               struct {
-                       unsigned long flags;    /* mandatory */
-                       atomic_t _count;        /* mandatory */
-                       slobidx_t units;        /* free units left in page */
-                       unsigned long pad[2];
-                       slob_t *free;           /* first free slob_t in page */
-                       struct list_head list;  /* linked list of free pages */
-               };
-               struct page page;
-       };
-};
-static inline void struct_slob_page_wrong_size(void)
-{ BUILD_BUG_ON(sizeof(struct slob_page) != sizeof(struct page)); }
-
-/*
- * free_slob_page: call before a slob_page is returned to the page allocator.
- */
-static inline void free_slob_page(struct slob_page *sp)
-{
-       reset_page_mapcount(&sp->page);
-       sp->page.mapping = NULL;
-}
-
 /*
  * All partially free slob pages go on these lists.
  */
@@ -130,47 +102,24 @@ static LIST_HEAD(free_slob_small);
 static LIST_HEAD(free_slob_medium);
 static LIST_HEAD(free_slob_large);
 
-/*
- * is_slob_page: True for all slob pages (false for bigblock pages)
- */
-static inline int is_slob_page(struct slob_page *sp)
-{
-       return PageSlab((struct page *)sp);
-}
-
-static inline void set_slob_page(struct slob_page *sp)
-{
-       __SetPageSlab((struct page *)sp);
-}
-
-static inline void clear_slob_page(struct slob_page *sp)
-{
-       __ClearPageSlab((struct page *)sp);
-}
-
-static inline struct slob_page *slob_page(const void *addr)
-{
-       return (struct slob_page *)virt_to_page(addr);
-}
-
 /*
  * slob_page_free: true for pages on free_slob_pages list.
  */
-static inline int slob_page_free(struct slob_page *sp)
+static inline int slob_page_free(struct page *sp)
 {
-       return PageSlobFree((struct page *)sp);
+       return PageSlobFree(sp);
 }
 
-static void set_slob_page_free(struct slob_page *sp, struct list_head *list)
+static void set_slob_page_free(struct page *sp, struct list_head *list)
 {
        list_add(&sp->list, list);
-       __SetPageSlobFree((struct page *)sp);
+       __SetPageSlobFree(sp);
 }
 
-static inline void clear_slob_page_free(struct slob_page *sp)
+static inline void clear_slob_page_free(struct page *sp)
 {
        list_del(&sp->list);
-       __ClearPageSlobFree((struct page *)sp);
+       __ClearPageSlobFree(sp);
 }
 
 #define SLOB_UNIT sizeof(slob_t)
@@ -267,12 +216,12 @@ static void slob_free_pages(void *b, int order)
 /*
  * Allocate a slob block within a given slob_page sp.
  */
-static void *slob_page_alloc(struct slob_page *sp, size_t size, int align)
+static void *slob_page_alloc(struct page *sp, size_t size, int align)
 {
        slob_t *prev, *cur, *aligned = NULL;
        int delta = 0, units = SLOB_UNITS(size);
 
-       for (prev = NULL, cur = sp->free; ; prev = cur, cur = slob_next(cur)) {
+       for (prev = NULL, cur = sp->freelist; ; prev = cur, cur = slob_next(cur)) {
                slobidx_t avail = slob_units(cur);
 
                if (align) {
@@ -296,12 +245,12 @@ static void *slob_page_alloc(struct slob_page *sp, size_t size, int align)
                                if (prev)
                                        set_slob(prev, slob_units(prev), next);
                                else
-                                       sp->free = next;
+                                       sp->freelist = next;
                        } else { /* fragment */
                                if (prev)
                                        set_slob(prev, slob_units(prev), cur + units);
                                else
-                                       sp->free = cur + units;
+                                       sp->freelist = cur + units;
                                set_slob(cur + units, avail - units, next);
                        }
 
@@ -320,7 +269,7 @@ static void *slob_page_alloc(struct slob_page *sp, size_t size, int align)
  */
 static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
 {
-       struct slob_page *sp;
+       struct page *sp;
        struct list_head *prev;
        struct list_head *slob_list;
        slob_t *b = NULL;
@@ -341,7 +290,7 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
                 * If there's a node specification, search for a partial
                 * page with a matching node id in the freelist.
                 */
-               if (node != -1 && page_to_nid(&sp->page) != node)
+               if (node != -1 && page_to_nid(sp) != node)
                        continue;
 #endif
                /* Enough room on this page? */
@@ -369,12 +318,12 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
                b = slob_new_pages(gfp & ~__GFP_ZERO, 0, node);
                if (!b)
                        return NULL;
-               sp = slob_page(b);
-               set_slob_page(sp);
+               sp = virt_to_page(b);
+               __SetPageSlab(sp);
 
                spin_lock_irqsave(&slob_lock, flags);
                sp->units = SLOB_UNITS(PAGE_SIZE);
-               sp->free = b;
+               sp->freelist = b;
                INIT_LIST_HEAD(&sp->list);
                set_slob(b, SLOB_UNITS(PAGE_SIZE), b + SLOB_UNITS(PAGE_SIZE));
                set_slob_page_free(sp, slob_list);
@@ -392,7 +341,7 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
  */
 static void slob_free(void *block, int size)
 {
-       struct slob_page *sp;
+       struct page *sp;
        slob_t *prev, *next, *b = (slob_t *)block;
        slobidx_t units;
        unsigned long flags;
@@ -402,7 +351,7 @@ static void slob_free(void *block, int size)
                return;
        BUG_ON(!size);
 
-       sp = slob_page(block);
+       sp = virt_to_page(block);
        units = SLOB_UNITS(size);
 
        spin_lock_irqsave(&slob_lock, flags);
@@ -412,8 +361,8 @@ static void slob_free(void *block, int size)
                if (slob_page_free(sp))
                        clear_slob_page_free(sp);
                spin_unlock_irqrestore(&slob_lock, flags);
-               clear_slob_page(sp);
-               free_slob_page(sp);
+               __ClearPageSlab(sp);
+               reset_page_mapcount(sp);
                slob_free_pages(b, 0);
                return;
        }
@@ -421,7 +370,7 @@ static void slob_free(void *block, int size)
        if (!slob_page_free(sp)) {
                /* This slob page is about to become partially free. Easy! */
                sp->units = units;
-               sp->free = b;
+               sp->freelist = b;
                set_slob(b, units,
                        (void *)((unsigned long)(b +
                                        SLOB_UNITS(PAGE_SIZE)) & PAGE_MASK));
@@ -441,15 +390,15 @@ static void slob_free(void *block, int size)
         */
        sp->units += units;
 
-       if (b < sp->free) {
-               if (b + units == sp->free) {
-                       units += slob_units(sp->free);
-                       sp->free = slob_next(sp->free);
+       if (b < (slob_t *)sp->freelist) {
+               if (b + units == sp->freelist) {
+                       units += slob_units(sp->freelist);
+                       sp->freelist = slob_next(sp->freelist);
                }
-               set_slob(b, units, sp->free);
-               sp->free = b;
+               set_slob(b, units, sp->freelist);
+               sp->freelist = b;
        } else {
-               prev = sp->free;
+               prev = sp->freelist;
                next = slob_next(prev);
                while (b > next) {
                        prev = next;
@@ -522,7 +471,7 @@ EXPORT_SYMBOL(__kmalloc_node);
 
 void kfree(const void *block)
 {
-       struct slob_page *sp;
+       struct page *sp;
 
        trace_kfree(_RET_IP_, block);
 
@@ -530,43 +479,36 @@ void kfree(const void *block)
                return;
        kmemleak_free(block);
 
-       sp = slob_page(block);
-       if (is_slob_page(sp)) {
+       sp = virt_to_page(block);
+       if (PageSlab(sp)) {
                int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
                unsigned int *m = (unsigned int *)(block - align);
                slob_free(m, *m + align);
        } else
-               put_page(&sp->page);
+               put_page(sp);
 }
 EXPORT_SYMBOL(kfree);
 
 /* can't use ksize for kmem_cache_alloc memory, only kmalloc */
 size_t ksize(const void *block)
 {
-       struct slob_page *sp;
+       struct page *sp;
 
        BUG_ON(!block);
        if (unlikely(block == ZERO_SIZE_PTR))
                return 0;
 
-       sp = slob_page(block);
-       if (is_slob_page(sp)) {
+       sp = virt_to_page(block);
+       if (PageSlab(sp)) {
                int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
                unsigned int *m = (unsigned int *)(block - align);
                return SLOB_UNITS(*m) * SLOB_UNIT;
        } else
-               return sp->page.private;
+               return sp->private;
 }
 EXPORT_SYMBOL(ksize);
 
-struct kmem_cache {
-       unsigned int size, align;
-       unsigned long flags;
-       const char *name;
-       void (*ctor)(void *);
-};
-
-struct kmem_cache *kmem_cache_create(const char *name, size_t size,
+struct kmem_cache *__kmem_cache_create(const char *name, size_t size,
        size_t align, unsigned long flags, void (*ctor)(void *))
 {
        struct kmem_cache *c;
@@ -589,13 +531,12 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
                        c->align = ARCH_SLAB_MINALIGN;
                if (c->align < align)
                        c->align = align;
-       } else if (flags & SLAB_PANIC)
-               panic("Cannot create slab cache %s\n", name);
 
-       kmemleak_alloc(c, sizeof(struct kmem_cache), 1, GFP_KERNEL);
+               kmemleak_alloc(c, sizeof(struct kmem_cache), 1, GFP_KERNEL);
+               c->refcount = 1;
+       }
        return c;
 }
-EXPORT_SYMBOL(kmem_cache_create);
 
 void kmem_cache_destroy(struct kmem_cache *c)
 {
@@ -678,19 +619,12 @@ int kmem_cache_shrink(struct kmem_cache *d)
 }
 EXPORT_SYMBOL(kmem_cache_shrink);
 
-static unsigned int slob_ready __read_mostly;
-
-int slab_is_available(void)
-{
-       return slob_ready;
-}
-
 void __init kmem_cache_init(void)
 {
-       slob_ready = 1;
+       slab_state = UP;
 }
 
 void __init kmem_cache_init_late(void)
 {
-       /* Nothing to do */
+       slab_state = FULL;
 }
index 8c691fa1cf3c78a91fa301bcd0cd323df1b28a1e..e517d435e5dca65394754c3f1212864e8fe24c58 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
+#include "slab.h"
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/kmemcheck.h>
 
 /*
  * Lock order:
- *   1. slub_lock (Global Semaphore)
+ *   1. slab_mutex (Global Mutex)
  *   2. node->list_lock
  *   3. slab_lock(page) (Only on some arches and for debugging)
  *
- *   slub_lock
+ *   slab_mutex
  *
- *   The role of the slub_lock is to protect the list of all the slabs
+ *   The role of the slab_mutex is to protect the list of all the slabs
  *   and to synchronize major metadata changes to slab cache structures.
  *
  *   The slab_lock is only used for debugging and on arches that do not
@@ -182,17 +183,6 @@ static int kmem_size = sizeof(struct kmem_cache);
 static struct notifier_block slab_notifier;
 #endif
 
-static enum {
-       DOWN,           /* No slab functionality available */
-       PARTIAL,        /* Kmem_cache_node works */
-       UP,             /* Everything works but does not show up in sysfs */
-       SYSFS           /* Sysfs up */
-} slab_state = DOWN;
-
-/* A list of all slab caches on the system */
-static DECLARE_RWSEM(slub_lock);
-static LIST_HEAD(slab_caches);
-
 /*
  * Tracking user of a slab.
  */
@@ -237,11 +227,6 @@ static inline void stat(const struct kmem_cache *s, enum stat_item si)
  *                     Core slab cache functions
  *******************************************************************/
 
-int slab_is_available(void)
-{
-       return slab_state >= UP;
-}
-
 static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node)
 {
        return s->node[node];
@@ -311,7 +296,7 @@ static inline size_t slab_ksize(const struct kmem_cache *s)
         * and whatever may come after it.
         */
        if (s->flags & (SLAB_RED_ZONE | SLAB_POISON))
-               return s->objsize;
+               return s->object_size;
 
 #endif
        /*
@@ -609,11 +594,11 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
        if (p > addr + 16)
                print_section("Bytes b4 ", p - 16, 16);
 
-       print_section("Object ", p, min_t(unsigned long, s->objsize,
+       print_section("Object ", p, min_t(unsigned long, s->object_size,
                                PAGE_SIZE));
        if (s->flags & SLAB_RED_ZONE)
-               print_section("Redzone ", p + s->objsize,
-                       s->inuse - s->objsize);
+               print_section("Redzone ", p + s->object_size,
+                       s->inuse - s->object_size);
 
        if (s->offset)
                off = s->offset + sizeof(void *);
@@ -655,12 +640,12 @@ static void init_object(struct kmem_cache *s, void *object, u8 val)
        u8 *p = object;
 
        if (s->flags & __OBJECT_POISON) {
-               memset(p, POISON_FREE, s->objsize - 1);
-               p[s->objsize - 1] = POISON_END;
+               memset(p, POISON_FREE, s->object_size - 1);
+               p[s->object_size - 1] = POISON_END;
        }
 
        if (s->flags & SLAB_RED_ZONE)
-               memset(p + s->objsize, val, s->inuse - s->objsize);
+               memset(p + s->object_size, val, s->inuse - s->object_size);
 }
 
 static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
@@ -705,10 +690,10 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
  *     Poisoning uses 0x6b (POISON_FREE) and the last byte is
  *     0xa5 (POISON_END)
  *
- * object + s->objsize
+ * object + s->object_size
  *     Padding to reach word boundary. This is also used for Redzoning.
  *     Padding is extended by another word if Redzoning is enabled and
- *     objsize == inuse.
+ *     object_size == inuse.
  *
  *     We fill with 0xbb (RED_INACTIVE) for inactive objects and with
  *     0xcc (RED_ACTIVE) for objects in use.
@@ -727,7 +712,7 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
  * object + s->size
  *     Nothing is used beyond s->size.
  *
- * If slabcaches are merged then the objsize and inuse boundaries are mostly
+ * If slabcaches are merged then the object_size and inuse boundaries are mostly
  * ignored. And therefore no slab options that rely on these boundaries
  * may be used with merged slabcaches.
  */
@@ -787,25 +772,25 @@ static int check_object(struct kmem_cache *s, struct page *page,
                                        void *object, u8 val)
 {
        u8 *p = object;
-       u8 *endobject = object + s->objsize;
+       u8 *endobject = object + s->object_size;
 
        if (s->flags & SLAB_RED_ZONE) {
                if (!check_bytes_and_report(s, page, object, "Redzone",
-                       endobject, val, s->inuse - s->objsize))
+                       endobject, val, s->inuse - s->object_size))
                        return 0;
        } else {
-               if ((s->flags & SLAB_POISON) && s->objsize < s->inuse) {
+               if ((s->flags & SLAB_POISON) && s->object_size < s->inuse) {
                        check_bytes_and_report(s, page, p, "Alignment padding",
-                               endobject, POISON_INUSE, s->inuse - s->objsize);
+                               endobject, POISON_INUSE, s->inuse - s->object_size);
                }
        }
 
        if (s->flags & SLAB_POISON) {
                if (val != SLUB_RED_ACTIVE && (s->flags & __OBJECT_POISON) &&
                        (!check_bytes_and_report(s, page, p, "Poison", p,
-                                       POISON_FREE, s->objsize - 1) ||
+                                       POISON_FREE, s->object_size - 1) ||
                         !check_bytes_and_report(s, page, p, "Poison",
-                               p + s->objsize - 1, POISON_END, 1)))
+                               p + s->object_size - 1, POISON_END, 1)))
                        return 0;
                /*
                 * check_pad_bytes cleans up on its own.
@@ -926,7 +911,7 @@ static void trace(struct kmem_cache *s, struct page *page, void *object,
                        page->freelist);
 
                if (!alloc)
-                       print_section("Object ", (void *)object, s->objsize);
+                       print_section("Object ", (void *)object, s->object_size);
 
                dump_stack();
        }
@@ -942,14 +927,14 @@ static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
        lockdep_trace_alloc(flags);
        might_sleep_if(flags & __GFP_WAIT);
 
-       return should_failslab(s->objsize, flags, s->flags);
+       return should_failslab(s->object_size, flags, s->flags);
 }
 
 static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags, void *object)
 {
        flags &= gfp_allowed_mask;
        kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
-       kmemleak_alloc_recursive(object, s->objsize, 1, s->flags, flags);
+       kmemleak_alloc_recursive(object, s->object_size, 1, s->flags, flags);
 }
 
 static inline void slab_free_hook(struct kmem_cache *s, void *x)
@@ -966,13 +951,13 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x)
                unsigned long flags;
 
                local_irq_save(flags);
-               kmemcheck_slab_free(s, x, s->objsize);
-               debug_check_no_locks_freed(x, s->objsize);
+               kmemcheck_slab_free(s, x, s->object_size);
+               debug_check_no_locks_freed(x, s->object_size);
                local_irq_restore(flags);
        }
 #endif
        if (!(s->flags & SLAB_DEBUG_OBJECTS))
-               debug_check_no_obj_freed(x, s->objsize);
+               debug_check_no_obj_freed(x, s->object_size);
 }
 
 /*
@@ -1207,7 +1192,7 @@ out:
 
 __setup("slub_debug", setup_slub_debug);
 
-static unsigned long kmem_cache_flags(unsigned long objsize,
+static unsigned long kmem_cache_flags(unsigned long object_size,
        unsigned long flags, const char *name,
        void (*ctor)(void *))
 {
@@ -1237,7 +1222,7 @@ static inline int check_object(struct kmem_cache *s, struct page *page,
 static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n,
                                        struct page *page) {}
 static inline void remove_full(struct kmem_cache *s, struct page *page) {}
-static inline unsigned long kmem_cache_flags(unsigned long objsize,
+static inline unsigned long kmem_cache_flags(unsigned long object_size,
        unsigned long flags, const char *name,
        void (*ctor)(void *))
 {
@@ -1314,13 +1299,7 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
                        stat(s, ORDER_FALLBACK);
        }
 
-       if (flags & __GFP_WAIT)
-               local_irq_disable();
-
-       if (!page)
-               return NULL;
-
-       if (kmemcheck_enabled
+       if (kmemcheck_enabled && page
                && !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) {
                int pages = 1 << oo_order(oo);
 
@@ -1336,6 +1315,11 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
                        kmemcheck_mark_unallocated_pages(page, pages);
        }
 
+       if (flags & __GFP_WAIT)
+               local_irq_disable();
+       if (!page)
+               return NULL;
+
        page->objects = oo_objects(oo);
        mod_zone_page_state(page_zone(page),
                (s->flags & SLAB_RECLAIM_ACCOUNT) ?
@@ -1490,12 +1474,12 @@ static inline void remove_partial(struct kmem_cache_node *n,
 }
 
 /*
- * Lock slab, remove from the partial list and put the object into the
- * per cpu freelist.
+ * Remove slab from the partial list, freeze it and
+ * return the pointer to the freelist.
  *
  * Returns a list of objects or NULL if it fails.
  *
- * Must hold list_lock.
+ * Must hold list_lock since we modify the partial list.
  */
 static inline void *acquire_slab(struct kmem_cache *s,
                struct kmem_cache_node *n, struct page *page,
@@ -1510,26 +1494,27 @@ static inline void *acquire_slab(struct kmem_cache *s,
         * The old freelist is the list of objects for the
         * per cpu allocation list.
         */
-       do {
-               freelist = page->freelist;
-               counters = page->counters;
-               new.counters = counters;
-               if (mode) {
-                       new.inuse = page->objects;
-                       new.freelist = NULL;
-               } else {
-                       new.freelist = freelist;
-               }
+       freelist = page->freelist;
+       counters = page->counters;
+       new.counters = counters;
+       if (mode) {
+               new.inuse = page->objects;
+               new.freelist = NULL;
+       } else {
+               new.freelist = freelist;
+       }
 
-               VM_BUG_ON(new.frozen);
-               new.frozen = 1;
+       VM_BUG_ON(new.frozen);
+       new.frozen = 1;
 
-       } while (!__cmpxchg_double_slab(s, page,
+       if (!__cmpxchg_double_slab(s, page,
                        freelist, counters,
                        new.freelist, new.counters,
-                       "lock and freeze"));
+                       "acquire_slab"))
+               return NULL;
 
        remove_partial(n, page);
+       WARN_ON(!freelist);
        return freelist;
 }
 
@@ -1563,7 +1548,6 @@ static void *get_partial_node(struct kmem_cache *s,
 
                if (!object) {
                        c->page = page;
-                       c->node = page_to_nid(page);
                        stat(s, ALLOC_FROM_PARTIAL);
                        object = t;
                        available =  page->objects - page->inuse;
@@ -1617,7 +1601,7 @@ static void *get_any_partial(struct kmem_cache *s, gfp_t flags,
 
        do {
                cpuset_mems_cookie = get_mems_allowed();
-               zonelist = node_zonelist(slab_node(current->mempolicy), flags);
+               zonelist = node_zonelist(slab_node(), flags);
                for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
                        struct kmem_cache_node *n;
 
@@ -1731,14 +1715,12 @@ void init_kmem_cache_cpus(struct kmem_cache *s)
 /*
  * Remove the cpu slab
  */
-static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
+static void deactivate_slab(struct kmem_cache *s, struct page *page, void *freelist)
 {
        enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
-       struct page *page = c->page;
        struct kmem_cache_node *n = get_node(s, page_to_nid(page));
        int lock = 0;
        enum slab_modes l = M_NONE, m = M_NONE;
-       void *freelist;
        void *nextfree;
        int tail = DEACTIVATE_TO_HEAD;
        struct page new;
@@ -1749,11 +1731,6 @@ static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
                tail = DEACTIVATE_TO_TAIL;
        }
 
-       c->tid = next_tid(c->tid);
-       c->page = NULL;
-       freelist = c->freelist;
-       c->freelist = NULL;
-
        /*
         * Stage one: Free all available per cpu objects back
         * to the page freelist while it is still frozen. Leave the
@@ -1879,21 +1856,31 @@ redo:
        }
 }
 
-/* Unfreeze all the cpu partial slabs */
+/*
+ * Unfreeze all the cpu partial slabs.
+ *
+ * This function must be called with interrupt disabled.
+ */
 static void unfreeze_partials(struct kmem_cache *s)
 {
-       struct kmem_cache_node *n = NULL;
+       struct kmem_cache_node *n = NULL, *n2 = NULL;
        struct kmem_cache_cpu *c = this_cpu_ptr(s->cpu_slab);
        struct page *page, *discard_page = NULL;
 
        while ((page = c->partial)) {
-               enum slab_modes { M_PARTIAL, M_FREE };
-               enum slab_modes l, m;
                struct page new;
                struct page old;
 
                c->partial = page->next;
-               l = M_FREE;
+
+               n2 = get_node(s, page_to_nid(page));
+               if (n != n2) {
+                       if (n)
+                               spin_unlock(&n->list_lock);
+
+                       n = n2;
+                       spin_lock(&n->list_lock);
+               }
 
                do {
 
@@ -1906,43 +1893,17 @@ static void unfreeze_partials(struct kmem_cache *s)
 
                        new.frozen = 0;
 
-                       if (!new.inuse && (!n || n->nr_partial > s->min_partial))
-                               m = M_FREE;
-                       else {
-                               struct kmem_cache_node *n2 = get_node(s,
-                                                       page_to_nid(page));
-
-                               m = M_PARTIAL;
-                               if (n != n2) {
-                                       if (n)
-                                               spin_unlock(&n->list_lock);
-
-                                       n = n2;
-                                       spin_lock(&n->list_lock);
-                               }
-                       }
-
-                       if (l != m) {
-                               if (l == M_PARTIAL) {
-                                       remove_partial(n, page);
-                                       stat(s, FREE_REMOVE_PARTIAL);
-                               } else {
-                                       add_partial(n, page,
-                                               DEACTIVATE_TO_TAIL);
-                                       stat(s, FREE_ADD_PARTIAL);
-                               }
-
-                               l = m;
-                       }
-
-               } while (!cmpxchg_double_slab(s, page,
+               } while (!__cmpxchg_double_slab(s, page,
                                old.freelist, old.counters,
                                new.freelist, new.counters,
                                "unfreezing slab"));
 
-               if (m == M_FREE) {
+               if (unlikely(!new.inuse && n->nr_partial > s->min_partial)) {
                        page->next = discard_page;
                        discard_page = page;
+               } else {
+                       add_partial(n, page, DEACTIVATE_TO_TAIL);
+                       stat(s, FREE_ADD_PARTIAL);
                }
        }
 
@@ -2011,7 +1972,11 @@ int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
 static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
 {
        stat(s, CPUSLAB_FLUSH);
-       deactivate_slab(s, c);
+       deactivate_slab(s, c->page, c->freelist);
+
+       c->tid = next_tid(c->tid);
+       c->page = NULL;
+       c->freelist = NULL;
 }
 
 /*
@@ -2055,10 +2020,10 @@ static void flush_all(struct kmem_cache *s)
  * Check if the objects in a per cpu structure fit numa
  * locality expectations.
  */
-static inline int node_match(struct kmem_cache_cpu *c, int node)
+static inline int node_match(struct page *page, int node)
 {
 #ifdef CONFIG_NUMA
-       if (node != NUMA_NO_NODE && c->node != node)
+       if (node != NUMA_NO_NODE && page_to_nid(page) != node)
                return 0;
 #endif
        return 1;
@@ -2101,10 +2066,10 @@ slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
                "SLUB: Unable to allocate memory on node %d (gfp=0x%x)\n",
                nid, gfpflags);
        printk(KERN_WARNING "  cache: %s, object size: %d, buffer size: %d, "
-               "default order: %d, min order: %d\n", s->name, s->objsize,
+               "default order: %d, min order: %d\n", s->name, s->object_size,
                s->size, oo_order(s->oo), oo_order(s->min));
 
-       if (oo_order(s->min) > get_order(s->objsize))
+       if (oo_order(s->min) > get_order(s->object_size))
                printk(KERN_WARNING "  %s debugging increased min order, use "
                       "slub_debug=O to disable.\n", s->name);
 
@@ -2130,10 +2095,16 @@ slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
 static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
                        int node, struct kmem_cache_cpu **pc)
 {
-       void *object;
-       struct kmem_cache_cpu *c;
-       struct page *page = new_slab(s, flags, node);
+       void *freelist;
+       struct kmem_cache_cpu *c = *pc;
+       struct page *page;
+
+       freelist = get_partial(s, flags, node, c);
 
+       if (freelist)
+               return freelist;
+
+       page = new_slab(s, flags, node);
        if (page) {
                c = __this_cpu_ptr(s->cpu_slab);
                if (c->page)
@@ -2143,17 +2114,16 @@ static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
                 * No other reference to the page yet so we can
                 * muck around with it freely without cmpxchg
                 */
-               object = page->freelist;
+               freelist = page->freelist;
                page->freelist = NULL;
 
                stat(s, ALLOC_SLAB);
-               c->node = page_to_nid(page);
                c->page = page;
                *pc = c;
        } else
-               object = NULL;
+               freelist = NULL;
 
-       return object;
+       return freelist;
 }
 
 /*
@@ -2163,6 +2133,8 @@ static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
  * The page is still frozen if the return value is not NULL.
  *
  * If this function returns NULL then the page has been unfrozen.
+ *
+ * This function must be called with interrupt disabled.
  */
 static inline void *get_freelist(struct kmem_cache *s, struct page *page)
 {
@@ -2173,13 +2145,14 @@ static inline void *get_freelist(struct kmem_cache *s, struct page *page)
        do {
                freelist = page->freelist;
                counters = page->counters;
+
                new.counters = counters;
                VM_BUG_ON(!new.frozen);
 
                new.inuse = page->objects;
                new.frozen = freelist != NULL;
 
-       } while (!cmpxchg_double_slab(s, page,
+       } while (!__cmpxchg_double_slab(s, page,
                freelist, counters,
                NULL, new.counters,
                "get_freelist"));
@@ -2206,7 +2179,8 @@ static inline void *get_freelist(struct kmem_cache *s, struct page *page)
 static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
                          unsigned long addr, struct kmem_cache_cpu *c)
 {
-       void **object;
+       void *freelist;
+       struct page *page;
        unsigned long flags;
 
        local_irq_save(flags);
@@ -2219,25 +2193,29 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
        c = this_cpu_ptr(s->cpu_slab);
 #endif
 
-       if (!c->page)
+       page = c->page;
+       if (!page)
                goto new_slab;
 redo:
-       if (unlikely(!node_match(c, node))) {
+
+       if (unlikely(!node_match(page, node))) {
                stat(s, ALLOC_NODE_MISMATCH);
-               deactivate_slab(s, c);
+               deactivate_slab(s, page, c->freelist);
+               c->page = NULL;
+               c->freelist = NULL;
                goto new_slab;
        }
 
        /* must check again c->freelist in case of cpu migration or IRQ */
-       object = c->freelist;
-       if (object)
+       freelist = c->freelist;
+       if (freelist)
                goto load_freelist;
 
        stat(s, ALLOC_SLOWPATH);
 
-       object = get_freelist(s, c->page);
+       freelist = get_freelist(s, page);
 
-       if (!object) {
+       if (!freelist) {
                c->page = NULL;
                stat(s, DEACTIVATE_BYPASS);
                goto new_slab;
@@ -2246,50 +2224,50 @@ redo:
        stat(s, ALLOC_REFILL);
 
 load_freelist:
-       c->freelist = get_freepointer(s, object);
+       /*
+        * freelist is pointing to the list of objects to be used.
+        * page is pointing to the page from which the objects are obtained.
+        * That page must be frozen for per cpu allocations to work.
+        */
+       VM_BUG_ON(!c->page->frozen);
+       c->freelist = get_freepointer(s, freelist);
        c->tid = next_tid(c->tid);
        local_irq_restore(flags);
-       return object;
+       return freelist;
 
 new_slab:
 
        if (c->partial) {
-               c->page = c->partial;
-               c->partial = c->page->next;
-               c->node = page_to_nid(c->page);
+               page = c->page = c->partial;
+               c->partial = page->next;
                stat(s, CPU_PARTIAL_ALLOC);
                c->freelist = NULL;
                goto redo;
        }
 
-       /* Then do expensive stuff like retrieving pages from the partial lists */
-       object = get_partial(s, gfpflags, node, c);
+       freelist = new_slab_objects(s, gfpflags, node, &c);
 
-       if (unlikely(!object)) {
+       if (unlikely(!freelist)) {
+               if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit())
+                       slab_out_of_memory(s, gfpflags, node);
 
-               object = new_slab_objects(s, gfpflags, node, &c);
-
-               if (unlikely(!object)) {
-                       if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit())
-                               slab_out_of_memory(s, gfpflags, node);
-
-                       local_irq_restore(flags);
-                       return NULL;
-               }
+               local_irq_restore(flags);
+               return NULL;
        }
 
+       page = c->page;
        if (likely(!kmem_cache_debug(s)))
                goto load_freelist;
 
        /* Only entered in the debug case */
-       if (!alloc_debug_processing(s, c->page, object, addr))
+       if (!alloc_debug_processing(s, page, freelist, addr))
                goto new_slab;  /* Slab failed checks. Next slab needed */
 
-       c->freelist = get_freepointer(s, object);
-       deactivate_slab(s, c);
-       c->node = NUMA_NO_NODE;
+       deactivate_slab(s, page, get_freepointer(s, freelist));
+       c->page = NULL;
+       c->freelist = NULL;
        local_irq_restore(flags);
-       return object;
+       return freelist;
 }
 
 /*
@@ -2307,6 +2285,7 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
 {
        void **object;
        struct kmem_cache_cpu *c;
+       struct page *page;
        unsigned long tid;
 
        if (slab_pre_alloc_hook(s, gfpflags))
@@ -2332,7 +2311,8 @@ redo:
        barrier();
 
        object = c->freelist;
-       if (unlikely(!object || !node_match(c, node)))
+       page = c->page;
+       if (unlikely(!object || !node_match(page, node)))
 
                object = __slab_alloc(s, gfpflags, node, addr, c);
 
@@ -2364,7 +2344,7 @@ redo:
        }
 
        if (unlikely(gfpflags & __GFP_ZERO) && object)
-               memset(object, 0, s->objsize);
+               memset(object, 0, s->object_size);
 
        slab_post_alloc_hook(s, gfpflags, object);
 
@@ -2375,7 +2355,7 @@ void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
 {
        void *ret = slab_alloc(s, gfpflags, NUMA_NO_NODE, _RET_IP_);
 
-       trace_kmem_cache_alloc(_RET_IP_, ret, s->objsize, s->size, gfpflags);
+       trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size, s->size, gfpflags);
 
        return ret;
 }
@@ -2405,7 +2385,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
        void *ret = slab_alloc(s, gfpflags, node, _RET_IP_);
 
        trace_kmem_cache_alloc_node(_RET_IP_, ret,
-                                   s->objsize, s->size, gfpflags, node);
+                                   s->object_size, s->size, gfpflags, node);
 
        return ret;
 }
@@ -2900,7 +2880,7 @@ static void set_min_partial(struct kmem_cache *s, unsigned long min)
 static int calculate_sizes(struct kmem_cache *s, int forced_order)
 {
        unsigned long flags = s->flags;
-       unsigned long size = s->objsize;
+       unsigned long size = s->object_size;
        unsigned long align = s->align;
        int order;
 
@@ -2929,7 +2909,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
         * end of the object and the free pointer. If not then add an
         * additional word to have some bytes to store Redzone information.
         */
-       if ((flags & SLAB_RED_ZONE) && size == s->objsize)
+       if ((flags & SLAB_RED_ZONE) && size == s->object_size)
                size += sizeof(void *);
 #endif
 
@@ -2977,7 +2957,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
         * user specified and the dynamic determination of cache line size
         * on bootup.
         */
-       align = calculate_alignment(flags, align, s->objsize);
+       align = calculate_alignment(flags, align, s->object_size);
        s->align = align;
 
        /*
@@ -3025,7 +3005,7 @@ static int kmem_cache_open(struct kmem_cache *s,
        memset(s, 0, kmem_size);
        s->name = name;
        s->ctor = ctor;
-       s->objsize = size;
+       s->object_size = size;
        s->align = align;
        s->flags = kmem_cache_flags(size, flags, name, ctor);
        s->reserved = 0;
@@ -3040,7 +3020,7 @@ static int kmem_cache_open(struct kmem_cache *s,
                 * Disable debugging flags that store metadata if the min slab
                 * order increased.
                 */
-               if (get_order(s->size) > get_order(s->objsize)) {
+               if (get_order(s->size) > get_order(s->object_size)) {
                        s->flags &= ~DEBUG_METADATA_FLAGS;
                        s->offset = 0;
                        if (!calculate_sizes(s, -1))
@@ -3114,7 +3094,7 @@ error:
  */
 unsigned int kmem_cache_size(struct kmem_cache *s)
 {
-       return s->objsize;
+       return s->object_size;
 }
 EXPORT_SYMBOL(kmem_cache_size);
 
@@ -3192,11 +3172,11 @@ static inline int kmem_cache_close(struct kmem_cache *s)
  */
 void kmem_cache_destroy(struct kmem_cache *s)
 {
-       down_write(&slub_lock);
+       mutex_lock(&slab_mutex);
        s->refcount--;
        if (!s->refcount) {
                list_del(&s->list);
-               up_write(&slub_lock);
+               mutex_unlock(&slab_mutex);
                if (kmem_cache_close(s)) {
                        printk(KERN_ERR "SLUB %s: %s called for cache that "
                                "still has objects.\n", s->name, __func__);
@@ -3206,7 +3186,7 @@ void kmem_cache_destroy(struct kmem_cache *s)
                        rcu_barrier();
                sysfs_slab_remove(s);
        } else
-               up_write(&slub_lock);
+               mutex_unlock(&slab_mutex);
 }
 EXPORT_SYMBOL(kmem_cache_destroy);
 
@@ -3268,7 +3248,7 @@ static struct kmem_cache *__init create_kmalloc_cache(const char *name,
 
        /*
         * This function is called with IRQs disabled during early-boot on
-        * single CPU so there's no need to take slub_lock here.
+        * single CPU so there's no need to take slab_mutex here.
         */
        if (!kmem_cache_open(s, name, size, ARCH_KMALLOC_MINALIGN,
                                                                flags, NULL))
@@ -3553,10 +3533,10 @@ static int slab_mem_going_offline_callback(void *arg)
 {
        struct kmem_cache *s;
 
-       down_read(&slub_lock);
+       mutex_lock(&slab_mutex);
        list_for_each_entry(s, &slab_caches, list)
                kmem_cache_shrink(s);
-       up_read(&slub_lock);
+       mutex_unlock(&slab_mutex);
 
        return 0;
 }
@@ -3577,7 +3557,7 @@ static void slab_mem_offline_callback(void *arg)
        if (offline_node < 0)
                return;
 
-       down_read(&slub_lock);
+       mutex_lock(&slab_mutex);
        list_for_each_entry(s, &slab_caches, list) {
                n = get_node(s, offline_node);
                if (n) {
@@ -3593,7 +3573,7 @@ static void slab_mem_offline_callback(void *arg)
                        kmem_cache_free(kmem_cache_node, n);
                }
        }
-       up_read(&slub_lock);
+       mutex_unlock(&slab_mutex);
 }
 
 static int slab_mem_going_online_callback(void *arg)
@@ -3616,7 +3596,7 @@ static int slab_mem_going_online_callback(void *arg)
         * allocate a kmem_cache_node structure in order to bring the node
         * online.
         */
-       down_read(&slub_lock);
+       mutex_lock(&slab_mutex);
        list_for_each_entry(s, &slab_caches, list) {
                /*
                 * XXX: kmem_cache_alloc_node will fallback to other nodes
@@ -3632,7 +3612,7 @@ static int slab_mem_going_online_callback(void *arg)
                s->node[nid] = n;
        }
 out:
-       up_read(&slub_lock);
+       mutex_unlock(&slab_mutex);
        return ret;
 }
 
@@ -3843,11 +3823,11 @@ void __init kmem_cache_init(void)
 
                if (s && s->size) {
                        char *name = kasprintf(GFP_NOWAIT,
-                                "dma-kmalloc-%d", s->objsize);
+                                "dma-kmalloc-%d", s->object_size);
 
                        BUG_ON(!name);
                        kmalloc_dma_caches[i] = create_kmalloc_cache(name,
-                               s->objsize, SLAB_CACHE_DMA);
+                               s->object_size, SLAB_CACHE_DMA);
                }
        }
 #endif
@@ -3924,16 +3904,12 @@ static struct kmem_cache *find_mergeable(size_t size,
        return NULL;
 }
 
-struct kmem_cache *kmem_cache_create(const char *name, size_t size,
+struct kmem_cache *__kmem_cache_create(const char *name, size_t size,
                size_t align, unsigned long flags, void (*ctor)(void *))
 {
        struct kmem_cache *s;
        char *n;
 
-       if (WARN_ON(!name))
-               return NULL;
-
-       down_write(&slub_lock);
        s = find_mergeable(size, align, flags, name, ctor);
        if (s) {
                s->refcount++;
@@ -3941,49 +3917,42 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
                 * Adjust the object sizes so that we clear
                 * the complete object on kzalloc.
                 */
-               s->objsize = max(s->objsize, (int)size);
+               s->object_size = max(s->object_size, (int)size);
                s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *)));
 
                if (sysfs_slab_alias(s, name)) {
                        s->refcount--;
-                       goto err;
+                       return NULL;
                }
-               up_write(&slub_lock);
                return s;
        }
 
        n = kstrdup(name, GFP_KERNEL);
        if (!n)
-               goto err;
+               return NULL;
 
        s = kmalloc(kmem_size, GFP_KERNEL);
        if (s) {
                if (kmem_cache_open(s, n,
                                size, align, flags, ctor)) {
+                       int r;
+
                        list_add(&s->list, &slab_caches);
-                       up_write(&slub_lock);
-                       if (sysfs_slab_add(s)) {
-                               down_write(&slub_lock);
-                               list_del(&s->list);
-                               kfree(n);
-                               kfree(s);
-                               goto err;
-                       }
-                       return s;
+                       mutex_unlock(&slab_mutex);
+                       r = sysfs_slab_add(s);
+                       mutex_lock(&slab_mutex);
+
+                       if (!r)
+                               return s;
+
+                       list_del(&s->list);
+                       kmem_cache_close(s);
                }
                kfree(s);
        }
        kfree(n);
-err:
-       up_write(&slub_lock);
-
-       if (flags & SLAB_PANIC)
-               panic("Cannot create slabcache %s\n", name);
-       else
-               s = NULL;
-       return s;
+       return NULL;
 }
-EXPORT_SYMBOL(kmem_cache_create);
 
 #ifdef CONFIG_SMP
 /*
@@ -4002,13 +3971,13 @@ static int __cpuinit slab_cpuup_callback(struct notifier_block *nfb,
        case CPU_UP_CANCELED_FROZEN:
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
-               down_read(&slub_lock);
+               mutex_lock(&slab_mutex);
                list_for_each_entry(s, &slab_caches, list) {
                        local_irq_save(flags);
                        __flush_cpu_slab(s, cpu);
                        local_irq_restore(flags);
                }
-               up_read(&slub_lock);
+               mutex_unlock(&slab_mutex);
                break;
        default:
                break;
@@ -4500,30 +4469,31 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
 
                for_each_possible_cpu(cpu) {
                        struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
-                       int node = ACCESS_ONCE(c->node);
+                       int node;
                        struct page *page;
 
-                       if (node < 0)
-                               continue;
                        page = ACCESS_ONCE(c->page);
-                       if (page) {
-                               if (flags & SO_TOTAL)
-                                       x = page->objects;
-                               else if (flags & SO_OBJECTS)
-                                       x = page->inuse;
-                               else
-                                       x = 1;
+                       if (!page)
+                               continue;
 
-                               total += x;
-                               nodes[node] += x;
-                       }
-                       page = c->partial;
+                       node = page_to_nid(page);
+                       if (flags & SO_TOTAL)
+                               x = page->objects;
+                       else if (flags & SO_OBJECTS)
+                               x = page->inuse;
+                       else
+                               x = 1;
 
+                       total += x;
+                       nodes[node] += x;
+
+                       page = ACCESS_ONCE(c->partial);
                        if (page) {
                                x = page->pobjects;
                                total += x;
                                nodes[node] += x;
                        }
+
                        per_cpu[node]++;
                }
        }
@@ -4623,7 +4593,7 @@ SLAB_ATTR_RO(align);
 
 static ssize_t object_size_show(struct kmem_cache *s, char *buf)
 {
-       return sprintf(buf, "%d\n", s->objsize);
+       return sprintf(buf, "%d\n", s->object_size);
 }
 SLAB_ATTR_RO(object_size);
 
@@ -5286,7 +5256,7 @@ static int sysfs_slab_add(struct kmem_cache *s)
        const char *name;
        int unmergeable;
 
-       if (slab_state < SYSFS)
+       if (slab_state < FULL)
                /* Defer until later */
                return 0;
 
@@ -5331,7 +5301,7 @@ static int sysfs_slab_add(struct kmem_cache *s)
 
 static void sysfs_slab_remove(struct kmem_cache *s)
 {
-       if (slab_state < SYSFS)
+       if (slab_state < FULL)
                /*
                 * Sysfs has not been setup yet so no need to remove the
                 * cache from sysfs.
@@ -5359,7 +5329,7 @@ static int sysfs_slab_alias(struct kmem_cache *s, const char *name)
 {
        struct saved_alias *al;
 
-       if (slab_state == SYSFS) {
+       if (slab_state == FULL) {
                /*
                 * If we have a leftover link then remove it.
                 */
@@ -5383,16 +5353,16 @@ static int __init slab_sysfs_init(void)
        struct kmem_cache *s;
        int err;
 
-       down_write(&slub_lock);
+       mutex_lock(&slab_mutex);
 
        slab_kset = kset_create_and_add("slab", &slab_uevent_ops, kernel_kobj);
        if (!slab_kset) {
-               up_write(&slub_lock);
+               mutex_unlock(&slab_mutex);
                printk(KERN_ERR "Cannot register slab subsystem.\n");
                return -ENOSYS;
        }
 
-       slab_state = SYSFS;
+       slab_state = FULL;
 
        list_for_each_entry(s, &slab_caches, list) {
                err = sysfs_slab_add(s);
@@ -5408,11 +5378,11 @@ static int __init slab_sysfs_init(void)
                err = sysfs_slab_alias(al->s, al->name);
                if (err)
                        printk(KERN_ERR "SLUB: Unable to add boot slab alias"
-                                       " %s to sysfs\n", s->name);
+                                       " %s to sysfs\n", al->name);
                kfree(al);
        }
 
-       up_write(&slub_lock);
+       mutex_unlock(&slab_mutex);
        resiliency_test();
        return 0;
 }
@@ -5427,7 +5397,7 @@ __initcall(slab_sysfs_init);
 static void print_slabinfo_header(struct seq_file *m)
 {
        seq_puts(m, "slabinfo - version: 2.1\n");
-       seq_puts(m, "# name            <active_objs> <num_objs> <objsize> "
+       seq_puts(m, "# name            <active_objs> <num_objs> <object_size> "
                 "<objperslab> <pagesperslab>");
        seq_puts(m, " : tunables <limit> <batchcount> <sharedfactor>");
        seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>");
@@ -5438,7 +5408,7 @@ static void *s_start(struct seq_file *m, loff_t *pos)
 {
        loff_t n = *pos;
 
-       down_read(&slub_lock);
+       mutex_lock(&slab_mutex);
        if (!n)
                print_slabinfo_header(m);
 
@@ -5452,7 +5422,7 @@ static void *s_next(struct seq_file *m, void *p, loff_t *pos)
 
 static void s_stop(struct seq_file *m, void *p)
 {
-       up_read(&slub_lock);
+       mutex_unlock(&slab_mutex);
 }
 
 static int s_show(struct seq_file *m, void *p)
index c7ac8e1b3ac76480cd05fcfaeab6703e9a2610dd..e03f4c7307a5b2dc4d7535815c69a786b2124f5d 100644 (file)
@@ -1280,7 +1280,7 @@ DEFINE_RWLOCK(vmlist_lock);
 struct vm_struct *vmlist;
 
 static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
-                             unsigned long flags, void *caller)
+                             unsigned long flags, const void *caller)
 {
        vm->flags = flags;
        vm->addr = (void *)va->va_start;
@@ -1306,7 +1306,7 @@ static void insert_vmalloc_vmlist(struct vm_struct *vm)
 }
 
 static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
-                             unsigned long flags, void *caller)
+                             unsigned long flags, const void *caller)
 {
        setup_vmalloc_vm(vm, va, flags, caller);
        insert_vmalloc_vmlist(vm);
@@ -1314,7 +1314,7 @@ static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
 
 static struct vm_struct *__get_vm_area_node(unsigned long size,
                unsigned long align, unsigned long flags, unsigned long start,
-               unsigned long end, int node, gfp_t gfp_mask, void *caller)
+               unsigned long end, int node, gfp_t gfp_mask, const void *caller)
 {
        struct vmap_area *va;
        struct vm_struct *area;
@@ -1375,7 +1375,7 @@ EXPORT_SYMBOL_GPL(__get_vm_area);
 
 struct vm_struct *__get_vm_area_caller(unsigned long size, unsigned long flags,
                                       unsigned long start, unsigned long end,
-                                      void *caller)
+                                      const void *caller)
 {
        return __get_vm_area_node(size, 1, flags, start, end, -1, GFP_KERNEL,
                                  caller);
@@ -1397,13 +1397,21 @@ struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
 }
 
 struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
-                               void *caller)
+                               const void *caller)
 {
        return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
                                                -1, GFP_KERNEL, caller);
 }
 
-static struct vm_struct *find_vm_area(const void *addr)
+/**
+ *     find_vm_area  -  find a continuous kernel virtual area
+ *     @addr:          base address
+ *
+ *     Search for the kernel VM area starting at @addr, and return it.
+ *     It is up to the caller to do all required locking to keep the returned
+ *     pointer valid.
+ */
+struct vm_struct *find_vm_area(const void *addr)
 {
        struct vmap_area *va;
 
@@ -1568,9 +1576,9 @@ EXPORT_SYMBOL(vmap);
 
 static void *__vmalloc_node(unsigned long size, unsigned long align,
                            gfp_t gfp_mask, pgprot_t prot,
-                           int node, void *caller);
+                           int node, const void *caller);
 static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
-                                pgprot_t prot, int node, void *caller)
+                                pgprot_t prot, int node, const void *caller)
 {
        const int order = 0;
        struct page **pages;
@@ -1643,7 +1651,7 @@ fail:
  */
 void *__vmalloc_node_range(unsigned long size, unsigned long align,
                        unsigned long start, unsigned long end, gfp_t gfp_mask,
-                       pgprot_t prot, int node, void *caller)
+                       pgprot_t prot, int node, const void *caller)
 {
        struct vm_struct *area;
        void *addr;
@@ -1699,7 +1707,7 @@ fail:
  */
 static void *__vmalloc_node(unsigned long size, unsigned long align,
                            gfp_t gfp_mask, pgprot_t prot,
-                           int node, void *caller)
+                           int node, const void *caller)
 {
        return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
                                gfp_mask, prot, node, caller);
index ba4323bce0e92beff34d13dcdc45b63a1b14dce7..69e38db28e5f3efcda5ce871ac5682408eb5aa9e 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/string.h>
 
 
+#include <linux/ceph/ceph_features.h>
 #include <linux/ceph/libceph.h>
 #include <linux/ceph/debugfs.h>
 #include <linux/ceph/decode.h>
@@ -460,27 +461,23 @@ struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private,
        client->auth_err = 0;
 
        client->extra_mon_dispatch = NULL;
-       client->supported_features = CEPH_FEATURE_SUPPORTED_DEFAULT |
+       client->supported_features = CEPH_FEATURES_SUPPORTED_DEFAULT |
                supported_features;
-       client->required_features = CEPH_FEATURE_REQUIRED_DEFAULT |
+       client->required_features = CEPH_FEATURES_REQUIRED_DEFAULT |
                required_features;
 
        /* msgr */
        if (ceph_test_opt(client, MYIP))
                myaddr = &client->options->my_addr;
-       client->msgr = ceph_messenger_create(myaddr,
-                                            client->supported_features,
-                                            client->required_features);
-       if (IS_ERR(client->msgr)) {
-               err = PTR_ERR(client->msgr);
-               goto fail;
-       }
-       client->msgr->nocrc = ceph_test_opt(client, NOCRC);
+       ceph_messenger_init(&client->msgr, myaddr,
+               client->supported_features,
+               client->required_features,
+               ceph_test_opt(client, NOCRC));
 
        /* subsystems */
        err = ceph_monc_init(&client->monc, client);
        if (err < 0)
-               goto fail_msgr;
+               goto fail;
        err = ceph_osdc_init(&client->osdc, client);
        if (err < 0)
                goto fail_monc;
@@ -489,8 +486,6 @@ struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private,
 
 fail_monc:
        ceph_monc_stop(&client->monc);
-fail_msgr:
-       ceph_messenger_destroy(client->msgr);
 fail:
        kfree(client);
        return ERR_PTR(err);
@@ -501,6 +496,8 @@ void ceph_destroy_client(struct ceph_client *client)
 {
        dout("destroy_client %p\n", client);
 
+       atomic_set(&client->msgr.stopping, 1);
+
        /* unmount */
        ceph_osdc_stop(&client->osdc);
 
@@ -508,8 +505,6 @@ void ceph_destroy_client(struct ceph_client *client)
 
        ceph_debugfs_client_cleanup(client);
 
-       ceph_messenger_destroy(client->msgr);
-
        ceph_destroy_options(client->options);
 
        kfree(client);
index d7edc24333b84d5aab17da2d983878ff5044b2bb..35fce755ce103528071d422ca6e9ca2e0faf6a27 100644 (file)
@@ -306,7 +306,6 @@ static int crush_choose(const struct crush_map *map,
        int item = 0;
        int itemtype;
        int collide, reject;
-       const unsigned int orig_tries = 5; /* attempts before we fall back to search */
 
        dprintk("CHOOSE%s bucket %d x %d outpos %d numrep %d\n", recurse_to_leaf ? "_LEAF" : "",
                bucket->id, x, outpos, numrep);
@@ -351,8 +350,9 @@ static int crush_choose(const struct crush_map *map,
                                        reject = 1;
                                        goto reject;
                                }
-                               if (flocal >= (in->size>>1) &&
-                                   flocal > orig_tries)
+                               if (map->choose_local_fallback_tries > 0 &&
+                                   flocal >= (in->size>>1) &&
+                                   flocal > map->choose_local_fallback_tries)
                                        item = bucket_perm_choose(in, x, r);
                                else
                                        item = crush_bucket_choose(in, x, r);
@@ -422,13 +422,14 @@ reject:
                                        ftotal++;
                                        flocal++;
 
-                                       if (collide && flocal < 3)
+                                       if (collide && flocal <= map->choose_local_tries)
                                                /* retry locally a few times */
                                                retry_bucket = 1;
-                                       else if (flocal <= in->size + orig_tries)
+                                       else if (map->choose_local_fallback_tries > 0 &&
+                                                flocal <= in->size + map->choose_local_fallback_tries)
                                                /* exhaustive bucket search */
                                                retry_bucket = 1;
-                                       else if (ftotal < 20)
+                                       else if (ftotal <= map->choose_total_tries)
                                                /* then retry descent */
                                                retry_descent = 1;
                                        else
index 10255e81be79d84c5428504c2a79be3180626f79..b9796750034afc093c172dc9ac92b2e864d87271 100644 (file)
  * the sender.
  */
 
+/*
+ * We track the state of the socket on a given connection using
+ * values defined below.  The transition to a new socket state is
+ * handled by a function which verifies we aren't coming from an
+ * unexpected state.
+ *
+ *      --------
+ *      | NEW* |  transient initial state
+ *      --------
+ *          | con_sock_state_init()
+ *          v
+ *      ----------
+ *      | CLOSED |  initialized, but no socket (and no
+ *      ----------  TCP connection)
+ *       ^      \
+ *       |       \ con_sock_state_connecting()
+ *       |        ----------------------
+ *       |                              \
+ *       + con_sock_state_closed()       \
+ *       |+---------------------------    \
+ *       | \                          \    \
+ *       |  -----------                \    \
+ *       |  | CLOSING |  socket event;  \    \
+ *       |  -----------  await close     \    \
+ *       |       ^                        \   |
+ *       |       |                         \  |
+ *       |       + con_sock_state_closing() \ |
+ *       |      / \                         | |
+ *       |     /   ---------------          | |
+ *       |    /                   \         v v
+ *       |   /                    --------------
+ *       |  /    -----------------| CONNECTING |  socket created, TCP
+ *       |  |   /                 --------------  connect initiated
+ *       |  |   | con_sock_state_connected()
+ *       |  |   v
+ *      -------------
+ *      | CONNECTED |  TCP connection established
+ *      -------------
+ *
+ * State values for ceph_connection->sock_state; NEW is assumed to be 0.
+ */
+
+#define CON_SOCK_STATE_NEW             0       /* -> CLOSED */
+#define CON_SOCK_STATE_CLOSED          1       /* -> CONNECTING */
+#define CON_SOCK_STATE_CONNECTING      2       /* -> CONNECTED or -> CLOSING */
+#define CON_SOCK_STATE_CONNECTED       3       /* -> CLOSING or -> CLOSED */
+#define CON_SOCK_STATE_CLOSING         4       /* -> CLOSED */
+
+/*
+ * connection states
+ */
+#define CON_STATE_CLOSED        1  /* -> PREOPEN */
+#define CON_STATE_PREOPEN       2  /* -> CONNECTING, CLOSED */
+#define CON_STATE_CONNECTING    3  /* -> NEGOTIATING, CLOSED */
+#define CON_STATE_NEGOTIATING   4  /* -> OPEN, CLOSED */
+#define CON_STATE_OPEN          5  /* -> STANDBY, CLOSED */
+#define CON_STATE_STANDBY       6  /* -> PREOPEN, CLOSED */
+
+/*
+ * ceph_connection flag bits
+ */
+#define CON_FLAG_LOSSYTX           0  /* we can close channel or drop
+                                      * messages on errors */
+#define CON_FLAG_KEEPALIVE_PENDING 1  /* we need to send a keepalive */
+#define CON_FLAG_WRITE_PENDING    2  /* we have data ready to send */
+#define CON_FLAG_SOCK_CLOSED      3  /* socket state changed to closed */
+#define CON_FLAG_BACKOFF           4  /* need to retry queuing delayed work */
+
 /* static tag bytes (protocol control messages) */
 static char tag_msg = CEPH_MSGR_TAG_MSG;
 static char tag_ack = CEPH_MSGR_TAG_ACK;
@@ -147,72 +215,130 @@ void ceph_msgr_flush(void)
 }
 EXPORT_SYMBOL(ceph_msgr_flush);
 
+/* Connection socket state transition functions */
+
+static void con_sock_state_init(struct ceph_connection *con)
+{
+       int old_state;
+
+       old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CLOSED);
+       if (WARN_ON(old_state != CON_SOCK_STATE_NEW))
+               printk("%s: unexpected old state %d\n", __func__, old_state);
+       dout("%s con %p sock %d -> %d\n", __func__, con, old_state,
+            CON_SOCK_STATE_CLOSED);
+}
+
+static void con_sock_state_connecting(struct ceph_connection *con)
+{
+       int old_state;
+
+       old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CONNECTING);
+       if (WARN_ON(old_state != CON_SOCK_STATE_CLOSED))
+               printk("%s: unexpected old state %d\n", __func__, old_state);
+       dout("%s con %p sock %d -> %d\n", __func__, con, old_state,
+            CON_SOCK_STATE_CONNECTING);
+}
+
+static void con_sock_state_connected(struct ceph_connection *con)
+{
+       int old_state;
+
+       old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CONNECTED);
+       if (WARN_ON(old_state != CON_SOCK_STATE_CONNECTING))
+               printk("%s: unexpected old state %d\n", __func__, old_state);
+       dout("%s con %p sock %d -> %d\n", __func__, con, old_state,
+            CON_SOCK_STATE_CONNECTED);
+}
+
+static void con_sock_state_closing(struct ceph_connection *con)
+{
+       int old_state;
+
+       old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CLOSING);
+       if (WARN_ON(old_state != CON_SOCK_STATE_CONNECTING &&
+                       old_state != CON_SOCK_STATE_CONNECTED &&
+                       old_state != CON_SOCK_STATE_CLOSING))
+               printk("%s: unexpected old state %d\n", __func__, old_state);
+       dout("%s con %p sock %d -> %d\n", __func__, con, old_state,
+            CON_SOCK_STATE_CLOSING);
+}
+
+static void con_sock_state_closed(struct ceph_connection *con)
+{
+       int old_state;
+
+       old_state = atomic_xchg(&con->sock_state, CON_SOCK_STATE_CLOSED);
+       if (WARN_ON(old_state != CON_SOCK_STATE_CONNECTED &&
+                   old_state != CON_SOCK_STATE_CLOSING &&
+                   old_state != CON_SOCK_STATE_CONNECTING &&
+                   old_state != CON_SOCK_STATE_CLOSED))
+               printk("%s: unexpected old state %d\n", __func__, old_state);
+       dout("%s con %p sock %d -> %d\n", __func__, con, old_state,
+            CON_SOCK_STATE_CLOSED);
+}
 
 /*
  * socket callback functions
  */
 
 /* data available on socket, or listen socket received a connect */
-static void ceph_data_ready(struct sock *sk, int count_unused)
+static void ceph_sock_data_ready(struct sock *sk, int count_unused)
 {
        struct ceph_connection *con = sk->sk_user_data;
+       if (atomic_read(&con->msgr->stopping)) {
+               return;
+       }
 
        if (sk->sk_state != TCP_CLOSE_WAIT) {
-               dout("ceph_data_ready on %p state = %lu, queueing work\n",
+               dout("%s on %p state = %lu, queueing work\n", __func__,
                     con, con->state);
                queue_con(con);
        }
 }
 
 /* socket has buffer space for writing */
-static void ceph_write_space(struct sock *sk)
+static void ceph_sock_write_space(struct sock *sk)
 {
        struct ceph_connection *con = sk->sk_user_data;
 
        /* only queue to workqueue if there is data we want to write,
         * and there is sufficient space in the socket buffer to accept
-        * more data.  clear SOCK_NOSPACE so that ceph_write_space()
+        * more data.  clear SOCK_NOSPACE so that ceph_sock_write_space()
         * doesn't get called again until try_write() fills the socket
         * buffer. See net/ipv4/tcp_input.c:tcp_check_space()
         * and net/core/stream.c:sk_stream_write_space().
         */
-       if (test_bit(WRITE_PENDING, &con->state)) {
+       if (test_bit(CON_FLAG_WRITE_PENDING, &con->flags)) {
                if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
-                       dout("ceph_write_space %p queueing write work\n", con);
+                       dout("%s %p queueing write work\n", __func__, con);
                        clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
                        queue_con(con);
                }
        } else {
-               dout("ceph_write_space %p nothing to write\n", con);
+               dout("%s %p nothing to write\n", __func__, con);
        }
 }
 
 /* socket's state has changed */
-static void ceph_state_change(struct sock *sk)
+static void ceph_sock_state_change(struct sock *sk)
 {
        struct ceph_connection *con = sk->sk_user_data;
 
-       dout("ceph_state_change %p state = %lu sk_state = %u\n",
+       dout("%s %p state = %lu sk_state = %u\n", __func__,
             con, con->state, sk->sk_state);
 
-       if (test_bit(CLOSED, &con->state))
-               return;
-
        switch (sk->sk_state) {
        case TCP_CLOSE:
-               dout("ceph_state_change TCP_CLOSE\n");
+               dout("%s TCP_CLOSE\n", __func__);
        case TCP_CLOSE_WAIT:
-               dout("ceph_state_change TCP_CLOSE_WAIT\n");
-               if (test_and_set_bit(SOCK_CLOSED, &con->state) == 0) {
-                       if (test_bit(CONNECTING, &con->state))
-                               con->error_msg = "connection failed";
-                       else
-                               con->error_msg = "socket closed";
-                       queue_con(con);
-               }
+               dout("%s TCP_CLOSE_WAIT\n", __func__);
+               con_sock_state_closing(con);
+               set_bit(CON_FLAG_SOCK_CLOSED, &con->flags);
+               queue_con(con);
                break;
        case TCP_ESTABLISHED:
-               dout("ceph_state_change TCP_ESTABLISHED\n");
+               dout("%s TCP_ESTABLISHED\n", __func__);
+               con_sock_state_connected(con);
                queue_con(con);
                break;
        default:        /* Everything else is uninteresting */
@@ -228,9 +354,9 @@ static void set_sock_callbacks(struct socket *sock,
 {
        struct sock *sk = sock->sk;
        sk->sk_user_data = con;
-       sk->sk_data_ready = ceph_data_ready;
-       sk->sk_write_space = ceph_write_space;
-       sk->sk_state_change = ceph_state_change;
+       sk->sk_data_ready = ceph_sock_data_ready;
+       sk->sk_write_space = ceph_sock_write_space;
+       sk->sk_state_change = ceph_sock_state_change;
 }
 
 
@@ -262,6 +388,7 @@ static int ceph_tcp_connect(struct ceph_connection *con)
 
        dout("connect %s\n", ceph_pr_addr(&con->peer_addr.in_addr));
 
+       con_sock_state_connecting(con);
        ret = sock->ops->connect(sock, (struct sockaddr *)paddr, sizeof(*paddr),
                                 O_NONBLOCK);
        if (ret == -EINPROGRESS) {
@@ -277,7 +404,6 @@ static int ceph_tcp_connect(struct ceph_connection *con)
                return ret;
        }
        con->sock = sock;
-
        return 0;
 }
 
@@ -333,16 +459,24 @@ static int ceph_tcp_sendpage(struct socket *sock, struct page *page,
  */
 static int con_close_socket(struct ceph_connection *con)
 {
-       int rc;
+       int rc = 0;
 
        dout("con_close_socket on %p sock %p\n", con, con->sock);
-       if (!con->sock)
-               return 0;
-       set_bit(SOCK_CLOSED, &con->state);
-       rc = con->sock->ops->shutdown(con->sock, SHUT_RDWR);
-       sock_release(con->sock);
-       con->sock = NULL;
-       clear_bit(SOCK_CLOSED, &con->state);
+       if (con->sock) {
+               rc = con->sock->ops->shutdown(con->sock, SHUT_RDWR);
+               sock_release(con->sock);
+               con->sock = NULL;
+       }
+
+       /*
+        * Forcibly clear the SOCK_CLOSED flag.  It gets set
+        * independent of the connection mutex, and we could have
+        * received a socket close event before we had the chance to
+        * shut the socket down.
+        */
+       clear_bit(CON_FLAG_SOCK_CLOSED, &con->flags);
+
+       con_sock_state_closed(con);
        return rc;
 }
 
@@ -353,6 +487,10 @@ static int con_close_socket(struct ceph_connection *con)
 static void ceph_msg_remove(struct ceph_msg *msg)
 {
        list_del_init(&msg->list_head);
+       BUG_ON(msg->con == NULL);
+       msg->con->ops->put(msg->con);
+       msg->con = NULL;
+
        ceph_msg_put(msg);
 }
 static void ceph_msg_remove_list(struct list_head *head)
@@ -372,8 +510,11 @@ static void reset_connection(struct ceph_connection *con)
        ceph_msg_remove_list(&con->out_sent);
 
        if (con->in_msg) {
+               BUG_ON(con->in_msg->con != con);
+               con->in_msg->con = NULL;
                ceph_msg_put(con->in_msg);
                con->in_msg = NULL;
+               con->ops->put(con);
        }
 
        con->connect_seq = 0;
@@ -391,32 +532,44 @@ static void reset_connection(struct ceph_connection *con)
  */
 void ceph_con_close(struct ceph_connection *con)
 {
+       mutex_lock(&con->mutex);
        dout("con_close %p peer %s\n", con,
             ceph_pr_addr(&con->peer_addr.in_addr));
-       set_bit(CLOSED, &con->state);  /* in case there's queued work */
-       clear_bit(STANDBY, &con->state);  /* avoid connect_seq bump */
-       clear_bit(LOSSYTX, &con->state);  /* so we retry next connect */
-       clear_bit(KEEPALIVE_PENDING, &con->state);
-       clear_bit(WRITE_PENDING, &con->state);
-       mutex_lock(&con->mutex);
+       con->state = CON_STATE_CLOSED;
+
+       clear_bit(CON_FLAG_LOSSYTX, &con->flags); /* so we retry next connect */
+       clear_bit(CON_FLAG_KEEPALIVE_PENDING, &con->flags);
+       clear_bit(CON_FLAG_WRITE_PENDING, &con->flags);
+       clear_bit(CON_FLAG_KEEPALIVE_PENDING, &con->flags);
+       clear_bit(CON_FLAG_BACKOFF, &con->flags);
+
        reset_connection(con);
        con->peer_global_seq = 0;
        cancel_delayed_work(&con->work);
+       con_close_socket(con);
        mutex_unlock(&con->mutex);
-       queue_con(con);
 }
 EXPORT_SYMBOL(ceph_con_close);
 
 /*
  * Reopen a closed connection, with a new peer address.
  */
-void ceph_con_open(struct ceph_connection *con, struct ceph_entity_addr *addr)
+void ceph_con_open(struct ceph_connection *con,
+                  __u8 entity_type, __u64 entity_num,
+                  struct ceph_entity_addr *addr)
 {
+       mutex_lock(&con->mutex);
        dout("con_open %p %s\n", con, ceph_pr_addr(&addr->in_addr));
-       set_bit(OPENING, &con->state);
-       clear_bit(CLOSED, &con->state);
+
+       BUG_ON(con->state != CON_STATE_CLOSED);
+       con->state = CON_STATE_PREOPEN;
+
+       con->peer_name.type = (__u8) entity_type;
+       con->peer_name.num = cpu_to_le64(entity_num);
+
        memcpy(&con->peer_addr, addr, sizeof(*addr));
        con->delay = 0;      /* reset backoff memory */
+       mutex_unlock(&con->mutex);
        queue_con(con);
 }
 EXPORT_SYMBOL(ceph_con_open);
@@ -429,43 +582,27 @@ bool ceph_con_opened(struct ceph_connection *con)
        return con->connect_seq > 0;
 }
 
-/*
- * generic get/put
- */
-struct ceph_connection *ceph_con_get(struct ceph_connection *con)
-{
-       int nref = __atomic_add_unless(&con->nref, 1, 0);
-
-       dout("con_get %p nref = %d -> %d\n", con, nref, nref + 1);
-
-       return nref ? con : NULL;
-}
-
-void ceph_con_put(struct ceph_connection *con)
-{
-       int nref = atomic_dec_return(&con->nref);
-
-       BUG_ON(nref < 0);
-       if (nref == 0) {
-               BUG_ON(con->sock);
-               kfree(con);
-       }
-       dout("con_put %p nref = %d -> %d\n", con, nref + 1, nref);
-}
-
 /*
  * initialize a new connection.
  */
-void ceph_con_init(struct ceph_messenger *msgr, struct ceph_connection *con)
+void ceph_con_init(struct ceph_connection *con, void *private,
+       const struct ceph_connection_operations *ops,
+       struct ceph_messenger *msgr)
 {
        dout("con_init %p\n", con);
        memset(con, 0, sizeof(*con));
-       atomic_set(&con->nref, 1);
+       con->private = private;
+       con->ops = ops;
        con->msgr = msgr;
+
+       con_sock_state_init(con);
+
        mutex_init(&con->mutex);
        INIT_LIST_HEAD(&con->out_queue);
        INIT_LIST_HEAD(&con->out_sent);
        INIT_DELAYED_WORK(&con->work, con_work);
+
+       con->state = CON_STATE_CLOSED;
 }
 EXPORT_SYMBOL(ceph_con_init);
 
@@ -486,14 +623,14 @@ static u32 get_global_seq(struct ceph_messenger *msgr, u32 gt)
        return ret;
 }
 
-static void ceph_con_out_kvec_reset(struct ceph_connection *con)
+static void con_out_kvec_reset(struct ceph_connection *con)
 {
        con->out_kvec_left = 0;
        con->out_kvec_bytes = 0;
        con->out_kvec_cur = &con->out_kvec[0];
 }
 
-static void ceph_con_out_kvec_add(struct ceph_connection *con,
+static void con_out_kvec_add(struct ceph_connection *con,
                                size_t size, void *data)
 {
        int index;
@@ -507,6 +644,53 @@ static void ceph_con_out_kvec_add(struct ceph_connection *con,
        con->out_kvec_bytes += size;
 }
 
+#ifdef CONFIG_BLOCK
+static void init_bio_iter(struct bio *bio, struct bio **iter, int *seg)
+{
+       if (!bio) {
+               *iter = NULL;
+               *seg = 0;
+               return;
+       }
+       *iter = bio;
+       *seg = bio->bi_idx;
+}
+
+static void iter_bio_next(struct bio **bio_iter, int *seg)
+{
+       if (*bio_iter == NULL)
+               return;
+
+       BUG_ON(*seg >= (*bio_iter)->bi_vcnt);
+
+       (*seg)++;
+       if (*seg == (*bio_iter)->bi_vcnt)
+               init_bio_iter((*bio_iter)->bi_next, bio_iter, seg);
+}
+#endif
+
+static void prepare_write_message_data(struct ceph_connection *con)
+{
+       struct ceph_msg *msg = con->out_msg;
+
+       BUG_ON(!msg);
+       BUG_ON(!msg->hdr.data_len);
+
+       /* initialize page iterator */
+       con->out_msg_pos.page = 0;
+       if (msg->pages)
+               con->out_msg_pos.page_pos = msg->page_alignment;
+       else
+               con->out_msg_pos.page_pos = 0;
+#ifdef CONFIG_BLOCK
+       if (msg->bio)
+               init_bio_iter(msg->bio, &msg->bio_iter, &msg->bio_seg);
+#endif
+       con->out_msg_pos.data_pos = 0;
+       con->out_msg_pos.did_page_crc = false;
+       con->out_more = 1;  /* data + footer will follow */
+}
+
 /*
  * Prepare footer for currently outgoing message, and finish things
  * off.  Assumes out_kvec* are already valid.. we just add on to the end.
@@ -516,6 +700,8 @@ static void prepare_write_message_footer(struct ceph_connection *con)
        struct ceph_msg *m = con->out_msg;
        int v = con->out_kvec_left;
 
+       m->footer.flags |= CEPH_MSG_FOOTER_COMPLETE;
+
        dout("prepare_write_message_footer %p\n", con);
        con->out_kvec_is_msg = true;
        con->out_kvec[v].iov_base = &m->footer;
@@ -534,7 +720,7 @@ static void prepare_write_message(struct ceph_connection *con)
        struct ceph_msg *m;
        u32 crc;
 
-       ceph_con_out_kvec_reset(con);
+       con_out_kvec_reset(con);
        con->out_kvec_is_msg = true;
        con->out_msg_done = false;
 
@@ -542,14 +728,16 @@ static void prepare_write_message(struct ceph_connection *con)
         * TCP packet that's a good thing. */
        if (con->in_seq > con->in_seq_acked) {
                con->in_seq_acked = con->in_seq;
-               ceph_con_out_kvec_add(con, sizeof (tag_ack), &tag_ack);
+               con_out_kvec_add(con, sizeof (tag_ack), &tag_ack);
                con->out_temp_ack = cpu_to_le64(con->in_seq_acked);
-               ceph_con_out_kvec_add(con, sizeof (con->out_temp_ack),
+               con_out_kvec_add(con, sizeof (con->out_temp_ack),
                        &con->out_temp_ack);
        }
 
+       BUG_ON(list_empty(&con->out_queue));
        m = list_first_entry(&con->out_queue, struct ceph_msg, list_head);
        con->out_msg = m;
+       BUG_ON(m->con != con);
 
        /* put message on sent list */
        ceph_msg_get(m);
@@ -576,18 +764,18 @@ static void prepare_write_message(struct ceph_connection *con)
        BUG_ON(le32_to_cpu(m->hdr.front_len) != m->front.iov_len);
 
        /* tag + hdr + front + middle */
-       ceph_con_out_kvec_add(con, sizeof (tag_msg), &tag_msg);
-       ceph_con_out_kvec_add(con, sizeof (m->hdr), &m->hdr);
-       ceph_con_out_kvec_add(con, m->front.iov_len, m->front.iov_base);
+       con_out_kvec_add(con, sizeof (tag_msg), &tag_msg);
+       con_out_kvec_add(con, sizeof (m->hdr), &m->hdr);
+       con_out_kvec_add(con, m->front.iov_len, m->front.iov_base);
 
        if (m->middle)
-               ceph_con_out_kvec_add(con, m->middle->vec.iov_len,
+               con_out_kvec_add(con, m->middle->vec.iov_len,
                        m->middle->vec.iov_base);
 
        /* fill in crc (except data pages), footer */
        crc = crc32c(0, &m->hdr, offsetof(struct ceph_msg_header, crc));
        con->out_msg->hdr.crc = cpu_to_le32(crc);
-       con->out_msg->footer.flags = CEPH_MSG_FOOTER_COMPLETE;
+       con->out_msg->footer.flags = 0;
 
        crc = crc32c(0, m->front.iov_base, m->front.iov_len);
        con->out_msg->footer.front_crc = cpu_to_le32(crc);
@@ -597,28 +785,19 @@ static void prepare_write_message(struct ceph_connection *con)
                con->out_msg->footer.middle_crc = cpu_to_le32(crc);
        } else
                con->out_msg->footer.middle_crc = 0;
-       con->out_msg->footer.data_crc = 0;
-       dout("prepare_write_message front_crc %u data_crc %u\n",
+       dout("%s front_crc %u middle_crc %u\n", __func__,
             le32_to_cpu(con->out_msg->footer.front_crc),
             le32_to_cpu(con->out_msg->footer.middle_crc));
 
        /* is there a data payload? */
-       if (le32_to_cpu(m->hdr.data_len) > 0) {
-               /* initialize page iterator */
-               con->out_msg_pos.page = 0;
-               if (m->pages)
-                       con->out_msg_pos.page_pos = m->page_alignment;
-               else
-                       con->out_msg_pos.page_pos = 0;
-               con->out_msg_pos.data_pos = 0;
-               con->out_msg_pos.did_page_crc = false;
-               con->out_more = 1;  /* data + footer will follow */
-       } else {
+       con->out_msg->footer.data_crc = 0;
+       if (m->hdr.data_len)
+               prepare_write_message_data(con);
+       else
                /* no, queue up footer too and be done */
                prepare_write_message_footer(con);
-       }
 
-       set_bit(WRITE_PENDING, &con->state);
+       set_bit(CON_FLAG_WRITE_PENDING, &con->flags);
 }
 
 /*
@@ -630,16 +809,16 @@ static void prepare_write_ack(struct ceph_connection *con)
             con->in_seq_acked, con->in_seq);
        con->in_seq_acked = con->in_seq;
 
-       ceph_con_out_kvec_reset(con);
+       con_out_kvec_reset(con);
 
-       ceph_con_out_kvec_add(con, sizeof (tag_ack), &tag_ack);
+       con_out_kvec_add(con, sizeof (tag_ack), &tag_ack);
 
        con->out_temp_ack = cpu_to_le64(con->in_seq_acked);
-       ceph_con_out_kvec_add(con, sizeof (con->out_temp_ack),
+       con_out_kvec_add(con, sizeof (con->out_temp_ack),
                                &con->out_temp_ack);
 
        con->out_more = 1;  /* more will follow.. eventually.. */
-       set_bit(WRITE_PENDING, &con->state);
+       set_bit(CON_FLAG_WRITE_PENDING, &con->flags);
 }
 
 /*
@@ -648,9 +827,9 @@ static void prepare_write_ack(struct ceph_connection *con)
 static void prepare_write_keepalive(struct ceph_connection *con)
 {
        dout("prepare_write_keepalive %p\n", con);
-       ceph_con_out_kvec_reset(con);
-       ceph_con_out_kvec_add(con, sizeof (tag_keepalive), &tag_keepalive);
-       set_bit(WRITE_PENDING, &con->state);
+       con_out_kvec_reset(con);
+       con_out_kvec_add(con, sizeof (tag_keepalive), &tag_keepalive);
+       set_bit(CON_FLAG_WRITE_PENDING, &con->flags);
 }
 
 /*
@@ -665,27 +844,21 @@ static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection
        if (!con->ops->get_authorizer) {
                con->out_connect.authorizer_protocol = CEPH_AUTH_UNKNOWN;
                con->out_connect.authorizer_len = 0;
-
                return NULL;
        }
 
        /* Can't hold the mutex while getting authorizer */
-
        mutex_unlock(&con->mutex);
-
        auth = con->ops->get_authorizer(con, auth_proto, con->auth_retry);
-
        mutex_lock(&con->mutex);
 
        if (IS_ERR(auth))
                return auth;
-       if (test_bit(CLOSED, &con->state) || test_bit(OPENING, &con->state))
+       if (con->state != CON_STATE_NEGOTIATING)
                return ERR_PTR(-EAGAIN);
 
        con->auth_reply_buf = auth->authorizer_reply_buf;
        con->auth_reply_buf_len = auth->authorizer_reply_buf_len;
-
-
        return auth;
 }
 
@@ -694,12 +867,12 @@ static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection
  */
 static void prepare_write_banner(struct ceph_connection *con)
 {
-       ceph_con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER);
-       ceph_con_out_kvec_add(con, sizeof (con->msgr->my_enc_addr),
+       con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER);
+       con_out_kvec_add(con, sizeof (con->msgr->my_enc_addr),
                                        &con->msgr->my_enc_addr);
 
        con->out_more = 0;
-       set_bit(WRITE_PENDING, &con->state);
+       set_bit(CON_FLAG_WRITE_PENDING, &con->flags);
 }
 
 static int prepare_write_connect(struct ceph_connection *con)
@@ -742,14 +915,15 @@ static int prepare_write_connect(struct ceph_connection *con)
        con->out_connect.authorizer_len = auth ?
                cpu_to_le32(auth->authorizer_buf_len) : 0;
 
-       ceph_con_out_kvec_add(con, sizeof (con->out_connect),
+       con_out_kvec_reset(con);
+       con_out_kvec_add(con, sizeof (con->out_connect),
                                        &con->out_connect);
        if (auth && auth->authorizer_buf_len)
-               ceph_con_out_kvec_add(con, auth->authorizer_buf_len,
+               con_out_kvec_add(con, auth->authorizer_buf_len,
                                        auth->authorizer_buf);
 
        con->out_more = 0;
-       set_bit(WRITE_PENDING, &con->state);
+       set_bit(CON_FLAG_WRITE_PENDING, &con->flags);
 
        return 0;
 }
@@ -797,30 +971,34 @@ out:
        return ret;  /* done! */
 }
 
-#ifdef CONFIG_BLOCK
-static void init_bio_iter(struct bio *bio, struct bio **iter, int *seg)
+static void out_msg_pos_next(struct ceph_connection *con, struct page *page,
+                       size_t len, size_t sent, bool in_trail)
 {
-       if (!bio) {
-               *iter = NULL;
-               *seg = 0;
-               return;
-       }
-       *iter = bio;
-       *seg = bio->bi_idx;
-}
+       struct ceph_msg *msg = con->out_msg;
 
-static void iter_bio_next(struct bio **bio_iter, int *seg)
-{
-       if (*bio_iter == NULL)
-               return;
+       BUG_ON(!msg);
+       BUG_ON(!sent);
 
-       BUG_ON(*seg >= (*bio_iter)->bi_vcnt);
+       con->out_msg_pos.data_pos += sent;
+       con->out_msg_pos.page_pos += sent;
+       if (sent < len)
+               return;
 
-       (*seg)++;
-       if (*seg == (*bio_iter)->bi_vcnt)
-               init_bio_iter((*bio_iter)->bi_next, bio_iter, seg);
-}
+       BUG_ON(sent != len);
+       con->out_msg_pos.page_pos = 0;
+       con->out_msg_pos.page++;
+       con->out_msg_pos.did_page_crc = false;
+       if (in_trail)
+               list_move_tail(&page->lru,
+                              &msg->trail->head);
+       else if (msg->pagelist)
+               list_move_tail(&page->lru,
+                              &msg->pagelist->head);
+#ifdef CONFIG_BLOCK
+       else if (msg->bio)
+               iter_bio_next(&msg->bio_iter, &msg->bio_seg);
 #endif
+}
 
 /*
  * Write as much message data payload as we can.  If we finish, queue
@@ -837,41 +1015,36 @@ static int write_partial_msg_pages(struct ceph_connection *con)
        bool do_datacrc = !con->msgr->nocrc;
        int ret;
        int total_max_write;
-       int in_trail = 0;
-       size_t trail_len = (msg->trail ? msg->trail->length : 0);
+       bool in_trail = false;
+       const size_t trail_len = (msg->trail ? msg->trail->length : 0);
+       const size_t trail_off = data_len - trail_len;
 
        dout("write_partial_msg_pages %p msg %p page %d/%d offset %d\n",
-            con, con->out_msg, con->out_msg_pos.page, con->out_msg->nr_pages,
+            con, msg, con->out_msg_pos.page, msg->nr_pages,
             con->out_msg_pos.page_pos);
 
-#ifdef CONFIG_BLOCK
-       if (msg->bio && !msg->bio_iter)
-               init_bio_iter(msg->bio, &msg->bio_iter, &msg->bio_seg);
-#endif
-
+       /*
+        * Iterate through each page that contains data to be
+        * written, and send as much as possible for each.
+        *
+        * If we are calculating the data crc (the default), we will
+        * need to map the page.  If we have no pages, they have
+        * been revoked, so use the zero page.
+        */
        while (data_len > con->out_msg_pos.data_pos) {
                struct page *page = NULL;
                int max_write = PAGE_SIZE;
                int bio_offset = 0;
 
-               total_max_write = data_len - trail_len -
-                       con->out_msg_pos.data_pos;
-
-               /*
-                * if we are calculating the data crc (the default), we need
-                * to map the page.  if our pages[] has been revoked, use the
-                * zero page.
-                */
-
-               /* have we reached the trail part of the data? */
-               if (con->out_msg_pos.data_pos >= data_len - trail_len) {
-                       in_trail = 1;
+               in_trail = in_trail || con->out_msg_pos.data_pos >= trail_off;
+               if (!in_trail)
+                       total_max_write = trail_off - con->out_msg_pos.data_pos;
 
+               if (in_trail) {
                        total_max_write = data_len - con->out_msg_pos.data_pos;
 
                        page = list_first_entry(&msg->trail->head,
                                                struct page, lru);
-                       max_write = PAGE_SIZE;
                } else if (msg->pages) {
                        page = msg->pages[con->out_msg_pos.page];
                } else if (msg->pagelist) {
@@ -894,15 +1067,14 @@ static int write_partial_msg_pages(struct ceph_connection *con)
 
                if (do_datacrc && !con->out_msg_pos.did_page_crc) {
                        void *base;
-                       u32 crc;
-                       u32 tmpcrc = le32_to_cpu(con->out_msg->footer.data_crc);
+                       u32 crc = le32_to_cpu(msg->footer.data_crc);
                        char *kaddr;
 
                        kaddr = kmap(page);
                        BUG_ON(kaddr == NULL);
                        base = kaddr + con->out_msg_pos.page_pos + bio_offset;
-                       crc = crc32c(tmpcrc, base, len);
-                       con->out_msg->footer.data_crc = cpu_to_le32(crc);
+                       crc = crc32c(crc, base, len);
+                       msg->footer.data_crc = cpu_to_le32(crc);
                        con->out_msg_pos.did_page_crc = true;
                }
                ret = ceph_tcp_sendpage(con->sock, page,
@@ -915,31 +1087,15 @@ static int write_partial_msg_pages(struct ceph_connection *con)
                if (ret <= 0)
                        goto out;
 
-               con->out_msg_pos.data_pos += ret;
-               con->out_msg_pos.page_pos += ret;
-               if (ret == len) {
-                       con->out_msg_pos.page_pos = 0;
-                       con->out_msg_pos.page++;
-                       con->out_msg_pos.did_page_crc = false;
-                       if (in_trail)
-                               list_move_tail(&page->lru,
-                                              &msg->trail->head);
-                       else if (msg->pagelist)
-                               list_move_tail(&page->lru,
-                                              &msg->pagelist->head);
-#ifdef CONFIG_BLOCK
-                       else if (msg->bio)
-                               iter_bio_next(&msg->bio_iter, &msg->bio_seg);
-#endif
-               }
+               out_msg_pos_next(con, page, len, (size_t) ret, in_trail);
        }
 
        dout("write_partial_msg_pages %p msg %p done\n", con, msg);
 
        /* prepare and queue up footer, too */
        if (!do_datacrc)
-               con->out_msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC;
-       ceph_con_out_kvec_reset(con);
+               msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC;
+       con_out_kvec_reset(con);
        prepare_write_message_footer(con);
        ret = 1;
 out:
@@ -1351,20 +1507,14 @@ static int process_banner(struct ceph_connection *con)
                     ceph_pr_addr(&con->msgr->inst.addr.in_addr));
        }
 
-       set_bit(NEGOTIATING, &con->state);
-       prepare_read_connect(con);
        return 0;
 }
 
 static void fail_protocol(struct ceph_connection *con)
 {
        reset_connection(con);
-       set_bit(CLOSED, &con->state);  /* in case there's queued work */
-
-       mutex_unlock(&con->mutex);
-       if (con->ops->bad_proto)
-               con->ops->bad_proto(con);
-       mutex_lock(&con->mutex);
+       BUG_ON(con->state != CON_STATE_NEGOTIATING);
+       con->state = CON_STATE_CLOSED;
 }
 
 static int process_connect(struct ceph_connection *con)
@@ -1407,7 +1557,6 @@ static int process_connect(struct ceph_connection *con)
                        return -1;
                }
                con->auth_retry = 1;
-               ceph_con_out_kvec_reset(con);
                ret = prepare_write_connect(con);
                if (ret < 0)
                        return ret;
@@ -1428,7 +1577,6 @@ static int process_connect(struct ceph_connection *con)
                       ENTITY_NAME(con->peer_name),
                       ceph_pr_addr(&con->peer_addr.in_addr));
                reset_connection(con);
-               ceph_con_out_kvec_reset(con);
                ret = prepare_write_connect(con);
                if (ret < 0)
                        return ret;
@@ -1440,8 +1588,7 @@ static int process_connect(struct ceph_connection *con)
                if (con->ops->peer_reset)
                        con->ops->peer_reset(con);
                mutex_lock(&con->mutex);
-               if (test_bit(CLOSED, &con->state) ||
-                   test_bit(OPENING, &con->state))
+               if (con->state != CON_STATE_NEGOTIATING)
                        return -EAGAIN;
                break;
 
@@ -1454,7 +1601,6 @@ static int process_connect(struct ceph_connection *con)
                     le32_to_cpu(con->out_connect.connect_seq),
                     le32_to_cpu(con->in_reply.connect_seq));
                con->connect_seq = le32_to_cpu(con->in_reply.connect_seq);
-               ceph_con_out_kvec_reset(con);
                ret = prepare_write_connect(con);
                if (ret < 0)
                        return ret;
@@ -1471,7 +1617,6 @@ static int process_connect(struct ceph_connection *con)
                     le32_to_cpu(con->in_reply.global_seq));
                get_global_seq(con->msgr,
                               le32_to_cpu(con->in_reply.global_seq));
-               ceph_con_out_kvec_reset(con);
                ret = prepare_write_connect(con);
                if (ret < 0)
                        return ret;
@@ -1489,7 +1634,10 @@ static int process_connect(struct ceph_connection *con)
                        fail_protocol(con);
                        return -1;
                }
-               clear_bit(CONNECTING, &con->state);
+
+               BUG_ON(con->state != CON_STATE_NEGOTIATING);
+               con->state = CON_STATE_OPEN;
+
                con->peer_global_seq = le32_to_cpu(con->in_reply.global_seq);
                con->connect_seq++;
                con->peer_features = server_feat;
@@ -1501,7 +1649,9 @@ static int process_connect(struct ceph_connection *con)
                        le32_to_cpu(con->in_reply.connect_seq));
 
                if (con->in_reply.flags & CEPH_MSG_CONNECT_LOSSY)
-                       set_bit(LOSSYTX, &con->state);
+                       set_bit(CON_FLAG_LOSSYTX, &con->flags);
+
+               con->delay = 0;      /* reset backoff memory */
 
                prepare_read_tag(con);
                break;
@@ -1587,10 +1737,7 @@ static int read_partial_message_section(struct ceph_connection *con,
        return 1;
 }
 
-static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
-                               struct ceph_msg_header *hdr,
-                               int *skip);
-
+static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip);
 
 static int read_partial_message_pages(struct ceph_connection *con,
                                      struct page **pages,
@@ -1633,9 +1780,6 @@ static int read_partial_message_bio(struct ceph_connection *con,
        void *p;
        int ret, left;
 
-       if (IS_ERR(bv))
-               return PTR_ERR(bv);
-
        left = min((int)(data_len - con->in_msg_pos.data_pos),
                   (int)(bv->bv_len - con->in_msg_pos.page_pos));
 
@@ -1672,7 +1816,6 @@ static int read_partial_message(struct ceph_connection *con)
        int ret;
        unsigned int front_len, middle_len, data_len;
        bool do_datacrc = !con->msgr->nocrc;
-       int skip;
        u64 seq;
        u32 crc;
 
@@ -1723,10 +1866,13 @@ static int read_partial_message(struct ceph_connection *con)
 
        /* allocate message? */
        if (!con->in_msg) {
+               int skip = 0;
+
                dout("got hdr type %d front %d data %d\n", con->in_hdr.type,
                     con->in_hdr.front_len, con->in_hdr.data_len);
-               skip = 0;
-               con->in_msg = ceph_alloc_msg(con, &con->in_hdr, &skip);
+               ret = ceph_con_in_msg_alloc(con, &skip);
+               if (ret < 0)
+                       return ret;
                if (skip) {
                        /* skip this message */
                        dout("alloc_msg said skip message\n");
@@ -1737,11 +1883,9 @@ static int read_partial_message(struct ceph_connection *con)
                        con->in_seq++;
                        return 0;
                }
-               if (!con->in_msg) {
-                       con->error_msg =
-                               "error allocating memory for incoming message";
-                       return -ENOMEM;
-               }
+
+               BUG_ON(!con->in_msg);
+               BUG_ON(con->in_msg->con != con);
                m = con->in_msg;
                m->front.iov_len = 0;    /* haven't read it yet */
                if (m->middle)
@@ -1753,6 +1897,11 @@ static int read_partial_message(struct ceph_connection *con)
                else
                        con->in_msg_pos.page_pos = 0;
                con->in_msg_pos.data_pos = 0;
+
+#ifdef CONFIG_BLOCK
+               if (m->bio)
+                       init_bio_iter(m->bio, &m->bio_iter, &m->bio_seg);
+#endif
        }
 
        /* front */
@@ -1769,10 +1918,6 @@ static int read_partial_message(struct ceph_connection *con)
                if (ret <= 0)
                        return ret;
        }
-#ifdef CONFIG_BLOCK
-       if (m->bio && !m->bio_iter)
-               init_bio_iter(m->bio, &m->bio_iter, &m->bio_seg);
-#endif
 
        /* (page) data */
        while (con->in_msg_pos.data_pos < data_len) {
@@ -1783,7 +1928,7 @@ static int read_partial_message(struct ceph_connection *con)
                                return ret;
 #ifdef CONFIG_BLOCK
                } else if (m->bio) {
-
+                       BUG_ON(!m->bio_iter);
                        ret = read_partial_message_bio(con,
                                                 &m->bio_iter, &m->bio_seg,
                                                 data_len, do_datacrc);
@@ -1837,8 +1982,11 @@ static void process_message(struct ceph_connection *con)
 {
        struct ceph_msg *msg;
 
+       BUG_ON(con->in_msg->con != con);
+       con->in_msg->con = NULL;
        msg = con->in_msg;
        con->in_msg = NULL;
+       con->ops->put(con);
 
        /* if first message, set peer_name */
        if (con->peer_name.type == 0)
@@ -1858,7 +2006,6 @@ static void process_message(struct ceph_connection *con)
        con->ops->dispatch(con, msg);
 
        mutex_lock(&con->mutex);
-       prepare_read_tag(con);
 }
 
 
@@ -1870,22 +2017,19 @@ static int try_write(struct ceph_connection *con)
 {
        int ret = 1;
 
-       dout("try_write start %p state %lu nref %d\n", con, con->state,
-            atomic_read(&con->nref));
+       dout("try_write start %p state %lu\n", con, con->state);
 
 more:
        dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes);
 
        /* open the socket first? */
-       if (con->sock == NULL) {
-               ceph_con_out_kvec_reset(con);
+       if (con->state == CON_STATE_PREOPEN) {
+               BUG_ON(con->sock);
+               con->state = CON_STATE_CONNECTING;
+
+               con_out_kvec_reset(con);
                prepare_write_banner(con);
-               ret = prepare_write_connect(con);
-               if (ret < 0)
-                       goto out;
                prepare_read_banner(con);
-               set_bit(CONNECTING, &con->state);
-               clear_bit(NEGOTIATING, &con->state);
 
                BUG_ON(con->in_msg);
                con->in_tag = CEPH_MSGR_TAG_READY;
@@ -1932,7 +2076,7 @@ more_kvec:
        }
 
 do_next:
-       if (!test_bit(CONNECTING, &con->state)) {
+       if (con->state == CON_STATE_OPEN) {
                /* is anything else pending? */
                if (!list_empty(&con->out_queue)) {
                        prepare_write_message(con);
@@ -1942,14 +2086,15 @@ do_next:
                        prepare_write_ack(con);
                        goto more;
                }
-               if (test_and_clear_bit(KEEPALIVE_PENDING, &con->state)) {
+               if (test_and_clear_bit(CON_FLAG_KEEPALIVE_PENDING,
+                                      &con->flags)) {
                        prepare_write_keepalive(con);
                        goto more;
                }
        }
 
        /* Nothing to do! */
-       clear_bit(WRITE_PENDING, &con->state);
+       clear_bit(CON_FLAG_WRITE_PENDING, &con->flags);
        dout("try_write nothing else to write.\n");
        ret = 0;
 out:
@@ -1966,38 +2111,42 @@ static int try_read(struct ceph_connection *con)
 {
        int ret = -1;
 
-       if (!con->sock)
-               return 0;
-
-       if (test_bit(STANDBY, &con->state))
+more:
+       dout("try_read start on %p state %lu\n", con, con->state);
+       if (con->state != CON_STATE_CONNECTING &&
+           con->state != CON_STATE_NEGOTIATING &&
+           con->state != CON_STATE_OPEN)
                return 0;
 
-       dout("try_read start on %p\n", con);
+       BUG_ON(!con->sock);
 
-more:
        dout("try_read tag %d in_base_pos %d\n", (int)con->in_tag,
             con->in_base_pos);
 
-       /*
-        * process_connect and process_message drop and re-take
-        * con->mutex.  make sure we handle a racing close or reopen.
-        */
-       if (test_bit(CLOSED, &con->state) ||
-           test_bit(OPENING, &con->state)) {
-               ret = -EAGAIN;
+       if (con->state == CON_STATE_CONNECTING) {
+               dout("try_read connecting\n");
+               ret = read_partial_banner(con);
+               if (ret <= 0)
+                       goto out;
+               ret = process_banner(con);
+               if (ret < 0)
+                       goto out;
+
+               BUG_ON(con->state != CON_STATE_CONNECTING);
+               con->state = CON_STATE_NEGOTIATING;
+
+               /* Banner is good, exchange connection info */
+               ret = prepare_write_connect(con);
+               if (ret < 0)
+                       goto out;
+               prepare_read_connect(con);
+
+               /* Send connection info before awaiting response */
                goto out;
        }
 
-       if (test_bit(CONNECTING, &con->state)) {
-               if (!test_bit(NEGOTIATING, &con->state)) {
-                       dout("try_read connecting\n");
-                       ret = read_partial_banner(con);
-                       if (ret <= 0)
-                               goto out;
-                       ret = process_banner(con);
-                       if (ret < 0)
-                               goto out;
-               }
+       if (con->state == CON_STATE_NEGOTIATING) {
+               dout("try_read negotiating\n");
                ret = read_partial_connect(con);
                if (ret <= 0)
                        goto out;
@@ -2007,6 +2156,8 @@ more:
                goto more;
        }
 
+       BUG_ON(con->state != CON_STATE_OPEN);
+
        if (con->in_base_pos < 0) {
                /*
                 * skipping + discarding content.
@@ -2040,7 +2191,8 @@ more:
                        prepare_read_ack(con);
                        break;
                case CEPH_MSGR_TAG_CLOSE:
-                       set_bit(CLOSED, &con->state);   /* fixme */
+                       con_close_socket(con);
+                       con->state = CON_STATE_CLOSED;
                        goto out;
                default:
                        goto bad_tag;
@@ -2063,6 +2215,8 @@ more:
                if (con->in_tag == CEPH_MSGR_TAG_READY)
                        goto more;
                process_message(con);
+               if (con->state == CON_STATE_OPEN)
+                       prepare_read_tag(con);
                goto more;
        }
        if (con->in_tag == CEPH_MSGR_TAG_ACK) {
@@ -2091,12 +2245,6 @@ bad_tag:
  */
 static void queue_con(struct ceph_connection *con)
 {
-       if (test_bit(DEAD, &con->state)) {
-               dout("queue_con %p ignoring: DEAD\n",
-                    con);
-               return;
-       }
-
        if (!con->ops->get(con)) {
                dout("queue_con %p ref count 0\n", con);
                return;
@@ -2121,7 +2269,26 @@ static void con_work(struct work_struct *work)
 
        mutex_lock(&con->mutex);
 restart:
-       if (test_and_clear_bit(BACKOFF, &con->state)) {
+       if (test_and_clear_bit(CON_FLAG_SOCK_CLOSED, &con->flags)) {
+               switch (con->state) {
+               case CON_STATE_CONNECTING:
+                       con->error_msg = "connection failed";
+                       break;
+               case CON_STATE_NEGOTIATING:
+                       con->error_msg = "negotiation failed";
+                       break;
+               case CON_STATE_OPEN:
+                       con->error_msg = "socket closed";
+                       break;
+               default:
+                       dout("unrecognized con state %d\n", (int)con->state);
+                       con->error_msg = "unrecognized con state";
+                       BUG();
+               }
+               goto fault;
+       }
+
+       if (test_and_clear_bit(CON_FLAG_BACKOFF, &con->flags)) {
                dout("con_work %p backing off\n", con);
                if (queue_delayed_work(ceph_msgr_wq, &con->work,
                                       round_jiffies_relative(con->delay))) {
@@ -2135,35 +2302,35 @@ restart:
                }
        }
 
-       if (test_bit(STANDBY, &con->state)) {
+       if (con->state == CON_STATE_STANDBY) {
                dout("con_work %p STANDBY\n", con);
                goto done;
        }
-       if (test_bit(CLOSED, &con->state)) { /* e.g. if we are replaced */
-               dout("con_work CLOSED\n");
-               con_close_socket(con);
+       if (con->state == CON_STATE_CLOSED) {
+               dout("con_work %p CLOSED\n", con);
+               BUG_ON(con->sock);
                goto done;
        }
-       if (test_and_clear_bit(OPENING, &con->state)) {
-               /* reopen w/ new peer */
+       if (con->state == CON_STATE_PREOPEN) {
                dout("con_work OPENING\n");
-               con_close_socket(con);
+               BUG_ON(con->sock);
        }
 
-       if (test_and_clear_bit(SOCK_CLOSED, &con->state))
-               goto fault;
-
        ret = try_read(con);
        if (ret == -EAGAIN)
                goto restart;
-       if (ret < 0)
+       if (ret < 0) {
+               con->error_msg = "socket error on read";
                goto fault;
+       }
 
        ret = try_write(con);
        if (ret == -EAGAIN)
                goto restart;
-       if (ret < 0)
+       if (ret < 0) {
+               con->error_msg = "socket error on write";
                goto fault;
+       }
 
 done:
        mutex_unlock(&con->mutex);
@@ -2172,7 +2339,6 @@ done_unlocked:
        return;
 
 fault:
-       mutex_unlock(&con->mutex);
        ceph_fault(con);     /* error/fault path */
        goto done_unlocked;
 }
@@ -2183,26 +2349,31 @@ fault:
  * exponential backoff
  */
 static void ceph_fault(struct ceph_connection *con)
+       __releases(con->mutex)
 {
        pr_err("%s%lld %s %s\n", ENTITY_NAME(con->peer_name),
               ceph_pr_addr(&con->peer_addr.in_addr), con->error_msg);
        dout("fault %p state %lu to peer %s\n",
             con, con->state, ceph_pr_addr(&con->peer_addr.in_addr));
 
-       if (test_bit(LOSSYTX, &con->state)) {
-               dout("fault on LOSSYTX channel\n");
-               goto out;
-       }
-
-       mutex_lock(&con->mutex);
-       if (test_bit(CLOSED, &con->state))
-               goto out_unlock;
+       BUG_ON(con->state != CON_STATE_CONNECTING &&
+              con->state != CON_STATE_NEGOTIATING &&
+              con->state != CON_STATE_OPEN);
 
        con_close_socket(con);
 
+       if (test_bit(CON_FLAG_LOSSYTX, &con->flags)) {
+               dout("fault on LOSSYTX channel, marking CLOSED\n");
+               con->state = CON_STATE_CLOSED;
+               goto out_unlock;
+       }
+
        if (con->in_msg) {
+               BUG_ON(con->in_msg->con != con);
+               con->in_msg->con = NULL;
                ceph_msg_put(con->in_msg);
                con->in_msg = NULL;
+               con->ops->put(con);
        }
 
        /* Requeue anything that hasn't been acked */
@@ -2211,12 +2382,13 @@ static void ceph_fault(struct ceph_connection *con)
        /* If there are no messages queued or keepalive pending, place
         * the connection in a STANDBY state */
        if (list_empty(&con->out_queue) &&
-           !test_bit(KEEPALIVE_PENDING, &con->state)) {
+           !test_bit(CON_FLAG_KEEPALIVE_PENDING, &con->flags)) {
                dout("fault %p setting STANDBY clearing WRITE_PENDING\n", con);
-               clear_bit(WRITE_PENDING, &con->state);
-               set_bit(STANDBY, &con->state);
+               clear_bit(CON_FLAG_WRITE_PENDING, &con->flags);
+               con->state = CON_STATE_STANDBY;
        } else {
                /* retry after a delay. */
+               con->state = CON_STATE_PREOPEN;
                if (con->delay == 0)
                        con->delay = BASE_DELAY_INTERVAL;
                else if (con->delay < MAX_DELAY_INTERVAL)
@@ -2237,13 +2409,12 @@ static void ceph_fault(struct ceph_connection *con)
                         * that when con_work restarts we schedule the
                         * delay then.
                         */
-                       set_bit(BACKOFF, &con->state);
+                       set_bit(CON_FLAG_BACKOFF, &con->flags);
                }
        }
 
 out_unlock:
        mutex_unlock(&con->mutex);
-out:
        /*
         * in case we faulted due to authentication, invalidate our
         * current tickets so that we can get new ones.
@@ -2260,18 +2431,14 @@ out:
 
 
 /*
- * create a new messenger instance
+ * initialize a new messenger instance
  */
-struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr,
-                                            u32 supported_features,
-                                            u32 required_features)
+void ceph_messenger_init(struct ceph_messenger *msgr,
+                       struct ceph_entity_addr *myaddr,
+                       u32 supported_features,
+                       u32 required_features,
+                       bool nocrc)
 {
-       struct ceph_messenger *msgr;
-
-       msgr = kzalloc(sizeof(*msgr), GFP_KERNEL);
-       if (msgr == NULL)
-               return ERR_PTR(-ENOMEM);
-
        msgr->supported_features = supported_features;
        msgr->required_features = required_features;
 
@@ -2284,30 +2451,23 @@ struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr,
        msgr->inst.addr.type = 0;
        get_random_bytes(&msgr->inst.addr.nonce, sizeof(msgr->inst.addr.nonce));
        encode_my_addr(msgr);
+       msgr->nocrc = nocrc;
 
-       dout("messenger_create %p\n", msgr);
-       return msgr;
-}
-EXPORT_SYMBOL(ceph_messenger_create);
+       atomic_set(&msgr->stopping, 0);
 
-void ceph_messenger_destroy(struct ceph_messenger *msgr)
-{
-       dout("destroy %p\n", msgr);
-       kfree(msgr);
-       dout("destroyed messenger %p\n", msgr);
+       dout("%s %p\n", __func__, msgr);
 }
-EXPORT_SYMBOL(ceph_messenger_destroy);
+EXPORT_SYMBOL(ceph_messenger_init);
 
 static void clear_standby(struct ceph_connection *con)
 {
        /* come back from STANDBY? */
-       if (test_and_clear_bit(STANDBY, &con->state)) {
-               mutex_lock(&con->mutex);
+       if (con->state == CON_STATE_STANDBY) {
                dout("clear_standby %p and ++connect_seq\n", con);
+               con->state = CON_STATE_PREOPEN;
                con->connect_seq++;
-               WARN_ON(test_bit(WRITE_PENDING, &con->state));
-               WARN_ON(test_bit(KEEPALIVE_PENDING, &con->state));
-               mutex_unlock(&con->mutex);
+               WARN_ON(test_bit(CON_FLAG_WRITE_PENDING, &con->flags));
+               WARN_ON(test_bit(CON_FLAG_KEEPALIVE_PENDING, &con->flags));
        }
 }
 
@@ -2316,21 +2476,24 @@ static void clear_standby(struct ceph_connection *con)
  */
 void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg)
 {
-       if (test_bit(CLOSED, &con->state)) {
-               dout("con_send %p closed, dropping %p\n", con, msg);
-               ceph_msg_put(msg);
-               return;
-       }
-
        /* set src+dst */
        msg->hdr.src = con->msgr->inst.name;
-
        BUG_ON(msg->front.iov_len != le32_to_cpu(msg->hdr.front_len));
-
        msg->needs_out_seq = true;
 
-       /* queue */
        mutex_lock(&con->mutex);
+
+       if (con->state == CON_STATE_CLOSED) {
+               dout("con_send %p closed, dropping %p\n", con, msg);
+               ceph_msg_put(msg);
+               mutex_unlock(&con->mutex);
+               return;
+       }
+
+       BUG_ON(msg->con != NULL);
+       msg->con = con->ops->get(con);
+       BUG_ON(msg->con == NULL);
+
        BUG_ON(!list_empty(&msg->list_head));
        list_add_tail(&msg->list_head, &con->out_queue);
        dout("----- %p to %s%lld %d=%s len %d+%d+%d -----\n", msg,
@@ -2339,12 +2502,13 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg)
             le32_to_cpu(msg->hdr.front_len),
             le32_to_cpu(msg->hdr.middle_len),
             le32_to_cpu(msg->hdr.data_len));
+
+       clear_standby(con);
        mutex_unlock(&con->mutex);
 
        /* if there wasn't anything waiting to send before, queue
         * new work */
-       clear_standby(con);
-       if (test_and_set_bit(WRITE_PENDING, &con->state) == 0)
+       if (test_and_set_bit(CON_FLAG_WRITE_PENDING, &con->flags) == 0)
                queue_con(con);
 }
 EXPORT_SYMBOL(ceph_con_send);
@@ -2352,24 +2516,34 @@ EXPORT_SYMBOL(ceph_con_send);
 /*
  * Revoke a message that was previously queued for send
  */
-void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg)
+void ceph_msg_revoke(struct ceph_msg *msg)
 {
+       struct ceph_connection *con = msg->con;
+
+       if (!con)
+               return;         /* Message not in our possession */
+
        mutex_lock(&con->mutex);
        if (!list_empty(&msg->list_head)) {
-               dout("con_revoke %p msg %p - was on queue\n", con, msg);
+               dout("%s %p msg %p - was on queue\n", __func__, con, msg);
                list_del_init(&msg->list_head);
-               ceph_msg_put(msg);
+               BUG_ON(msg->con == NULL);
+               msg->con->ops->put(msg->con);
+               msg->con = NULL;
                msg->hdr.seq = 0;
+
+               ceph_msg_put(msg);
        }
        if (con->out_msg == msg) {
-               dout("con_revoke %p msg %p - was sending\n", con, msg);
+               dout("%s %p msg %p - was sending\n", __func__, con, msg);
                con->out_msg = NULL;
                if (con->out_kvec_is_msg) {
                        con->out_skip = con->out_kvec_bytes;
                        con->out_kvec_is_msg = false;
                }
-               ceph_msg_put(msg);
                msg->hdr.seq = 0;
+
+               ceph_msg_put(msg);
        }
        mutex_unlock(&con->mutex);
 }
@@ -2377,17 +2551,27 @@ void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg)
 /*
  * Revoke a message that we may be reading data into
  */
-void ceph_con_revoke_message(struct ceph_connection *con, struct ceph_msg *msg)
+void ceph_msg_revoke_incoming(struct ceph_msg *msg)
 {
+       struct ceph_connection *con;
+
+       BUG_ON(msg == NULL);
+       if (!msg->con) {
+               dout("%s msg %p null con\n", __func__, msg);
+
+               return;         /* Message not in our possession */
+       }
+
+       con = msg->con;
        mutex_lock(&con->mutex);
-       if (con->in_msg && con->in_msg == msg) {
+       if (con->in_msg == msg) {
                unsigned int front_len = le32_to_cpu(con->in_hdr.front_len);
                unsigned int middle_len = le32_to_cpu(con->in_hdr.middle_len);
                unsigned int data_len = le32_to_cpu(con->in_hdr.data_len);
 
                /* skip rest of message */
-               dout("con_revoke_pages %p msg %p revoked\n", con, msg);
-                       con->in_base_pos = con->in_base_pos -
+               dout("%s %p msg %p revoked\n", __func__, con, msg);
+               con->in_base_pos = con->in_base_pos -
                                sizeof(struct ceph_msg_header) -
                                front_len -
                                middle_len -
@@ -2398,8 +2582,8 @@ void ceph_con_revoke_message(struct ceph_connection *con, struct ceph_msg *msg)
                con->in_tag = CEPH_MSGR_TAG_READY;
                con->in_seq++;
        } else {
-               dout("con_revoke_pages %p msg %p pages %p no-op\n",
-                    con, con->in_msg, msg);
+               dout("%s %p in_msg %p msg %p no-op\n",
+                    __func__, con, con->in_msg, msg);
        }
        mutex_unlock(&con->mutex);
 }
@@ -2410,9 +2594,11 @@ void ceph_con_revoke_message(struct ceph_connection *con, struct ceph_msg *msg)
 void ceph_con_keepalive(struct ceph_connection *con)
 {
        dout("con_keepalive %p\n", con);
+       mutex_lock(&con->mutex);
        clear_standby(con);
-       if (test_and_set_bit(KEEPALIVE_PENDING, &con->state) == 0 &&
-           test_and_set_bit(WRITE_PENDING, &con->state) == 0)
+       mutex_unlock(&con->mutex);
+       if (test_and_set_bit(CON_FLAG_KEEPALIVE_PENDING, &con->flags) == 0 &&
+           test_and_set_bit(CON_FLAG_WRITE_PENDING, &con->flags) == 0)
                queue_con(con);
 }
 EXPORT_SYMBOL(ceph_con_keepalive);
@@ -2431,6 +2617,8 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags,
        if (m == NULL)
                goto out;
        kref_init(&m->kref);
+
+       m->con = NULL;
        INIT_LIST_HEAD(&m->list_head);
 
        m->hdr.tid = 0;
@@ -2526,46 +2714,77 @@ static int ceph_alloc_middle(struct ceph_connection *con, struct ceph_msg *msg)
 }
 
 /*
- * Generic message allocator, for incoming messages.
+ * Allocate a message for receiving an incoming message on a
+ * connection, and save the result in con->in_msg.  Uses the
+ * connection's private alloc_msg op if available.
+ *
+ * Returns 0 on success, or a negative error code.
+ *
+ * On success, if we set *skip = 1:
+ *  - the next message should be skipped and ignored.
+ *  - con->in_msg == NULL
+ * or if we set *skip = 0:
+ *  - con->in_msg is non-null.
+ * On error (ENOMEM, EAGAIN, ...),
+ *  - con->in_msg == NULL
  */
-static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
-                               struct ceph_msg_header *hdr,
-                               int *skip)
+static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip)
 {
+       struct ceph_msg_header *hdr = &con->in_hdr;
        int type = le16_to_cpu(hdr->type);
        int front_len = le32_to_cpu(hdr->front_len);
        int middle_len = le32_to_cpu(hdr->middle_len);
-       struct ceph_msg *msg = NULL;
-       int ret;
+       int ret = 0;
+
+       BUG_ON(con->in_msg != NULL);
 
        if (con->ops->alloc_msg) {
+               struct ceph_msg *msg;
+
                mutex_unlock(&con->mutex);
                msg = con->ops->alloc_msg(con, hdr, skip);
                mutex_lock(&con->mutex);
-               if (!msg || *skip)
-                       return NULL;
+               if (con->state != CON_STATE_OPEN) {
+                       ceph_msg_put(msg);
+                       return -EAGAIN;
+               }
+               con->in_msg = msg;
+               if (con->in_msg) {
+                       con->in_msg->con = con->ops->get(con);
+                       BUG_ON(con->in_msg->con == NULL);
+               }
+               if (*skip) {
+                       con->in_msg = NULL;
+                       return 0;
+               }
+               if (!con->in_msg) {
+                       con->error_msg =
+                               "error allocating memory for incoming message";
+                       return -ENOMEM;
+               }
        }
-       if (!msg) {
-               *skip = 0;
-               msg = ceph_msg_new(type, front_len, GFP_NOFS, false);
-               if (!msg) {
+       if (!con->in_msg) {
+               con->in_msg = ceph_msg_new(type, front_len, GFP_NOFS, false);
+               if (!con->in_msg) {
                        pr_err("unable to allocate msg type %d len %d\n",
                               type, front_len);
-                       return NULL;
+                       return -ENOMEM;
                }
-               msg->page_alignment = le16_to_cpu(hdr->data_off);
+               con->in_msg->con = con->ops->get(con);
+               BUG_ON(con->in_msg->con == NULL);
+               con->in_msg->page_alignment = le16_to_cpu(hdr->data_off);
        }
-       memcpy(&msg->hdr, &con->in_hdr, sizeof(con->in_hdr));
+       memcpy(&con->in_msg->hdr, &con->in_hdr, sizeof(con->in_hdr));
 
-       if (middle_len && !msg->middle) {
-               ret = ceph_alloc_middle(con, msg);
+       if (middle_len && !con->in_msg->middle) {
+               ret = ceph_alloc_middle(con, con->in_msg);
                if (ret < 0) {
-                       ceph_msg_put(msg);
-                       return NULL;
+                       ceph_msg_put(con->in_msg);
+                       con->in_msg = NULL;
                }
        }
 
-       return msg;
+       return ret;
 }
 
 
index d0649a9655be3b7bbf1baaa03220548c74156ff0..105d533b55f3bcc3e8a2e7a82b80a6459cbb9363 100644 (file)
@@ -106,9 +106,9 @@ static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len)
        monc->pending_auth = 1;
        monc->m_auth->front.iov_len = len;
        monc->m_auth->hdr.front_len = cpu_to_le32(len);
-       ceph_con_revoke(monc->con, monc->m_auth);
+       ceph_msg_revoke(monc->m_auth);
        ceph_msg_get(monc->m_auth);  /* keep our ref */
-       ceph_con_send(monc->con, monc->m_auth);
+       ceph_con_send(&monc->con, monc->m_auth);
 }
 
 /*
@@ -117,8 +117,11 @@ static void __send_prepared_auth_request(struct ceph_mon_client *monc, int len)
 static void __close_session(struct ceph_mon_client *monc)
 {
        dout("__close_session closing mon%d\n", monc->cur_mon);
-       ceph_con_revoke(monc->con, monc->m_auth);
-       ceph_con_close(monc->con);
+       ceph_msg_revoke(monc->m_auth);
+       ceph_msg_revoke_incoming(monc->m_auth_reply);
+       ceph_msg_revoke(monc->m_subscribe);
+       ceph_msg_revoke_incoming(monc->m_subscribe_ack);
+       ceph_con_close(&monc->con);
        monc->cur_mon = -1;
        monc->pending_auth = 0;
        ceph_auth_reset(monc->auth);
@@ -142,9 +145,8 @@ static int __open_session(struct ceph_mon_client *monc)
                monc->want_next_osdmap = !!monc->want_next_osdmap;
 
                dout("open_session mon%d opening\n", monc->cur_mon);
-               monc->con->peer_name.type = CEPH_ENTITY_TYPE_MON;
-               monc->con->peer_name.num = cpu_to_le64(monc->cur_mon);
-               ceph_con_open(monc->con,
+               ceph_con_open(&monc->con,
+                             CEPH_ENTITY_TYPE_MON, monc->cur_mon,
                              &monc->monmap->mon_inst[monc->cur_mon].addr);
 
                /* initiatiate authentication handshake */
@@ -226,8 +228,8 @@ static void __send_subscribe(struct ceph_mon_client *monc)
 
                msg->front.iov_len = p - msg->front.iov_base;
                msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
-               ceph_con_revoke(monc->con, msg);
-               ceph_con_send(monc->con, ceph_msg_get(msg));
+               ceph_msg_revoke(msg);
+               ceph_con_send(&monc->con, ceph_msg_get(msg));
 
                monc->sub_sent = jiffies | 1;  /* never 0 */
        }
@@ -247,7 +249,7 @@ static void handle_subscribe_ack(struct ceph_mon_client *monc,
        if (monc->hunting) {
                pr_info("mon%d %s session established\n",
                        monc->cur_mon,
-                       ceph_pr_addr(&monc->con->peer_addr.in_addr));
+                       ceph_pr_addr(&monc->con.peer_addr.in_addr));
                monc->hunting = false;
        }
        dout("handle_subscribe_ack after %d seconds\n", seconds);
@@ -439,6 +441,7 @@ static struct ceph_msg *get_generic_reply(struct ceph_connection *con,
                m = NULL;
        } else {
                dout("get_generic_reply %lld got %p\n", tid, req->reply);
+               *skip = 0;
                m = ceph_msg_get(req->reply);
                /*
                 * we don't need to track the connection reading into
@@ -461,7 +464,7 @@ static int do_generic_request(struct ceph_mon_client *monc,
        req->request->hdr.tid = cpu_to_le64(req->tid);
        __insert_generic_request(monc, req);
        monc->num_generic_requests++;
-       ceph_con_send(monc->con, ceph_msg_get(req->request));
+       ceph_con_send(&monc->con, ceph_msg_get(req->request));
        mutex_unlock(&monc->mutex);
 
        err = wait_for_completion_interruptible(&req->completion);
@@ -684,8 +687,9 @@ static void __resend_generic_request(struct ceph_mon_client *monc)
 
        for (p = rb_first(&monc->generic_request_tree); p; p = rb_next(p)) {
                req = rb_entry(p, struct ceph_mon_generic_request, node);
-               ceph_con_revoke(monc->con, req->request);
-               ceph_con_send(monc->con, ceph_msg_get(req->request));
+               ceph_msg_revoke(req->request);
+               ceph_msg_revoke_incoming(req->reply);
+               ceph_con_send(&monc->con, ceph_msg_get(req->request));
        }
 }
 
@@ -705,7 +709,7 @@ static void delayed_work(struct work_struct *work)
                __close_session(monc);
                __open_session(monc);  /* continue hunting */
        } else {
-               ceph_con_keepalive(monc->con);
+               ceph_con_keepalive(&monc->con);
 
                __validate_auth(monc);
 
@@ -760,19 +764,12 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
                goto out;
 
        /* connection */
-       monc->con = kmalloc(sizeof(*monc->con), GFP_KERNEL);
-       if (!monc->con)
-               goto out_monmap;
-       ceph_con_init(monc->client->msgr, monc->con);
-       monc->con->private = monc;
-       monc->con->ops = &mon_con_ops;
-
        /* authentication */
        monc->auth = ceph_auth_init(cl->options->name,
                                    cl->options->key);
        if (IS_ERR(monc->auth)) {
                err = PTR_ERR(monc->auth);
-               goto out_con;
+               goto out_monmap;
        }
        monc->auth->want_keys =
                CEPH_ENTITY_TYPE_AUTH | CEPH_ENTITY_TYPE_MON |
@@ -801,6 +798,9 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
        if (!monc->m_auth)
                goto out_auth_reply;
 
+       ceph_con_init(&monc->con, monc, &mon_con_ops,
+                     &monc->client->msgr);
+
        monc->cur_mon = -1;
        monc->hunting = true;
        monc->sub_renew_after = jiffies;
@@ -824,8 +824,6 @@ out_subscribe_ack:
        ceph_msg_put(monc->m_subscribe_ack);
 out_auth:
        ceph_auth_destroy(monc->auth);
-out_con:
-       monc->con->ops->put(monc->con);
 out_monmap:
        kfree(monc->monmap);
 out:
@@ -841,10 +839,6 @@ void ceph_monc_stop(struct ceph_mon_client *monc)
        mutex_lock(&monc->mutex);
        __close_session(monc);
 
-       monc->con->private = NULL;
-       monc->con->ops->put(monc->con);
-       monc->con = NULL;
-
        mutex_unlock(&monc->mutex);
 
        /*
@@ -888,8 +882,8 @@ static void handle_auth_reply(struct ceph_mon_client *monc,
        } else if (!was_auth && monc->auth->ops->is_authenticated(monc->auth)) {
                dout("authenticated, starting session\n");
 
-               monc->client->msgr->inst.name.type = CEPH_ENTITY_TYPE_CLIENT;
-               monc->client->msgr->inst.name.num =
+               monc->client->msgr.inst.name.type = CEPH_ENTITY_TYPE_CLIENT;
+               monc->client->msgr.inst.name.num =
                                        cpu_to_le64(monc->auth->global_id);
 
                __send_subscribe(monc);
@@ -1000,6 +994,8 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
        case CEPH_MSG_MDS_MAP:
        case CEPH_MSG_OSD_MAP:
                m = ceph_msg_new(type, front_len, GFP_NOFS, false);
+               if (!m)
+                       return NULL;    /* ENOMEM--return skip == 0 */
                break;
        }
 
@@ -1029,7 +1025,7 @@ static void mon_fault(struct ceph_connection *con)
        if (!monc->hunting)
                pr_info("mon%d %s session lost, "
                        "hunting for new mon\n", monc->cur_mon,
-                       ceph_pr_addr(&monc->con->peer_addr.in_addr));
+                       ceph_pr_addr(&monc->con.peer_addr.in_addr));
 
        __close_session(monc);
        if (!monc->hunting) {
@@ -1044,9 +1040,23 @@ out:
        mutex_unlock(&monc->mutex);
 }
 
+/*
+ * We can ignore refcounting on the connection struct, as all references
+ * will come from the messenger workqueue, which is drained prior to
+ * mon_client destruction.
+ */
+static struct ceph_connection *con_get(struct ceph_connection *con)
+{
+       return con;
+}
+
+static void con_put(struct ceph_connection *con)
+{
+}
+
 static const struct ceph_connection_operations mon_con_ops = {
-       .get = ceph_con_get,
-       .put = ceph_con_put,
+       .get = con_get,
+       .put = con_put,
        .dispatch = dispatch,
        .fault = mon_fault,
        .alloc_msg = mon_alloc_msg,
index 11d5f4196a73cfeef3492389c76f9f285c50188d..ddec1c10ac80fc3b993cdc7ba5524e317382bd04 100644 (file)
@@ -12,7 +12,7 @@ static void *msgpool_alloc(gfp_t gfp_mask, void *arg)
        struct ceph_msgpool *pool = arg;
        struct ceph_msg *msg;
 
-       msg = ceph_msg_new(0, pool->front_len, gfp_mask, true);
+       msg = ceph_msg_new(pool->type, pool->front_len, gfp_mask, true);
        if (!msg) {
                dout("msgpool_alloc %s failed\n", pool->name);
        } else {
@@ -32,10 +32,11 @@ static void msgpool_free(void *element, void *arg)
        ceph_msg_put(msg);
 }
 
-int ceph_msgpool_init(struct ceph_msgpool *pool,
+int ceph_msgpool_init(struct ceph_msgpool *pool, int type,
                      int front_len, int size, bool blocking, const char *name)
 {
        dout("msgpool %s init\n", name);
+       pool->type = type;
        pool->front_len = front_len;
        pool->pool = mempool_create(size, msgpool_alloc, msgpool_free, pool);
        if (!pool->pool)
@@ -61,7 +62,7 @@ struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool,
                WARN_ON(1);
 
                /* try to alloc a fresh message */
-               return ceph_msg_new(0, front_len, GFP_NOFS, false);
+               return ceph_msg_new(pool->type, front_len, GFP_NOFS, false);
        }
 
        msg = mempool_alloc(pool->pool, GFP_NOFS);
index ca59e66c9787303805519f2bf325cc5d5817ff55..42119c05e82c023b777298e9f41b6a6ebbade0cb 100644 (file)
@@ -140,10 +140,9 @@ void ceph_osdc_release_request(struct kref *kref)
        if (req->r_request)
                ceph_msg_put(req->r_request);
        if (req->r_con_filling_msg) {
-               dout("release_request revoking pages %p from con %p\n",
+               dout("%s revoking pages %p from con %p\n", __func__,
                     req->r_pages, req->r_con_filling_msg);
-               ceph_con_revoke_message(req->r_con_filling_msg,
-                                     req->r_reply);
+               ceph_msg_revoke_incoming(req->r_reply);
                req->r_con_filling_msg->ops->put(req->r_con_filling_msg);
        }
        if (req->r_reply)
@@ -214,10 +213,13 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
        kref_init(&req->r_kref);
        init_completion(&req->r_completion);
        init_completion(&req->r_safe_completion);
+       rb_init_node(&req->r_node);
        INIT_LIST_HEAD(&req->r_unsafe_item);
        INIT_LIST_HEAD(&req->r_linger_item);
        INIT_LIST_HEAD(&req->r_linger_osd);
        INIT_LIST_HEAD(&req->r_req_lru_item);
+       INIT_LIST_HEAD(&req->r_osd_item);
+
        req->r_flags = flags;
 
        WARN_ON((flags & (CEPH_OSD_FLAG_READ|CEPH_OSD_FLAG_WRITE)) == 0);
@@ -243,6 +245,7 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
                }
                ceph_pagelist_init(req->r_trail);
        }
+
        /* create request message; allow space for oid */
        msg_size += MAX_OBJ_NAME_SIZE;
        if (snapc)
@@ -256,7 +259,6 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
                return NULL;
        }
 
-       msg->hdr.type = cpu_to_le16(CEPH_MSG_OSD_OP);
        memset(msg->front.iov_base, 0, msg->front.iov_len);
 
        req->r_request = msg;
@@ -624,7 +626,7 @@ static void osd_reset(struct ceph_connection *con)
 /*
  * Track open sessions with osds.
  */
-static struct ceph_osd *create_osd(struct ceph_osd_client *osdc)
+static struct ceph_osd *create_osd(struct ceph_osd_client *osdc, int onum)
 {
        struct ceph_osd *osd;
 
@@ -634,15 +636,13 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc)
 
        atomic_set(&osd->o_ref, 1);
        osd->o_osdc = osdc;
+       osd->o_osd = onum;
        INIT_LIST_HEAD(&osd->o_requests);
        INIT_LIST_HEAD(&osd->o_linger_requests);
        INIT_LIST_HEAD(&osd->o_osd_lru);
        osd->o_incarnation = 1;
 
-       ceph_con_init(osdc->client->msgr, &osd->o_con);
-       osd->o_con.private = osd;
-       osd->o_con.ops = &osd_con_ops;
-       osd->o_con.peer_name.type = CEPH_ENTITY_TYPE_OSD;
+       ceph_con_init(&osd->o_con, osd, &osd_con_ops, &osdc->client->msgr);
 
        INIT_LIST_HEAD(&osd->o_keepalive_item);
        return osd;
@@ -688,7 +688,7 @@ static void __remove_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd)
 
 static void remove_all_osds(struct ceph_osd_client *osdc)
 {
-       dout("__remove_old_osds %p\n", osdc);
+       dout("%s %p\n", __func__, osdc);
        mutex_lock(&osdc->request_mutex);
        while (!RB_EMPTY_ROOT(&osdc->osds)) {
                struct ceph_osd *osd = rb_entry(rb_first(&osdc->osds),
@@ -752,7 +752,8 @@ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd)
                ret = -EAGAIN;
        } else {
                ceph_con_close(&osd->o_con);
-               ceph_con_open(&osd->o_con, &osdc->osdmap->osd_addr[osd->o_osd]);
+               ceph_con_open(&osd->o_con, CEPH_ENTITY_TYPE_OSD, osd->o_osd,
+                             &osdc->osdmap->osd_addr[osd->o_osd]);
                osd->o_incarnation++;
        }
        return ret;
@@ -853,7 +854,7 @@ static void __unregister_request(struct ceph_osd_client *osdc,
 
        if (req->r_osd) {
                /* make sure the original request isn't in flight. */
-               ceph_con_revoke(&req->r_osd->o_con, req->r_request);
+               ceph_msg_revoke(req->r_request);
 
                list_del_init(&req->r_osd_item);
                if (list_empty(&req->r_osd->o_requests) &&
@@ -880,7 +881,7 @@ static void __unregister_request(struct ceph_osd_client *osdc,
 static void __cancel_request(struct ceph_osd_request *req)
 {
        if (req->r_sent && req->r_osd) {
-               ceph_con_revoke(&req->r_osd->o_con, req->r_request);
+               ceph_msg_revoke(req->r_request);
                req->r_sent = 0;
        }
 }
@@ -890,7 +891,9 @@ static void __register_linger_request(struct ceph_osd_client *osdc,
 {
        dout("__register_linger_request %p\n", req);
        list_add_tail(&req->r_linger_item, &osdc->req_linger);
-       list_add_tail(&req->r_linger_osd, &req->r_osd->o_linger_requests);
+       if (req->r_osd)
+               list_add_tail(&req->r_linger_osd,
+                             &req->r_osd->o_linger_requests);
 }
 
 static void __unregister_linger_request(struct ceph_osd_client *osdc,
@@ -998,18 +1001,18 @@ static int __map_request(struct ceph_osd_client *osdc,
        req->r_osd = __lookup_osd(osdc, o);
        if (!req->r_osd && o >= 0) {
                err = -ENOMEM;
-               req->r_osd = create_osd(osdc);
+               req->r_osd = create_osd(osdc, o);
                if (!req->r_osd) {
                        list_move(&req->r_req_lru_item, &osdc->req_notarget);
                        goto out;
                }
 
                dout("map_request osd %p is osd%d\n", req->r_osd, o);
-               req->r_osd->o_osd = o;
-               req->r_osd->o_con.peer_name.num = cpu_to_le64(o);
                __insert_osd(osdc, req->r_osd);
 
-               ceph_con_open(&req->r_osd->o_con, &osdc->osdmap->osd_addr[o]);
+               ceph_con_open(&req->r_osd->o_con,
+                             CEPH_ENTITY_TYPE_OSD, o,
+                             &osdc->osdmap->osd_addr[o]);
        }
 
        if (req->r_osd) {
@@ -1304,8 +1307,9 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
 
        dout("kick_requests %s\n", force_resend ? " (force resend)" : "");
        mutex_lock(&osdc->request_mutex);
-       for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
+       for (p = rb_first(&osdc->requests); p; ) {
                req = rb_entry(p, struct ceph_osd_request, r_node);
+               p = rb_next(p);
                err = __map_request(osdc, req, force_resend);
                if (err < 0)
                        continue;  /* error */
@@ -1313,10 +1317,23 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
                        dout("%p tid %llu maps to no osd\n", req, req->r_tid);
                        needmap++;  /* request a newer map */
                } else if (err > 0) {
-                       dout("%p tid %llu requeued on osd%d\n", req, req->r_tid,
-                            req->r_osd ? req->r_osd->o_osd : -1);
-                       if (!req->r_linger)
+                       if (!req->r_linger) {
+                               dout("%p tid %llu requeued on osd%d\n", req,
+                                    req->r_tid,
+                                    req->r_osd ? req->r_osd->o_osd : -1);
                                req->r_flags |= CEPH_OSD_FLAG_RETRY;
+                       }
+               }
+               if (req->r_linger && list_empty(&req->r_linger_item)) {
+                       /*
+                        * register as a linger so that we will
+                        * re-submit below and get a new tid
+                        */
+                       dout("%p tid %llu restart on osd%d\n",
+                            req, req->r_tid,
+                            req->r_osd ? req->r_osd->o_osd : -1);
+                       __register_linger_request(osdc, req);
+                       __unregister_request(osdc, req);
                }
        }
 
@@ -1391,7 +1408,7 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
                             epoch, maplen);
                        newmap = osdmap_apply_incremental(&p, next,
                                                          osdc->osdmap,
-                                                         osdc->client->msgr);
+                                                         &osdc->client->msgr);
                        if (IS_ERR(newmap)) {
                                err = PTR_ERR(newmap);
                                goto bad;
@@ -1839,11 +1856,12 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
        if (!osdc->req_mempool)
                goto out;
 
-       err = ceph_msgpool_init(&osdc->msgpool_op, OSD_OP_FRONT_LEN, 10, true,
+       err = ceph_msgpool_init(&osdc->msgpool_op, CEPH_MSG_OSD_OP,
+                               OSD_OP_FRONT_LEN, 10, true,
                                "osd_op");
        if (err < 0)
                goto out_mempool;
-       err = ceph_msgpool_init(&osdc->msgpool_op_reply,
+       err = ceph_msgpool_init(&osdc->msgpool_op_reply, CEPH_MSG_OSD_OPREPLY,
                                OSD_OPREPLY_FRONT_LEN, 10, true,
                                "osd_op_reply");
        if (err < 0)
@@ -2019,15 +2037,15 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
        if (!req) {
                *skip = 1;
                m = NULL;
-               pr_info("get_reply unknown tid %llu from osd%d\n", tid,
-                       osd->o_osd);
+               dout("get_reply unknown tid %llu from osd%d\n", tid,
+                    osd->o_osd);
                goto out;
        }
 
        if (req->r_con_filling_msg) {
-               dout("get_reply revoking msg %p from old con %p\n",
+               dout("%s revoking msg %p from old con %p\n", __func__,
                     req->r_reply, req->r_con_filling_msg);
-               ceph_con_revoke_message(req->r_con_filling_msg, req->r_reply);
+               ceph_msg_revoke_incoming(req->r_reply);
                req->r_con_filling_msg->ops->put(req->r_con_filling_msg);
                req->r_con_filling_msg = NULL;
        }
@@ -2080,6 +2098,7 @@ static struct ceph_msg *alloc_msg(struct ceph_connection *con,
        int type = le16_to_cpu(hdr->type);
        int front = le32_to_cpu(hdr->front_len);
 
+       *skip = 0;
        switch (type) {
        case CEPH_MSG_OSD_MAP:
        case CEPH_MSG_WATCH_NOTIFY:
index 81e3b84a77efdecb6c44603e7784a083fe94b980..3124b71a888362910f96efec9bca0104f84dba5d 100644 (file)
@@ -135,6 +135,21 @@ bad:
        return -EINVAL;
 }
 
+static int skip_name_map(void **p, void *end)
+{
+        int len;
+        ceph_decode_32_safe(p, end, len ,bad);
+        while (len--) {
+                int strlen;
+                *p += sizeof(u32);
+                ceph_decode_32_safe(p, end, strlen, bad);
+                *p += strlen;
+}
+        return 0;
+bad:
+        return -EINVAL;
+}
+
 static struct crush_map *crush_decode(void *pbyval, void *end)
 {
        struct crush_map *c;
@@ -143,6 +158,7 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
        void **p = &pbyval;
        void *start = pbyval;
        u32 magic;
+       u32 num_name_maps;
 
        dout("crush_decode %p to %p len %d\n", *p, end, (int)(end - *p));
 
@@ -150,6 +166,11 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
        if (c == NULL)
                return ERR_PTR(-ENOMEM);
 
+        /* set tunables to default values */
+        c->choose_local_tries = 2;
+        c->choose_local_fallback_tries = 5;
+        c->choose_total_tries = 19;
+
        ceph_decode_need(p, end, 4*sizeof(u32), bad);
        magic = ceph_decode_32(p);
        if (magic != CRUSH_MAGIC) {
@@ -297,7 +318,25 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
        }
 
        /* ignore trailing name maps. */
+        for (num_name_maps = 0; num_name_maps < 3; num_name_maps++) {
+                err = skip_name_map(p, end);
+                if (err < 0)
+                        goto done;
+        }
+
+        /* tunables */
+        ceph_decode_need(p, end, 3*sizeof(u32), done);
+        c->choose_local_tries = ceph_decode_32(p);
+        c->choose_local_fallback_tries =  ceph_decode_32(p);
+        c->choose_total_tries = ceph_decode_32(p);
+        dout("crush decode tunable choose_local_tries = %d",
+             c->choose_local_tries);
+        dout("crush decode tunable choose_local_fallback_tries = %d",
+             c->choose_local_fallback_tries);
+        dout("crush decode tunable choose_total_tries = %d",
+             c->choose_total_tries);
 
+done:
        dout("crush_decode success\n");
        return c;
 
@@ -488,15 +527,16 @@ static int __decode_pool_names(void **p, void *end, struct ceph_osdmap *map)
                ceph_decode_32_safe(p, end, pool, bad);
                ceph_decode_32_safe(p, end, len, bad);
                dout("  pool %d len %d\n", pool, len);
+               ceph_decode_need(p, end, len, bad);
                pi = __lookup_pg_pool(&map->pg_pools, pool);
                if (pi) {
+                       char *name = kstrndup(*p, len, GFP_NOFS);
+
+                       if (!name)
+                               return -ENOMEM;
                        kfree(pi->name);
-                       pi->name = kmalloc(len + 1, GFP_NOFS);
-                       if (pi->name) {
-                               memcpy(pi->name, *p, len);
-                               pi->name[len] = '\0';
-                               dout("  name is %s\n", pi->name);
-                       }
+                       pi->name = name;
+                       dout("  name is %s\n", pi->name);
                }
                *p += len;
        }
@@ -666,6 +706,9 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end)
                ceph_decode_need(p, end, sizeof(u32) + sizeof(u64), bad);
                ceph_decode_copy(p, &pgid, sizeof(pgid));
                n = ceph_decode_32(p);
+               err = -EINVAL;
+               if (n > (UINT_MAX - sizeof(*pg)) / sizeof(u32))
+                       goto bad;
                ceph_decode_need(p, end, n * sizeof(u32), bad);
                err = -ENOMEM;
                pg = kmalloc(sizeof(*pg) + n*sizeof(u32), GFP_NOFS);
@@ -889,6 +932,10 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
                        (void) __remove_pg_mapping(&map->pg_temp, pgid);
 
                        /* insert */
+                       if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) {
+                               err = -EINVAL;
+                               goto bad;
+                       }
                        pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS);
                        if (!pg) {
                                err = -ENOMEM;
index 727e506cacda0f7e6d95178c783ac695d2e4b1fb..b5c067bccc4595204f21bff24bbf16631e54cad4 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/errno.h>
 #include <linux/hash.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/gss_api.h>
 #include <linux/spinlock.h>
 
 #ifdef RPC_DEBUG
@@ -122,6 +123,59 @@ rpcauth_unregister(const struct rpc_authops *ops)
 }
 EXPORT_SYMBOL_GPL(rpcauth_unregister);
 
+/**
+ * rpcauth_list_flavors - discover registered flavors and pseudoflavors
+ * @array: array to fill in
+ * @size: size of "array"
+ *
+ * Returns the number of array items filled in, or a negative errno.
+ *
+ * The returned array is not sorted by any policy.  Callers should not
+ * rely on the order of the items in the returned array.
+ */
+int
+rpcauth_list_flavors(rpc_authflavor_t *array, int size)
+{
+       rpc_authflavor_t flavor;
+       int result = 0;
+
+       spin_lock(&rpc_authflavor_lock);
+       for (flavor = 0; flavor < RPC_AUTH_MAXFLAVOR; flavor++) {
+               const struct rpc_authops *ops = auth_flavors[flavor];
+               rpc_authflavor_t pseudos[4];
+               int i, len;
+
+               if (result >= size) {
+                       result = -ENOMEM;
+                       break;
+               }
+
+               if (ops == NULL)
+                       continue;
+               if (ops->list_pseudoflavors == NULL) {
+                       array[result++] = ops->au_flavor;
+                       continue;
+               }
+               len = ops->list_pseudoflavors(pseudos, ARRAY_SIZE(pseudos));
+               if (len < 0) {
+                       result = len;
+                       break;
+               }
+               for (i = 0; i < len; i++) {
+                       if (result >= size) {
+                               result = -ENOMEM;
+                               break;
+                       }
+                       array[result++] = pseudos[i];
+               }
+       }
+       spin_unlock(&rpc_authflavor_lock);
+
+       dprintk("RPC:       %s returns %d\n", __func__, result);
+       return result;
+}
+EXPORT_SYMBOL_GPL(rpcauth_list_flavors);
+
 struct rpc_auth *
 rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
 {
index d3ad81f8da5b79551c36b17a7d53007406946699..34c522021004dc31f3ffe04b279333240ab311e1 100644 (file)
@@ -1619,6 +1619,7 @@ static const struct rpc_authops authgss_ops = {
        .crcreate       = gss_create_cred,
        .pipes_create   = gss_pipes_dentries_create,
        .pipes_destroy  = gss_pipes_dentries_destroy,
+       .list_pseudoflavors = gss_mech_list_pseudoflavors,
 };
 
 static const struct rpc_credops gss_credops = {
index 782bfe1b64650d991489d25f94ca7debf05e8ecb..b174fcd9ff4cc3167266dbc205a5b9ad2fd339ae 100644 (file)
@@ -239,14 +239,28 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
 
 EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor);
 
-int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr)
+/**
+ * gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors
+ * @array: array to fill in
+ * @size: size of "array"
+ *
+ * Returns the number of array items filled in, or a negative errno.
+ *
+ * The returned array is not sorted by any policy.  Callers should not
+ * rely on the order of the items in the returned array.
+ */
+int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size)
 {
        struct gss_api_mech *pos = NULL;
        int j, i = 0;
 
        spin_lock(&registered_mechs_lock);
        list_for_each_entry(pos, &registered_mechs, gm_list) {
-               for (j=0; j < pos->gm_pf_num; j++) {
+               for (j = 0; j < pos->gm_pf_num; j++) {
+                       if (i >= size) {
+                               spin_unlock(&registered_mechs_lock);
+                               return -ENOMEM;
+                       }
                        array_ptr[i++] = pos->gm_pfs[j].pseudoflavor;
                }
        }
@@ -254,8 +268,6 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr)
        return i;
 }
 
-EXPORT_SYMBOL_GPL(gss_mech_list_pseudoflavors);
-
 u32
 gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)
 {
index 47ad2666fdf6566f170b49e97097a285da29a231..2afd2a84dc35aa5cab139b38f82f5c5206e83728 100644 (file)
@@ -1349,8 +1349,11 @@ static int c_show(struct seq_file *m, void *p)
        if (cache_check(cd, cp, NULL))
                /* cache_check does a cache_put on failure */
                seq_printf(m, "# ");
-       else
+       else {
+               if (cache_is_expired(cd, cp))
+                       seq_printf(m, "# ");
                cache_put(cp, cd);
+       }
 
        return cd->cache_show(m, cd, cp);
 }
index 00eb859b7de5053f42d410be0de6632936a421cd..b05df36692ff0aec2e370c96fc4a74dfb2f50ff0 100644 (file)
@@ -1844,12 +1844,13 @@ call_timeout(struct rpc_task *task)
                return;
        }
        if (RPC_IS_SOFT(task)) {
-               if (clnt->cl_chatty)
+               if (clnt->cl_chatty) {
                        rcu_read_lock();
                        printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
                                clnt->cl_protname,
                                rcu_dereference(clnt->cl_xprt)->servername);
                        rcu_read_unlock();
+               }
                if (task->tk_flags & RPC_TASK_TIMEOUT)
                        rpc_exit(task, -ETIMEDOUT);
                else
index 0cf165580d8db04c00324fc44a94e349deb4bba4..0afba1b4b65606437d141cb21a64e6d00f3855f4 100644 (file)
@@ -128,34 +128,6 @@ xdr_terminate_string(struct xdr_buf *buf, const u32 len)
 }
 EXPORT_SYMBOL_GPL(xdr_terminate_string);
 
-void
-xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
-                unsigned int len)
-{
-       struct kvec *tail = xdr->tail;
-       u32 *p;
-
-       xdr->pages = pages;
-       xdr->page_base = base;
-       xdr->page_len = len;
-
-       p = (u32 *)xdr->head[0].iov_base + XDR_QUADLEN(xdr->head[0].iov_len);
-       tail->iov_base = p;
-       tail->iov_len = 0;
-
-       if (len & 3) {
-               unsigned int pad = 4 - (len & 3);
-
-               *p = 0;
-               tail->iov_base = (char *)p + (len & 3);
-               tail->iov_len  = pad;
-               len += pad;
-       }
-       xdr->buflen += len;
-       xdr->len += len;
-}
-EXPORT_SYMBOL_GPL(xdr_encode_pages);
-
 void
 xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
                 struct page **pages, unsigned int base, unsigned int len)
@@ -456,6 +428,16 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len)
 }
 EXPORT_SYMBOL_GPL(xdr_shift_buf);
 
+/**
+ * xdr_stream_pos - Return the current offset from the start of the xdr_stream
+ * @xdr: pointer to struct xdr_stream
+ */
+unsigned int xdr_stream_pos(const struct xdr_stream *xdr)
+{
+       return (unsigned int)(XDR_QUADLEN(xdr->buf->len) - xdr->nwords) << 2;
+}
+EXPORT_SYMBOL_GPL(xdr_stream_pos);
+
 /**
  * xdr_init_encode - Initialize a struct xdr_stream for sending data.
  * @xdr: pointer to xdr_stream struct
@@ -556,13 +538,11 @@ void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int b
 EXPORT_SYMBOL_GPL(xdr_write_pages);
 
 static void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov,
-               __be32 *p, unsigned int len)
+               unsigned int len)
 {
        if (len > iov->iov_len)
                len = iov->iov_len;
-       if (p == NULL)
-               p = (__be32*)iov->iov_base;
-       xdr->p = p;
+       xdr->p = (__be32*)iov->iov_base;
        xdr->end = (__be32*)(iov->iov_base + len);
        xdr->iov = iov;
        xdr->page_ptr = NULL;
@@ -609,7 +589,7 @@ static void xdr_set_next_page(struct xdr_stream *xdr)
        newbase -= xdr->buf->page_base;
 
        if (xdr_set_page_base(xdr, newbase, PAGE_SIZE) < 0)
-               xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len);
+               xdr_set_iov(xdr, xdr->buf->tail, xdr->buf->len);
 }
 
 static bool xdr_set_next_buffer(struct xdr_stream *xdr)
@@ -618,7 +598,7 @@ static bool xdr_set_next_buffer(struct xdr_stream *xdr)
                xdr_set_next_page(xdr);
        else if (xdr->iov == xdr->buf->head) {
                if (xdr_set_page_base(xdr, 0, PAGE_SIZE) < 0)
-                       xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len);
+                       xdr_set_iov(xdr, xdr->buf->tail, xdr->buf->len);
        }
        return xdr->p != xdr->end;
 }
@@ -634,10 +614,15 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
        xdr->buf = buf;
        xdr->scratch.iov_base = NULL;
        xdr->scratch.iov_len = 0;
+       xdr->nwords = XDR_QUADLEN(buf->len);
        if (buf->head[0].iov_len != 0)
-               xdr_set_iov(xdr, buf->head, p, buf->len);
+               xdr_set_iov(xdr, buf->head, buf->len);
        else if (buf->page_len != 0)
                xdr_set_page_base(xdr, 0, buf->len);
+       if (p != NULL && p > xdr->p && xdr->end >= p) {
+               xdr->nwords -= p - xdr->p;
+               xdr->p = p;
+       }
 }
 EXPORT_SYMBOL_GPL(xdr_init_decode);
 
@@ -662,12 +647,14 @@ EXPORT_SYMBOL_GPL(xdr_init_decode_pages);
 
 static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
 {
+       unsigned int nwords = XDR_QUADLEN(nbytes);
        __be32 *p = xdr->p;
-       __be32 *q = p + XDR_QUADLEN(nbytes);
+       __be32 *q = p + nwords;
 
-       if (unlikely(q > xdr->end || q < p))
+       if (unlikely(nwords > xdr->nwords || q > xdr->end || q < p))
                return NULL;
        xdr->p = q;
+       xdr->nwords -= nwords;
        return p;
 }
 
@@ -734,6 +721,31 @@ __be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
 }
 EXPORT_SYMBOL_GPL(xdr_inline_decode);
 
+static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len)
+{
+       struct xdr_buf *buf = xdr->buf;
+       struct kvec *iov;
+       unsigned int nwords = XDR_QUADLEN(len);
+       unsigned int cur = xdr_stream_pos(xdr);
+
+       if (xdr->nwords == 0)
+               return 0;
+       if (nwords > xdr->nwords) {
+               nwords = xdr->nwords;
+               len = nwords << 2;
+       }
+       /* Realign pages to current pointer position */
+       iov  = buf->head;
+       if (iov->iov_len > cur)
+               xdr_shrink_bufhead(buf, iov->iov_len - cur);
+
+       /* Truncate page data and move it into the tail */
+       if (buf->page_len > len)
+               xdr_shrink_pagelen(buf, buf->page_len - len);
+       xdr->nwords = XDR_QUADLEN(buf->len - cur);
+       return len;
+}
+
 /**
  * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position
  * @xdr: pointer to xdr_stream struct
@@ -742,39 +754,37 @@ EXPORT_SYMBOL_GPL(xdr_inline_decode);
  * Moves data beyond the current pointer position from the XDR head[] buffer
  * into the page list. Any data that lies beyond current position + "len"
  * bytes is moved into the XDR tail[].
+ *
+ * Returns the number of XDR encoded bytes now contained in the pages
  */
-void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
+unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
 {
        struct xdr_buf *buf = xdr->buf;
        struct kvec *iov;
-       ssize_t shift;
+       unsigned int nwords;
        unsigned int end;
-       int padding;
+       unsigned int padding;
 
-       /* Realign pages to current pointer position */
-       iov  = buf->head;
-       shift = iov->iov_len + (char *)iov->iov_base - (char *)xdr->p;
-       if (shift > 0)
-               xdr_shrink_bufhead(buf, shift);
-
-       /* Truncate page data and move it into the tail */
-       if (buf->page_len > len)
-               xdr_shrink_pagelen(buf, buf->page_len - len);
-       padding = (XDR_QUADLEN(len) << 2) - len;
+       len = xdr_align_pages(xdr, len);
+       if (len == 0)
+               return 0;
+       nwords = XDR_QUADLEN(len);
+       padding = (nwords << 2) - len;
        xdr->iov = iov = buf->tail;
        /* Compute remaining message length.  */
-       end = iov->iov_len;
-       shift = buf->buflen - buf->len;
-       if (shift < end)
-               end -= shift;
-       else if (shift > 0)
-               end = 0;
+       end = ((xdr->nwords - nwords) << 2) + padding;
+       if (end > iov->iov_len)
+               end = iov->iov_len;
+
        /*
         * Position current pointer at beginning of tail, and
         * set remaining message length.
         */
        xdr->p = (__be32 *)((char *)iov->iov_base + padding);
        xdr->end = (__be32 *)((char *)iov->iov_base + end);
+       xdr->page_ptr = NULL;
+       xdr->nwords = XDR_QUADLEN(end - padding);
+       return len;
 }
 EXPORT_SYMBOL_GPL(xdr_read_pages);
 
@@ -790,12 +800,13 @@ EXPORT_SYMBOL_GPL(xdr_read_pages);
  */
 void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
 {
-       xdr_read_pages(xdr, len);
+       len = xdr_align_pages(xdr, len);
        /*
         * Position current pointer at beginning of tail, and
         * set remaining message length.
         */
-       xdr_set_page_base(xdr, 0, len);
+       if (len != 0)
+               xdr_set_page_base(xdr, 0, len);
 }
 EXPORT_SYMBOL_GPL(xdr_enter_page);
 
index e5bd60ff48e3d553ef3921256123519df7b812b8..913d6bdfdda3ecb44f521af79980019d5a531399 100755 (executable)
@@ -1600,13 +1600,17 @@ sub process {
 
 # Check signature styles
                if (!$in_header_lines &&
-                   $line =~ /^(\s*)($signature_tags)(\s*)(.*)/) {
+                   $line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) {
                        my $space_before = $1;
                        my $sign_off = $2;
                        my $space_after = $3;
                        my $email = $4;
                        my $ucfirst_sign_off = ucfirst(lc($sign_off));
 
+                       if ($sign_off !~ /$signature_tags/) {
+                               WARN("BAD_SIGN_OFF",
+                                    "Non-standard signature: $sign_off\n" . $herecurr);
+                       }
                        if (defined $space_before && $space_before ne "") {
                                WARN("BAD_SIGN_OFF",
                                     "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr);
@@ -1848,8 +1852,8 @@ sub process {
 
                        my $pos = pos_last_openparen($rest);
                        if ($pos >= 0) {
-                               $line =~ /^\+([ \t]*)/;
-                               my $newindent = $1;
+                               $line =~ /^(\+| )([ \t]*)/;
+                               my $newindent = $2;
 
                                my $goodtabindent = $oldindent .
                                        "\t" x ($pos / 8) .
@@ -2984,6 +2988,45 @@ sub process {
                        }
                }
 
+# do {} while (0) macro tests:
+# single-statement macros do not need to be enclosed in do while (0) loop,
+# macro should not end with a semicolon
+               if ($^V && $^V ge 5.10.0 &&
+                   $realfile !~ m@/vmlinux.lds.h$@ &&
+                   $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) {
+                       my $ln = $linenr;
+                       my $cnt = $realcnt;
+                       my ($off, $dstat, $dcond, $rest);
+                       my $ctx = '';
+                       ($dstat, $dcond, $ln, $cnt, $off) =
+                               ctx_statement_block($linenr, $realcnt, 0);
+                       $ctx = $dstat;
+
+                       $dstat =~ s/\\\n.//g;
+
+                       if ($dstat =~ /^\+\s*#\s*define\s+$Ident\s*${balanced_parens}\s*do\s*{(.*)\s*}\s*while\s*\(\s*0\s*\)\s*([;\s]*)\s*$/) {
+                               my $stmts = $2;
+                               my $semis = $3;
+
+                               $ctx =~ s/\n*$//;
+                               my $cnt = statement_rawlines($ctx);
+                               my $herectx = $here . "\n";
+
+                               for (my $n = 0; $n < $cnt; $n++) {
+                                       $herectx .= raw_line($linenr, $n) . "\n";
+                               }
+
+                               if (($stmts =~ tr/;/;/) == 1) {
+                                       WARN("SINGLE_STATEMENT_DO_WHILE_MACRO",
+                                            "Single statement macros should not use a do {} while (0) loop\n" . "$herectx");
+                               }
+                               if (defined $semis && $semis ne "") {
+                                       WARN("DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON",
+                                            "do {} while (0) macros should not be semicolon terminated\n" . "$herectx");
+                               }
+                       }
+               }
+
 # make sure symbols are always wrapped with VMLINUX_SYMBOL() ...
 # all assignments may have only one of the following with an assignment:
 #      .
@@ -3261,6 +3304,12 @@ sub process {
                             "sizeof(& should be avoided\n" . $herecurr);
                }
 
+# check for sizeof without parenthesis
+               if ($line =~ /\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/) {
+                       WARN("SIZEOF_PARENTHESIS",
+                            "sizeof $1 should be sizeof($1)\n" . $herecurr);
+               }
+
 # check for line continuations in quoted strings with odd counts of "
                if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) {
                        WARN("LINE_CONTINUATIONS",
@@ -3309,6 +3358,22 @@ sub process {
                        }
                }
 
+# check usleep_range arguments
+               if ($^V && $^V ge 5.10.0 &&
+                   defined $stat &&
+                   $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) {
+                       my $min = $1;
+                       my $max = $7;
+                       if ($min eq $max) {
+                               WARN("USLEEP_RANGE",
+                                    "usleep_range should not use min == max args; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n");
+                       } elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ &&
+                                $min > $max) {
+                               WARN("USLEEP_RANGE",
+                                    "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n");
+                       }
+               }
+
 # check for new externs in .c files.
                if ($realfile =~ /\.c$/ && defined $stat &&
                    $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
diff --git a/scripts/coccinelle/iterators/use_after_iter.cocci b/scripts/coccinelle/iterators/use_after_iter.cocci
new file mode 100644 (file)
index 0000000..06284c5
--- /dev/null
@@ -0,0 +1,147 @@
+/// If list_for_each_entry, etc complete a traversal of the list, the iterator
+/// variable ends up pointing to an address at an offset from the list head,
+/// and not a meaningful structure.  Thus this value should not be used after
+/// the end of the iterator.
+//#False positives arise when there is a goto in the iterator and the
+//#reported reference is at the label of this goto.  Some flag tests
+//#may also cause a report to be a false positive.
+///
+// Confidence: Moderate
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LIP6.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: -no_includes -include_headers
+
+virtual context
+virtual org
+virtual report
+
+@r exists@
+identifier c,member;
+expression E,x;
+iterator name list_for_each_entry;
+iterator name list_for_each_entry_reverse;
+iterator name list_for_each_entry_continue;
+iterator name list_for_each_entry_continue_reverse;
+iterator name list_for_each_entry_from;
+iterator name list_for_each_entry_safe;
+iterator name list_for_each_entry_safe_continue;
+iterator name list_for_each_entry_safe_from;
+iterator name list_for_each_entry_safe_reverse;
+iterator name hlist_for_each_entry;
+iterator name hlist_for_each_entry_continue;
+iterator name hlist_for_each_entry_from;
+iterator name hlist_for_each_entry_safe;
+statement S;
+position p1,p2;
+@@
+
+(
+list_for_each_entry@p1(c,...,member) { ... when != break;
+                                 when forall
+                                 when strict
+}
+|
+list_for_each_entry_reverse@p1(c,...,member) { ... when != break;
+                                 when forall
+                                 when strict
+}
+|
+list_for_each_entry_continue@p1(c,...,member) { ... when != break;
+                                 when forall
+                                 when strict
+}
+|
+list_for_each_entry_continue_reverse@p1(c,...,member) { ... when != break;
+                                 when forall
+                                 when strict
+}
+|
+list_for_each_entry_from@p1(c,...,member) { ... when != break;
+                                 when forall
+                                 when strict
+}
+|
+list_for_each_entry_safe@p1(c,...,member) { ... when != break;
+                                 when forall
+                                 when strict
+}
+|
+list_for_each_entry_safe_continue@p1(c,...,member) { ... when != break;
+                                 when forall
+                                 when strict
+}
+|
+list_for_each_entry_safe_from@p1(c,...,member) { ... when != break;
+                                 when forall
+                                 when strict
+}
+|
+list_for_each_entry_safe_reverse@p1(c,...,member) { ... when != break;
+                                 when forall
+                                 when strict
+}
+)
+...
+(
+list_for_each_entry(c,...) S
+|
+list_for_each_entry_reverse(c,...) S
+|
+list_for_each_entry_continue(c,...) S
+|
+list_for_each_entry_continue_reverse(c,...) S
+|
+list_for_each_entry_from(c,...) S
+|
+list_for_each_entry_safe(c,...) S
+|
+list_for_each_entry_safe(x,c,...) S
+|
+list_for_each_entry_safe_continue(c,...) S
+|
+list_for_each_entry_safe_continue(x,c,...) S
+|
+list_for_each_entry_safe_from(c,...) S
+|
+list_for_each_entry_safe_from(x,c,...) S
+|
+list_for_each_entry_safe_reverse(c,...) S
+|
+list_for_each_entry_safe_reverse(x,c,...) S
+|
+hlist_for_each_entry(c,...) S
+|
+hlist_for_each_entry_continue(c,...) S
+|
+hlist_for_each_entry_from(c,...) S
+|
+hlist_for_each_entry_safe(c,...) S
+|
+list_remove_head(x,c,...)
+|
+sizeof(<+...c...+>)
+|
+&c->member
+|
+c = E
+|
+*c@p2
+)
+
+@script:python depends on org@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+cocci.print_main("invalid iterator index reference",p2)
+cocci.print_secs("iterator",p1)
+
+@script:python depends on report@
+p1 << r.p1;
+p2 << r.p2;
+@@
+
+msg = "ERROR: invalid reference to the index variable of the iterator on line %s" % (p1[0].line)
+coccilib.report.print_report(p2[0], msg)
diff --git a/scripts/coccinelle/misc/irqf_oneshot.cocci b/scripts/coccinelle/misc/irqf_oneshot.cocci
new file mode 100644 (file)
index 0000000..6cfde94
--- /dev/null
@@ -0,0 +1,65 @@
+/// Make sure threaded IRQs without a primary handler are always request with
+/// IRQF_ONESHOT
+///
+//
+// Confidence: Good
+// Comments:
+// Options: --no-includes
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@r1@
+expression irq;
+expression thread_fn;
+expression flags;
+position p;
+@@
+request_threaded_irq@p(irq, NULL, thread_fn,
+(
+flags | IRQF_ONESHOT
+|
+IRQF_ONESHOT
+)
+, ...)
+
+@depends on patch@
+expression irq;
+expression thread_fn;
+expression flags;
+position p != r1.p;
+@@
+request_threaded_irq@p(irq, NULL, thread_fn,
+(
+-0
++IRQF_ONESHOT
+|
+-flags
++flags | IRQF_ONESHOT
+)
+, ...)
+
+@depends on context@
+position p != r1.p;
+@@
+*request_threaded_irq@p(...)
+
+@match depends on report || org@
+expression irq;
+position p != r1.p;
+@@
+request_threaded_irq@p(irq, NULL, ...)
+
+@script:python depends on org@
+p << match.p;
+@@
+msg = "ERROR: Threaded IRQ with no primary handler requested without IRQF_ONESHOT"
+coccilib.org.print_todo(p[0],msg)
+
+@script:python depends on report@
+p << match.p;
+@@
+msg = "ERROR: Threaded IRQ with no primary handler requested without IRQF_ONESHOT"
+coccilib.report.print_report(p[0],msg)
index ed6653ef9702aa5320756537bb942e8a35123cb4..ee355394f4ef76eeb6d6f74dac00729d8cc942e3 100755 (executable)
@@ -1,6 +1,9 @@
 #!/bin/bash
 # Manipulate options in a .config file from the command line
 
+# If no prefix forced, use the default CONFIG_
+CONFIG_="${CONFIG_-CONFIG_}"
+
 usage() {
        cat >&2 <<EOL
 Manipulate options in a .config file from the command line.
@@ -14,6 +17,7 @@ commands:
                             Set option to "string"
        --set-val option value
                             Set option to value
+       --undefine|-u option Undefine option
        --state|-s option    Print state of option (n,y,m,undef)
 
        --enable-after|-E beforeopt option
@@ -26,10 +30,17 @@ commands:
        commands can be repeated multiple times
 
 options:
-       --file .config file to change (default .config)
+       --file config-file   .config file to change (default .config)
+       --keep-case|-k       Keep next symbols' case (dont' upper-case it)
 
 config doesn't check the validity of the .config file. This is done at next
- make time.
+make time.
+
+By default, config will upper-case the given symbol. Use --keep-case to keep
+the case of all following symbols unchanged.
+
+config uses 'CONFIG_' as the default symbol prefix. Set the environment
+variable CONFIG_ to the prefix to use. Eg.: CONFIG_="FOO_" config ...
 EOL
        exit 1
 }
@@ -40,11 +51,13 @@ checkarg() {
                usage
        fi
        case "$ARG" in
-       CONFIG_*)
-               ARG="${ARG/CONFIG_/}"
+       ${CONFIG_}*)
+               ARG="${ARG/${CONFIG_}/}"
                ;;
        esac
-       ARG="`echo $ARG | tr a-z A-Z`"
+       if [ "$MUNGE_CASE" = "yes" ] ; then
+               ARG="`echo $ARG | tr a-z A-Z`"
+       fi
 }
 
 set_var() {
@@ -61,6 +74,12 @@ set_var() {
        fi
 }
 
+undef_var() {
+       local name=$1
+
+       sed -ri "/^($name=|# $name is not set)/d" "$FN"
+}
+
 if [ "$1" = "--file" ]; then
        FN="$2"
        if [ "$FN" = "" ] ; then
@@ -75,10 +94,16 @@ if [ "$1" = "" ] ; then
        usage
 fi
 
+MUNGE_CASE=yes
 while [ "$1" != "" ] ; do
        CMD="$1"
        shift
        case "$CMD" in
+       --keep-case|-k)
+               MUNGE_CASE=no
+               shift
+               continue
+               ;;
        --refresh)
                ;;
        --*-after)
@@ -95,55 +120,58 @@ while [ "$1" != "" ] ; do
        esac
        case "$CMD" in
        --enable|-e)
-               set_var "CONFIG_$ARG" "CONFIG_$ARG=y"
+               set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=y"
                ;;
 
        --disable|-d)
-               set_var "CONFIG_$ARG" "# CONFIG_$ARG is not set"
+               set_var "${CONFIG_}$ARG" "# ${CONFIG_}$ARG is not set"
                ;;
 
        --module|-m)
-               set_var "CONFIG_$ARG" "CONFIG_$ARG=m"
+               set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=m"
                ;;
 
        --set-str)
                # sed swallows one level of escaping, so we need double-escaping
-               set_var "CONFIG_$ARG" "CONFIG_$ARG=\"${1//\"/\\\\\"}\""
+               set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=\"${1//\"/\\\\\"}\""
                shift
                ;;
 
        --set-val)
-               set_var "CONFIG_$ARG" "CONFIG_$ARG=$1"
+               set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=$1"
                shift
                ;;
+       --undefine|-u)
+               undef_var "${CONFIG_}$ARG"
+               ;;
 
        --state|-s)
-               if grep -q "# CONFIG_$ARG is not set" $FN ; then
+               if grep -q "# ${CONFIG_}$ARG is not set" $FN ; then
                        echo n
                else
-                       V="$(grep "^CONFIG_$ARG=" $FN)"
+                       V="$(grep "^${CONFIG_}$ARG=" $FN)"
                        if [ $? != 0 ] ; then
                                echo undef
                        else
-                               V="${V/#CONFIG_$ARG=/}"
+                               V="${V/#${CONFIG_}$ARG=/}"
                                V="${V/#\"/}"
                                V="${V/%\"/}"
-                               V="${V/\\\"/\"}"
+                               V="${V//\\\"/\"}"
                                echo "${V}"
                        fi
                fi
                ;;
 
        --enable-after|-E)
-               set_var "CONFIG_$B" "CONFIG_$B=y" "CONFIG_$A"
+               set_var "${CONFIG_}$B" "${CONFIG_}$B=y" "${CONFIG_}$A"
                ;;
 
        --disable-after|-D)
-               set_var "CONFIG_$B" "# CONFIG_$B is not set" "CONFIG_$A"
+               set_var "${CONFIG_}$B" "# ${CONFIG_}$B is not set" "${CONFIG_}$A"
                ;;
 
        --module-after|-M)
-               set_var "CONFIG_$B" "CONFIG_$B=m" "CONFIG_$A"
+               set_var "${CONFIG_}$B" "${CONFIG_}$B=m" "${CONFIG_}$A"
                ;;
 
        # undocumented because it ignores --file (fixme)
index ee120d441565422f0a6283b55ab5258fb61de9e7..be603c4fef624669ea2bac84e1f41311713a8065 100644 (file)
@@ -7,7 +7,6 @@ config*
 *.tab.h
 zconf.hash.c
 *.moc
-lkc_defs.h
 gconf.glade.h
 *.pot
 *.mo
index 79662658fb9158af1d7b3ee43dba0cfab0aa42cf..77d53999ffb90f51bea3f0395be08e495e3b75b8 100644 (file)
@@ -114,7 +114,7 @@ help:
        @echo  '  alldefconfig    - New config with all symbols set to default'
        @echo  '  randconfig      - New config with random answer to all options'
        @echo  '  listnewconfig   - List new options'
-       @echo  '  oldnoconfig     - Same as silentoldconfig but set new symbols to n (unset)'
+       @echo  '  oldnoconfig     - Same as silentoldconfig but sets new symbols to their default value'
 
 # lxdialog stuff
 check-lxdialog  := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
@@ -234,12 +234,12 @@ $(obj)/.tmp_qtcheck:
                if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \
              done; \
              if [ -z "$$dir" ]; then \
-               echo "*"; \
-               echo "* Unable to find any QT installation. Please make sure that"; \
-               echo "* the QT4 or QT3 development package is correctly installed and"; \
-               echo "* either qmake can be found or install pkg-config or set"; \
-               echo "* the QTDIR environment variable to the correct location."; \
-               echo "*"; \
+               echo >&2 "*"; \
+               echo >&2 "* Unable to find any QT installation. Please make sure that"; \
+               echo >&2 "* the QT4 or QT3 development package is correctly installed and"; \
+               echo >&2 "* either qmake can be found or install pkg-config or set"; \
+               echo >&2 "* the QTDIR environment variable to the correct location."; \
+               echo >&2 "*"; \
                false; \
              fi; \
              libpath=$$dir/lib; lib=qt; osdir=""; \
@@ -260,8 +260,8 @@ $(obj)/.tmp_qtcheck:
        else \
          cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \
          libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \
-         binpath="\$$(shell pkg-config QtCore --variable=prefix)"; \
-         moc="$$binpath/bin/moc"; \
+         moc="\$$(shell pkg-config QtCore --variable=moc_location)"; \
+         [ -n "$$moc" ] || moc="\$$(shell pkg-config QtCore --variable=prefix)/bin/moc"; \
        fi; \
        echo "KC_QT_CFLAGS=$$cflags" > $@; \
        echo "KC_QT_LIBS=$$libs" >> $@; \
@@ -279,17 +279,17 @@ $(obj)/.tmp_gtkcheck:
                if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then                  \
                        touch $@;                                                               \
                else                                                                    \
-                       echo "*";                                                       \
-                       echo "* GTK+ is present but version >= 2.0.0 is required.";     \
-                       echo "*";                                                       \
+                       echo >&2 "*";                                                   \
+                       echo >&2 "* GTK+ is present but version >= 2.0.0 is required."; \
+                       echo >&2 "*";                                                   \
                        false;                                                          \
                fi                                                                      \
        else                                                                            \
-               echo "*";                                                               \
-               echo "* Unable to find the GTK+ installation. Please make sure that";   \
-               echo "* the GTK+ 2.0 development package is correctly installed...";    \
-               echo "* You need gtk+-2.0, glib-2.0 and libglade-2.0.";                 \
-               echo "*";                                                               \
+               echo >&2 "*";                                                           \
+               echo >&2 "* Unable to find the GTK+ installation. Please make sure that";       \
+               echo >&2 "* the GTK+ 2.0 development package is correctly installed...";        \
+               echo >&2 "* You need gtk+-2.0, glib-2.0 and libglade-2.0.";             \
+               echo >&2 "*";                                                           \
                false;                                                                  \
        fi
 endif
@@ -298,8 +298,11 @@ $(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c
 
 $(obj)/qconf.o: $(obj)/qconf.moc
 
-$(obj)/%.moc: $(src)/%.h
-       $(KC_QT_MOC) -i $< -o $@
+quiet_cmd_moc = MOC     $@
+      cmd_moc = $(KC_QT_MOC) -i $< -o $@
+
+$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck
+       $(call cmd,moc)
 
 # Extract gconf menu items for I18N support
 $(obj)/gconf.glade.h: $(obj)/gconf.glade
index 52577f052bc12d06503aa9d6459eaa578fb0fd4b..13ddf1126c2a05d82eaa8171c75ee8949d4092cc 100644 (file)
@@ -182,10 +182,66 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
        return 0;
 }
 
+#define LINE_GROWTH 16
+static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
+{
+       char *nline;
+       size_t new_size = slen + 1;
+       if (new_size > *n) {
+               new_size += LINE_GROWTH - 1;
+               new_size *= 2;
+               nline = realloc(*lineptr, new_size);
+               if (!nline)
+                       return -1;
+
+               *lineptr = nline;
+               *n = new_size;
+       }
+
+       (*lineptr)[slen] = c;
+
+       return 0;
+}
+
+static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
+{
+       char *line = *lineptr;
+       size_t slen = 0;
+
+       for (;;) {
+               int c = getc(stream);
+
+               switch (c) {
+               case '\n':
+                       if (add_byte(c, &line, slen, n) < 0)
+                               goto e_out;
+                       slen++;
+                       /* fall through */
+               case EOF:
+                       if (add_byte('\0', &line, slen, n) < 0)
+                               goto e_out;
+                       *lineptr = line;
+                       if (slen == 0)
+                               return -1;
+                       return slen;
+               default:
+                       if (add_byte(c, &line, slen, n) < 0)
+                               goto e_out;
+                       slen++;
+               }
+       }
+
+e_out:
+       line[slen-1] = '\0';
+       *lineptr = line;
+       return -1;
+}
+
 int conf_read_simple(const char *name, int def)
 {
        FILE *in = NULL;
-       char line[1024];
+       char   *line = NULL;
+       size_t  line_asize = 0;
        char *p, *p2;
        struct symbol *sym;
        int i, def_flags;
@@ -247,7 +303,7 @@ load:
                }
        }
 
-       while (fgets(line, sizeof(line), in)) {
+       while (compat_getline(&line, &line_asize, in) != -1) {
                conf_lineno++;
                sym = NULL;
                if (line[0] == '#') {
@@ -335,6 +391,7 @@ setsym:
                        cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
                }
        }
+       free(line);
        fclose(in);
 
        if (modules_sym)
index 82cc3a85e7f885e2c7ab52aa99a6f76242899aa5..e3b12c010417c8e2886c1f57b07379cd483f7878 100644 (file)
@@ -4,7 +4,7 @@
 # What library to link
 ldflags()
 {
-       for ext in so a dylib ; do
+       for ext in so a dll.a dylib ; do
                for lib in ncursesw ncurses curses ; do
                        $cc -print-file-name=lib${lib}.${ext} | grep -q /
                        if [ $? -eq 0 ]; then
@@ -19,12 +19,12 @@ ldflags()
 # Where is ncurses.h?
 ccflags()
 {
-       if [ -f /usr/include/ncurses/ncurses.h ]; then
+       if [ -f /usr/include/ncursesw/curses.h ]; then
+               echo '-I/usr/include/ncursesw -DCURSES_LOC="<ncursesw/curses.h>"'
+       elif [ -f /usr/include/ncurses/ncurses.h ]; then
                echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
        elif [ -f /usr/include/ncurses/curses.h ]; then
                echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"'
-       elif [ -f /usr/include/ncursesw/curses.h ]; then
-               echo '-I/usr/include/ncursesw -DCURSES_LOC="<ncursesw/curses.h>"'
        elif [ -f /usr/include/ncurses.h ]; then
                echo '-DCURSES_LOC="<ncurses.h>"'
        else
index 154c2dd245b77536de60fd344d46e49dfbe41520..4e5de60a0c0d35765d1cfb8f67a06c852c892e8a 100644 (file)
@@ -129,6 +129,7 @@ do_resize:
                case 'e':
                case 'X':
                case 'x':
+               case 'q':
                        delwin(box);
                        delwin(dialog);
                        return 0;
@@ -190,6 +191,7 @@ do_resize:
                        break;
                case 'B':       /* Previous page */
                case 'b':
+               case 'u':
                case KEY_PPAGE:
                        if (begin_reached)
                                break;
@@ -214,6 +216,7 @@ do_resize:
                        break;
                case KEY_NPAGE: /* Next page */
                case ' ':
+               case 'd':
                        if (end_reached)
                                break;
 
index f606738d421d99c29f7321236e3eebcd2ac6a760..f584a281bb4c94d240b135ba6943fe75a433b3ec 100644 (file)
@@ -105,10 +105,10 @@ static const char mconf_readme[] = N_(
 "Text Box    (Help Window)\n"
 "--------\n"
 "o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
-"   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
-"   who are familiar with less and lynx.\n"
+"   keys h,j,k,l function here as do <u>, <d>, <SPACE BAR> and <B> for \n"
+"   those who are familiar with less and lynx.\n"
 "\n"
-"o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
+"o  Press <E>, <X>, <q>, <Enter> or <Esc><Esc> to exit.\n"
 "\n"
 "\n"
 "Alternate Configuration Files\n"
index 8c0eb65978c95aecedb73a7e71c6c4d788fe2255..1704a8562a5dc40ae09c23cd355958814b6976a8 100644 (file)
@@ -83,10 +83,10 @@ static const char nconf_readme[] = N_(
 "Text Box    (Help Window)\n"
 "--------\n"
 "o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
-"   keys h,j,k,l function here as do <SPACE BAR> for those\n"
-"   who are familiar with less and lynx.\n"
+"   keys h,j,k,l function here as do <u>, <d> and <SPACE BAR> for\n"
+"   those who are familiar with less and lynx.\n"
 "\n"
-"o  Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n"
+"o  Press <Enter>, <F1>, <F5>, <F9>, <q> or <Esc> to exit.\n"
 "\n"
 "\n"
 "Alternate Configuration Files\n"
@@ -1503,7 +1503,11 @@ int main(int ac, char **av)
        }
 
        notimeout(stdscr, FALSE);
+#if NCURSES_REENTRANT
+       set_escdelay(1);
+#else
        ESCDELAY = 1;
+#endif
 
        /* set btns menu */
        curses_menu = new_menu(curses_menu_items);
index 3b18dd839668b295cd3d06b1c4cac3d4c941ddf3..379003c7a2b4d8cef60e25548fcb9567ca3656c5 100644 (file)
@@ -604,9 +604,11 @@ void show_scroll_win(WINDOW *main_window,
                switch (res) {
                case KEY_NPAGE:
                case ' ':
+               case 'd':
                        start_y += text_lines-2;
                        break;
                case KEY_PPAGE:
+               case 'u':
                        start_y -= text_lines+2;
                        break;
                case KEY_HOME:
@@ -632,10 +634,10 @@ void show_scroll_win(WINDOW *main_window,
                        start_x++;
                        break;
                }
-               if (res == 10 || res == 27 || res == 'q'
-                   || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) {
+               if (res == 10 || res == 27 || res == 'q' ||
+                       res == KEY_F(F_HELP) || res == KEY_F(F_BACK) ||
+                       res == KEY_F(F_EXIT))
                        break;
-               }
                if (start_y < 0)
                        start_y = 0;
                if (start_y >= total_lines-text_lines)
index bccf07ddd0b67a0e2f761fd5721f274a49bf9bbb..2fbbbc1ddea02ad573315ef264fc5c79064a1f5e 100644 (file)
 use strict;
 use Getopt::Long;
 
+# set the environment variable LOCALMODCONFIG_DEBUG to get
+# debug output.
+my $debugprint = 0;
+$debugprint = 1 if (defined($ENV{LOCALMODCONFIG_DEBUG}));
+
+sub dprint {
+    return if (!$debugprint);
+    print STDERR @_;
+}
+
 my $config = ".config";
 
 my $uname = `uname -r`;
@@ -113,6 +123,10 @@ sub find_config {
 
 find_config;
 
+# Read in the entire config file into config_file
+my @config_file = <CIN>;
+close CIN;
+
 # Parse options
 my $localmodconfig = 0;
 my $localyesconfig = 0;
@@ -186,6 +200,7 @@ sub read_kconfig {
            $state = "NEW";
            $config = $2;
 
+           # Add depends for 'if' nesting
            for (my $i = 0; $i < $iflevel; $i++) {
                if ($i) {
                    $depends{$config} .= " " . $ifdeps[$i];
@@ -204,10 +219,11 @@ sub read_kconfig {
 
        # Get the configs that select this config
        } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) {
-           if (defined($selects{$1})) {
-               $selects{$1} .= " " . $config;
+           my $conf = $1;
+           if (defined($selects{$conf})) {
+               $selects{$conf} .= " " . $config;
            } else {
-               $selects{$1} = $config;
+               $selects{$conf} = $config;
            }
 
        # configs without prompts must be selected
@@ -250,6 +266,7 @@ if ($kconfig) {
     read_kconfig($kconfig);
 }
 
+# Makefiles can use variables to define their dependencies
 sub convert_vars {
     my ($line, %vars) = @_;
 
@@ -293,6 +310,7 @@ foreach my $makefile (@makefiles) {
 
        my $objs;
 
+       # Convert variables in a line (could define configs)
        $_ = convert_vars($_, %make_vars);
 
        # collect objects after obj-$(CONFIG_FOO_BAR)
@@ -373,13 +391,15 @@ while (<LIN>) {
 close (LIN);
 
 # add to the configs hash all configs that are needed to enable
-# a loaded module.
+# a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o
+# where we know we need bar.o so we add FOO to the list.
 my %configs;
 foreach my $module (keys(%modules)) {
     if (defined($objects{$module})) {
        my @arr = @{$objects{$module}};
        foreach my $conf (@arr) {
            $configs{$conf} = $module;
+           dprint "$conf added by direct ($module)\n";
        }
     } else {
        # Most likely, someone has a custom (binary?) module loaded.
@@ -387,9 +407,24 @@ foreach my $module (keys(%modules)) {
     }
 }
 
+# Read the current config, and see what is enabled. We want to
+# ignore configs that we would not enable anyway.
+
+my %orig_configs;
 my $valid = "A-Za-z_0-9";
+
+foreach my $line (@config_file) {
+    $_ = $line;
+
+    if (/(CONFIG_[$valid]*)=(m|y)/) {
+       $orig_configs{$1} = $2;
+    }
+}
+
 my $repeat = 1;
 
+my $depconfig;
+
 #
 # Note, we do not care about operands (like: &&, ||, !) we want to add any
 # config that is in the depend list of another config. This script does
@@ -398,7 +433,7 @@ my $repeat = 1;
 # to keep on. If A was on in the original config, B would not have been
 # and B would not be turned on by this script.
 #
-sub parse_config_dep_select
+sub parse_config_depends
 {
     my ($p) = @_;
 
@@ -409,10 +444,16 @@ sub parse_config_dep_select
 
            $p =~ s/^[^$valid]*[$valid]+//;
 
+           # We only need to process if the depend config is a module
+           if (!defined($orig_configs{$conf}) || !$orig_configs{conf} eq "m") {
+               next;
+           }
+
            if (!defined($configs{$conf})) {
                # We must make sure that this config has its
                # dependencies met.
                $repeat = 1; # do again
+               dprint "$conf selected by depend $depconfig\n";
                $configs{$conf} = 1;
            }
        } else {
@@ -421,31 +462,132 @@ sub parse_config_dep_select
     }
 }
 
-while ($repeat) {
-    $repeat = 0;
+# Select is treated a bit differently than depends. We call this
+# when a config has no prompt and requires another config to be
+# selected. We use to just select all configs that selected this
+# config, but found that that can balloon into enabling hundreds
+# of configs that we do not care about.
+#
+# The idea is we look at all the configs that select it. If one
+# is already in our list of configs to enable, then there's nothing
+# else to do. If there isn't, we pick the first config that was
+# enabled in the orignal config and use that.
+sub parse_config_selects
+{
+    my ($config, $p) = @_;
 
-    foreach my $config (keys %configs) {
-       $config =~ s/^CONFIG_//;
+    my $next_config;
+
+    while ($p =~ /[$valid]/) {
 
-       if (defined($depends{$config})) {
-           # This config has dependencies. Make sure they are also included
-           parse_config_dep_select $depends{$config};
+       if ($p =~ /^[^$valid]*([$valid]+)/) {
+           my $conf = "CONFIG_" . $1;
+
+           $p =~ s/^[^$valid]*[$valid]+//;
+
+           # Make sure that this config exists in the current .config file
+           if (!defined($orig_configs{$conf})) {
+               dprint "$conf not set for $config select\n";
+               next;
+           }
+
+           # Check if something other than a module selects this config
+           if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") {
+               dprint "$conf (non module) selects config, we are good\n";
+               # we are good with this
+               return;
+           }
+           if (defined($configs{$conf})) {
+               dprint "$conf selects $config so we are good\n";
+               # A set config selects this config, we are good
+               return;
+           }
+           # Set this config to be selected
+           if (!defined($next_config)) {
+               $next_config = $conf;
+           }
+       } else {
+           die "this should never happen";
        }
+    }
 
-       if (defined($prompts{$config}) || !defined($selects{$config})) {
-           next;
+    # If no possible config selected this, then something happened.
+    if (!defined($next_config)) {
+       print STDERR "WARNING: $config is required, but nothing in the\n";
+       print STDERR "  current config selects it.\n";
+       return;
+    }
+
+    # If we are here, then we found no config that is set and
+    # selects this config. Repeat.
+    $repeat = 1;
+    # Make this config need to be selected
+    $configs{$next_config} = 1;
+    dprint "$next_config selected by select $config\n";
+}
+
+my %process_selects;
+
+# loop through all configs, select their dependencies.
+sub loop_depend {
+    $repeat = 1;
+
+    while ($repeat) {
+       $repeat = 0;
+
+      forloop:
+       foreach my $config (keys %configs) {
+
+           # If this config is not a module, we do not need to process it
+           if (defined($orig_configs{$config}) && $orig_configs{$config} ne "m") {
+               next forloop;
+           }
+
+           $config =~ s/^CONFIG_//;
+           $depconfig = $config;
+
+           if (defined($depends{$config})) {
+               # This config has dependencies. Make sure they are also included
+               parse_config_depends $depends{$config};
+           }
+
+           # If the config has no prompt, then we need to check if a config
+           # that is enabled selected it. Or if we need to enable one.
+           if (!defined($prompts{$config}) && defined($selects{$config})) {
+               $process_selects{$config} = 1;
+           }
        }
+    }
+}
+
+sub loop_select {
+
+    foreach my $config (keys %process_selects) {
+       $config =~ s/^CONFIG_//;
+
+       dprint "Process select $config\n";
 
        # config has no prompt and must be selected.
-       parse_config_dep_select $selects{$config};
+       parse_config_selects $config, $selects{$config};
     }
 }
 
+while ($repeat) {
+    # Get the first set of configs and their dependencies.
+    loop_depend;
+
+    $repeat = 0;
+
+    # Now we need to see if we have to check selects;
+    loop_select;
+}          
+
 my %setconfigs;
 
 # Finally, read the .config file and turn off any module enabled that
 # we could not find a reason to keep enabled.
-while(<CIN>) {
+foreach my $line (@config_file) {
+    $_ = $line;
 
     if (/CONFIG_IKCONFIG/) {
        if (/# CONFIG_IKCONFIG is not set/) {
@@ -473,7 +615,6 @@ while(<CIN>) {
     }
     print;
 }
-close(CIN);
 
 # Integrity check, make sure all modules that we want enabled do
 # indeed have their configs set.
index cd9c6c6bb4c9d9dba4f9c80fc5edbb67170beef8..4629038c9e5acb677499ace431355a818ee4b3d6 100644 (file)
@@ -210,8 +210,8 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then
        mksysmap ${kallsyms_vmlinux} .tmp_System.map
 
        if ! cmp -s System.map .tmp_System.map; then
-               echo Inconsistent kallsyms data
-               echo echo Try "make KALLSYMS_EXTRA_PASS=1" as a workaround
+               echo >&2 Inconsistent kallsyms data
+               echo >&2 echo Try "make KALLSYMS_EXTRA_PASS=1" as a workaround
                cleanup
                exit 1
        fi
index c95fdda584147de330a53ef49b165304f6c8625c..acb86507828aaba1304594588959fbfc2804c528 100644 (file)
@@ -92,7 +92,7 @@ rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir"
 mkdir -m 755 -p "$tmpdir/DEBIAN"
 mkdir -p  "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename"
 mkdir -m 755 -p "$fwdir/DEBIAN"
-mkdir -p "$fwdir/lib" "$fwdir/usr/share/doc/$fwpackagename"
+mkdir -p "$fwdir/lib/firmware/$version/" "$fwdir/usr/share/doc/$fwpackagename"
 mkdir -m 755 -p "$libc_headers_dir/DEBIAN"
 mkdir -p "$libc_headers_dir/usr/share/doc/$libc_headers_packagename"
 mkdir -m 755 -p "$kernel_headers_dir/DEBIAN"
@@ -243,7 +243,7 @@ EOF
 fi
 
 # Build header package
-(cd $srctree; find . -name Makefile -o -name Kconfig\* -o -name \*.pl > "$objtree/debian/hdrsrcfiles")
+(cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl > "$objtree/debian/hdrsrcfiles")
 (cd $srctree; find arch/$SRCARCH/include include scripts -type f >> "$objtree/debian/hdrsrcfiles")
 (cd $objtree; find arch/$SRCARCH/include .config Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles")
 destdir=$kernel_headers_dir/usr/src/linux-headers-$version
@@ -267,7 +267,8 @@ EOF
 
 # Do we have firmware? Move it out of the way and build it into a package.
 if [ -e "$tmpdir/lib/firmware" ]; then
-       mv "$tmpdir/lib/firmware" "$fwdir/lib/"
+       mv "$tmpdir/lib/firmware"/* "$fwdir/lib/firmware/$version/"
+       rmdir "$tmpdir/lib/firmware"
 
        cat <<EOF >> debian/control
 
index 1ca9ceb95eb6413161f0844ca491ba4e1260f711..6acf834491050237548163230a2b89e7e53b9b61 100644 (file)
@@ -247,6 +247,7 @@ do_file(char const *const fname)
        case EM_X86_64:
                custom_sort = sort_x86_table;
                break;
+       case EM_S390:
        case EM_MIPS:
                break;
        }  /* end switch */
index cf7b12fee573174c8aaf00ee75aa9d21c056d61d..cff8faad73d15dab529f71943e5c5544b2ad9217 100755 (executable)
@@ -153,7 +153,8 @@ exuberant()
        --regex-c++='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/'      \
        --regex-c++='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/'  \
        --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \
-       --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/'
+       --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \
+       --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
 
        all_kconfigs | xargs $1 -a                              \
        --langdef=kconfig --language-force=kconfig              \
@@ -195,7 +196,8 @@ emacs()
        --regex='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/'  \
        --regex='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \
        --regex='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \
-       --regex='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/'
+       --regex='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \
+       --regex='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
 
        all_kconfigs | xargs $1 -a                              \
        --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/'
index 94c45a1531a4c1199535b38a5eb0041075b29ce4..6c77f63c759198ead061712fb3bad1166c4ace2a 100644 (file)
@@ -2791,11 +2791,16 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
 
                        /* We strip a nul only if it is at the end, otherwise the
                         * context contains a nul and we should audit that */
-                       str = value;
-                       if (str[size - 1] == '\0')
-                               audit_size = size - 1;
-                       else
-                               audit_size = size;
+                       if (value) {
+                               str = value;
+                               if (str[size - 1] == '\0')
+                                       audit_size = size - 1;
+                               else
+                                       audit_size = size;
+                       } else {
+                               str = "";
+                               audit_size = 0;
+                       }
                        ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR);
                        audit_log_format(ab, "op=setxattr invalid_context=");
                        audit_log_n_untrustedstring(ab, value, audit_size);
@@ -3180,6 +3185,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
        case F_GETFL:
        case F_GETOWN:
        case F_GETSIG:
+       case F_GETOWNER_UIDS:
                /* Just check FD__USE permission */
                err = file_has_perm(cred, file, 0);
                break;
index d31e6d957c21a47733ca1d73e8a43ef7d3fae22c..b1b768e4049af3304d457451f06c8fa834909b89 100644 (file)
@@ -323,11 +323,11 @@ static int smk_parse_long_rule(const char *data, struct smack_rule *rule,
        int datalen;
        int rc = -1;
 
-       /*
-        * This is probably inefficient, but safe.
-        */
+       /* This is inefficient */
        datalen = strlen(data);
-       subject = kzalloc(datalen, GFP_KERNEL);
+
+       /* Our first element can be 64 + \0 with no spaces */
+       subject = kzalloc(datalen + 1, GFP_KERNEL);
        if (subject == NULL)
                return -1;
        object = kzalloc(datalen, GFP_KERNEL);
index 768167925409ecb9be45b3c2ac82c885685da9bc..30e027ecf4da7383c7e6045f0b9a9f9905ca63b4 100644 (file)
@@ -68,6 +68,7 @@ void __snd_printk(unsigned int level, const char *path, int line,
 {
        va_list args;
 #ifdef CONFIG_SND_VERBOSE_PRINTK
+       int kern_level;
        struct va_format vaf;
        char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV";
 #endif
@@ -81,12 +82,16 @@ void __snd_printk(unsigned int level, const char *path, int line,
 #ifdef CONFIG_SND_VERBOSE_PRINTK
        vaf.fmt = format;
        vaf.va = &args;
-       if (format[0] == '<' && format[2] == '>') {
-               memcpy(verbose_fmt, format, 3);
-               vaf.fmt = format + 3;
+
+       kern_level = printk_get_level(format);
+       if (kern_level) {
+               const char *end_of_header = printk_skip_level(format);
+               memcpy(verbose_fmt, format, end_of_header - format);
+               vaf.fmt = end_of_header;
        } else if (level)
-               memcpy(verbose_fmt, KERN_DEBUG, 3);
+               memcpy(verbose_fmt, KERN_DEBUG, sizeof(KERN_DEBUG) - 1);
        printk(verbose_fmt, sanity_file_name(path), line, &vaf);
+
 #else
        vprintk(format, args);
 #endif
index 7eca25fae4137947ebf933451e2d2964d2bd9d40..b29b88f93c9e07e8e1860881576043c19c734f6e 100644 (file)
@@ -197,6 +197,8 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        strcpy(v->name, "FM");
        v->type = V4L2_TUNER_RADIO;
        v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+       if (!tea->cannot_read_data)
+               v->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED;
        v->rangelow = FREQ_LO;
        v->rangehigh = FREQ_HI;
        v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
@@ -305,7 +307,7 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *fh,
        }
        tea->val &= ~TEA575X_BIT_SEARCH;
        snd_tea575x_set_freq(tea);
-       return -EAGAIN;
+       return -ENODATA;
 }
 
 static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
index 0ff1e70b7770da5edac83ddafc7a7ac39f2fbd7c..c084c549942ecef39ffa52788524125b2c8ef1b6 100644 (file)
@@ -653,7 +653,7 @@ int twl6040_get_hs_step_size(struct snd_soc_codec *codec)
 {
        struct twl6040 *twl6040 = codec->control_data;
 
-       if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_2)
+       if (twl6040_get_revid(twl6040) < TWL6040_REV_ES1_3)
                /* For ES under ES_1.3 HS step is 2 mV */
                return 2;
        else
diff --git a/tools/lib/traceevent/.gitignore b/tools/lib/traceevent/.gitignore
new file mode 100644 (file)
index 0000000..35f56be
--- /dev/null
@@ -0,0 +1 @@
+TRACEEVENT-CFLAGS
index 46c2f6b7b123c388d056ae6c324cdde76edef182..14131cb0522d3e7983fc4efc730bb5f30e6ee8ef 100644 (file)
@@ -207,7 +207,7 @@ libtraceevent.so: $(PEVENT_LIB_OBJS)
 libtraceevent.a: $(PEVENT_LIB_OBJS)
        $(Q)$(do_build_static_lib)
 
-$(PEVENT_LIB_OBJS): %.o: $(src)/%.c
+$(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS
        $(Q)$(do_fpic_compile)
 
 define make_version.h
@@ -272,6 +272,16 @@ ifneq ($(dep_includes),)
  include $(dep_includes)
 endif
 
+### Detect environment changes
+TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE)
+
+TRACEEVENT-CFLAGS: force
+       @FLAGS='$(TRACK_CFLAGS)'; \
+           if test x"$$FLAGS" != x"`cat TRACEEVENT-CFLAGS 2>/dev/null`" ; then \
+               echo 1>&2 "    * new build flags or cross compiler"; \
+               echo "$$FLAGS" >TRACEEVENT-CFLAGS; \
+            fi
+
 tags:  force
        $(RM) tags
        find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
@@ -297,7 +307,7 @@ install: install_lib
 
 clean:
        $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d
-       $(RM) tags TAGS
+       $(RM) TRACEEVENT-CFLAGS tags TAGS
 
 endif # skip-makefile
 
index 75d74e5db8d552372aa0b7c19861c76458784f5e..77f124fe57ad54d8e45858f4e4429f6b63f42273 100644 (file)
@@ -354,6 +354,7 @@ LIB_OBJS += $(OUTPUT)util/usage.o
 LIB_OBJS += $(OUTPUT)util/wrapper.o
 LIB_OBJS += $(OUTPUT)util/sigchain.o
 LIB_OBJS += $(OUTPUT)util/symbol.o
+LIB_OBJS += $(OUTPUT)util/dso-test-data.o
 LIB_OBJS += $(OUTPUT)util/color.o
 LIB_OBJS += $(OUTPUT)util/pager.o
 LIB_OBJS += $(OUTPUT)util/header.o
@@ -803,6 +804,9 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
+$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
+       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $<
+
 $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
 
index 5ce30305462b1775fbfc80f9569e29328d25edd3..d909eb74a0eb74bc46ec8a9e6cb9d8acca5da7f2 100644 (file)
@@ -1141,6 +1141,10 @@ static struct test {
                .desc = "Test perf pmu format parsing",
                .func = test__perf_pmu,
        },
+       {
+               .desc = "Test dso data interface",
+               .func = dso__test_data,
+       },
        {
                .func = NULL,
        },
index e3cab5f088f8def4264a0ec65dba4f85b0b0f954..35e86c6df713d7af91bc50f98953d55f08cc4162 100644 (file)
@@ -125,7 +125,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
        /*
         * We can't annotate with just /proc/kallsyms
         */
-       if (map->dso->symtab_type == SYMTAB__KALLSYMS) {
+       if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
                pr_err("Can't annotate %s: No vmlinux file was found in the "
                       "path\n", sym->name);
                sleep(1);
index 482f0517b61e20f61a18933133717ce53fc0e1c1..413bd62eedb14ab0a2a023b6ef8f654235e59cda 100644 (file)
@@ -978,8 +978,8 @@ static int hist_browser__dump(struct hist_browser *browser)
        fp = fopen(filename, "w");
        if (fp == NULL) {
                char bf[64];
-               strerror_r(errno, bf, sizeof(bf));
-               ui_helpline__fpush("Couldn't write to %s: %s", filename, bf);
+               const char *err = strerror_r(errno, bf, sizeof(bf));
+               ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
                return -1;
        }
 
index 8069dfb5ba7774bd89afd8e78b36f3faea15e907..3a282c0057d2266fa2adcdb00122bf3bfdb69c27 100644 (file)
@@ -426,7 +426,18 @@ int symbol__alloc_hist(struct symbol *sym)
 {
        struct annotation *notes = symbol__annotation(sym);
        const size_t size = symbol__size(sym);
-       size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
+       size_t sizeof_sym_hist;
+
+       /* Check for overflow when calculating sizeof_sym_hist */
+       if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64))
+               return -1;
+
+       sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
+
+       /* Check for overflow in zalloc argument */
+       if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src))
+                               / symbol_conf.nr_events)
+               return -1;
 
        notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
        if (notes->src == NULL)
@@ -777,7 +788,7 @@ fallback:
                free_filename = false;
        }
 
-       if (dso->symtab_type == SYMTAB__KALLSYMS) {
+       if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
                char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
                char *build_id_msg = NULL;
 
diff --git a/tools/perf/util/dso-test-data.c b/tools/perf/util/dso-test-data.c
new file mode 100644 (file)
index 0000000..541cdc7
--- /dev/null
@@ -0,0 +1,153 @@
+#include "util.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "symbol.h"
+
+#define TEST_ASSERT_VAL(text, cond) \
+do { \
+       if (!(cond)) { \
+               pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
+               return -1; \
+       } \
+} while (0)
+
+static char *test_file(int size)
+{
+       static char buf_templ[] = "/tmp/test-XXXXXX";
+       char *templ = buf_templ;
+       int fd, i;
+       unsigned char *buf;
+
+       fd = mkostemp(templ, O_CREAT|O_WRONLY|O_TRUNC);
+
+       buf = malloc(size);
+       if (!buf) {
+               close(fd);
+               return NULL;
+       }
+
+       for (i = 0; i < size; i++)
+               buf[i] = (unsigned char) ((int) i % 10);
+
+       if (size != write(fd, buf, size))
+               templ = NULL;
+
+       close(fd);
+       return templ;
+}
+
+#define TEST_FILE_SIZE (DSO__DATA_CACHE_SIZE * 20)
+
+struct test_data_offset {
+       off_t offset;
+       u8 data[10];
+       int size;
+};
+
+struct test_data_offset offsets[] = {
+       /* Fill first cache page. */
+       {
+               .offset = 10,
+               .data   = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+               .size   = 10,
+       },
+       /* Read first cache page. */
+       {
+               .offset = 10,
+               .data   = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+               .size   = 10,
+       },
+       /* Fill cache boundary pages. */
+       {
+               .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
+               .data   = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+               .size   = 10,
+       },
+       /* Read cache boundary pages. */
+       {
+               .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
+               .data   = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+               .size   = 10,
+       },
+       /* Fill final cache page. */
+       {
+               .offset = TEST_FILE_SIZE - 10,
+               .data   = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+               .size   = 10,
+       },
+       /* Read final cache page. */
+       {
+               .offset = TEST_FILE_SIZE - 10,
+               .data   = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+               .size   = 10,
+       },
+       /* Read final cache page. */
+       {
+               .offset = TEST_FILE_SIZE - 3,
+               .data   = { 7, 8, 9, 0, 0, 0, 0, 0, 0, 0 },
+               .size   = 3,
+       },
+};
+
+int dso__test_data(void)
+{
+       struct machine machine;
+       struct dso *dso;
+       char *file = test_file(TEST_FILE_SIZE);
+       size_t i;
+
+       TEST_ASSERT_VAL("No test file", file);
+
+       memset(&machine, 0, sizeof(machine));
+
+       dso = dso__new((const char *)file);
+
+       /* Basic 10 bytes tests. */
+       for (i = 0; i < ARRAY_SIZE(offsets); i++) {
+               struct test_data_offset *data = &offsets[i];
+               ssize_t size;
+               u8 buf[10];
+
+               memset(buf, 0, 10);
+               size = dso__data_read_offset(dso, &machine, data->offset,
+                                    buf, 10);
+
+               TEST_ASSERT_VAL("Wrong size", size == data->size);
+               TEST_ASSERT_VAL("Wrong data", !memcmp(buf, data->data, 10));
+       }
+
+       /* Read cross multiple cache pages. */
+       {
+               ssize_t size;
+               int c;
+               u8 *buf;
+
+               buf = malloc(TEST_FILE_SIZE);
+               TEST_ASSERT_VAL("ENOMEM\n", buf);
+
+               /* First iteration to fill caches, second one to read them. */
+               for (c = 0; c < 2; c++) {
+                       memset(buf, 0, TEST_FILE_SIZE);
+                       size = dso__data_read_offset(dso, &machine, 10,
+                                                    buf, TEST_FILE_SIZE);
+
+                       TEST_ASSERT_VAL("Wrong size",
+                               size == (TEST_FILE_SIZE - 10));
+
+                       for (i = 0; i < (size_t)size; i++)
+                               TEST_ASSERT_VAL("Wrong data",
+                                       buf[i] == (i % 10));
+               }
+
+               free(buf);
+       }
+
+       dso__delete(dso);
+       unlink(file);
+       return 0;
+}
index f74e9560350eb3dccfe7cc47c6a13e6256f91bb4..3edfd3483816dfa88ac49dc966d0c2a4db2b5923 100644 (file)
@@ -214,7 +214,7 @@ int perf_evlist__add_tracepoints(struct perf_evlist *evlist,
                attrs[i].type          = PERF_TYPE_TRACEPOINT;
                attrs[i].config        = err;
                attrs[i].sample_type   = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
-                                         PERF_SAMPLE_CPU);
+                                         PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD);
                attrs[i].sample_period = 1;
        }
 
index 5a47aba46759274f7f542e533bae4a62749d565a..3a6d20443330b13d74b2b69b4c1d0e39cd5bb678 100644 (file)
@@ -1212,6 +1212,12 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
                                attr.exclude_user,
                                attr.exclude_kernel);
 
+               fprintf(fp, ", excl_host = %d, excl_guest = %d",
+                               attr.exclude_host,
+                               attr.exclude_guest);
+
+               fprintf(fp, ", precise_ip = %d", attr.precise_ip);
+
                if (nr)
                        fprintf(fp, ", id = {");
 
index 514e2a4b367d6d53838d9ac726a063b0ba3bf5e8..f247ef2789a4d77ffe4ee1e9c9d981d065775c3f 100644 (file)
@@ -708,7 +708,7 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
        bool printed = false;
        struct rb_node *node;
        int i = 0;
-       int ret;
+       int ret = 0;
 
        /*
         * If have one single callchain root, don't bother printing
@@ -747,8 +747,11 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
                root = &cnode->rb_root;
        }
 
-       return __callchain__fprintf_graph(fp, root, total_samples,
+       ret += __callchain__fprintf_graph(fp, root, total_samples,
                                          1, 1, left_margin);
+       ret += fprintf(fp, "\n");
+
+       return ret;
 }
 
 static size_t __callchain__fprintf_flat(FILE *fp,
index a1f4e3669142630aa641d1a34b0f53673b6b67b0..cc33486ad9e25b80e8486a4c60fce41d03a60b15 100644 (file)
@@ -7,6 +7,8 @@
 #include <stdio.h>
 #include <unistd.h>
 #include "map.h"
+#include "thread.h"
+#include "strlist.h"
 
 const char *map_type__name[MAP__NR_TYPES] = {
        [MAP__FUNCTION] = "Functions",
@@ -585,7 +587,21 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid)
        self->kmaps.machine = self;
        self->pid           = pid;
        self->root_dir      = strdup(root_dir);
-       return self->root_dir == NULL ? -ENOMEM : 0;
+       if (self->root_dir == NULL)
+               return -ENOMEM;
+
+       if (pid != HOST_KERNEL_ID) {
+               struct thread *thread = machine__findnew_thread(self, pid);
+               char comm[64];
+
+               if (thread == NULL)
+                       return -ENOMEM;
+
+               snprintf(comm, sizeof(comm), "[guest/%d]", pid);
+               thread__set_comm(thread, comm);
+       }
+
+       return 0;
 }
 
 static void dsos__delete(struct list_head *self)
@@ -680,7 +696,15 @@ struct machine *machines__findnew(struct rb_root *self, pid_t pid)
            (symbol_conf.guestmount)) {
                sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
                if (access(path, R_OK)) {
-                       pr_err("Can't access file %s\n", path);
+                       static struct strlist *seen;
+
+                       if (!seen)
+                               seen = strlist__new(true, NULL);
+
+                       if (!strlist__has_entry(seen, path)) {
+                               pr_err("Can't access file %s\n", path);
+                               strlist__add(seen, path);
+                       }
                        machine = NULL;
                        goto out;
                }
@@ -714,3 +738,16 @@ char *machine__mmap_name(struct machine *self, char *bf, size_t size)
 
        return bf;
 }
+
+void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size)
+{
+       struct rb_node *node;
+       struct machine *machine;
+
+       for (node = rb_first(machines); node; node = rb_next(node)) {
+               machine = rb_entry(node, struct machine, rb_node);
+               machine->id_hdr_size = id_hdr_size;
+       }
+
+       return;
+}
index c14c665d9a259c8c5c9aed791a32f2096eff6bb0..03a1e9b08b21a81f4cbdcc7834eb6f6bb7e6c8d1 100644 (file)
@@ -151,6 +151,7 @@ struct machine *machines__add(struct rb_root *self, pid_t pid,
 struct machine *machines__find_host(struct rb_root *self);
 struct machine *machines__find(struct rb_root *self, pid_t pid);
 struct machine *machines__findnew(struct rb_root *self, pid_t pid);
+void machines__set_id_hdr_size(struct rb_root *self, u16 id_hdr_size);
 char *machine__mmap_name(struct machine *self, char *bf, size_t size);
 int machine__init(struct machine *self, const char *root_dir, pid_t pid);
 void machine__exit(struct machine *self);
index 1aa721d7c10f33d84bbd63f8761ed67f18fbe86c..74a5af4d33ec5fc4720639c7634d37cf94e54a92 100644 (file)
@@ -377,6 +377,7 @@ static int add_tracepoint(struct list_head **list, int *idx,
        attr.sample_type |= PERF_SAMPLE_RAW;
        attr.sample_type |= PERF_SAMPLE_TIME;
        attr.sample_type |= PERF_SAMPLE_CPU;
+       attr.sample_type |= PERF_SAMPLE_PERIOD;
        attr.sample_period = 1;
 
        snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
@@ -489,6 +490,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
                attr.bp_len = HW_BREAKPOINT_LEN_4;
 
        attr.type = PERF_TYPE_BREAKPOINT;
+       attr.sample_period = 1;
 
        return add_event(list, idx, &attr, NULL);
 }
index 8e485592ca200c1712d1c959296230f9dce50d33..8e4f0755d2aa8364d81fa714888d622d61f6a2db 100644 (file)
@@ -87,6 +87,7 @@ void perf_session__update_sample_type(struct perf_session *self)
        self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
        self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist);
        self->host_machine.id_hdr_size = self->id_hdr_size;
+       machines__set_id_hdr_size(&self->machines, self->id_hdr_size);
 }
 
 int perf_session__create_kernel_maps(struct perf_session *self)
@@ -918,7 +919,9 @@ static struct machine *
 {
        const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
-       if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
+       if (perf_guest &&
+           ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) ||
+            (cpumode == PERF_RECORD_MISC_GUEST_USER))) {
                u32 pid;
 
                if (event->header.type == PERF_RECORD_MMAP)
index 50958bbeb26aa0c0d19f92deb830649cd43d5100..fdad4eeeb429c1fce9ef90125aab3e4a288c6066 100644 (file)
@@ -29,6 +29,7 @@
 #define NT_GNU_BUILD_ID 3
 #endif
 
+static void dso_cache__free(struct rb_root *root);
 static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
 static int elf_read_build_id(Elf *elf, void *bf, size_t size);
 static void dsos__add(struct list_head *head, struct dso *dso);
@@ -48,6 +49,31 @@ struct symbol_conf symbol_conf = {
        .symfs            = "",
 };
 
+static enum dso_binary_type binary_type_symtab[] = {
+       DSO_BINARY_TYPE__KALLSYMS,
+       DSO_BINARY_TYPE__GUEST_KALLSYMS,
+       DSO_BINARY_TYPE__JAVA_JIT,
+       DSO_BINARY_TYPE__DEBUGLINK,
+       DSO_BINARY_TYPE__BUILD_ID_CACHE,
+       DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
+       DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
+       DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
+       DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
+       DSO_BINARY_TYPE__GUEST_KMODULE,
+       DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+       DSO_BINARY_TYPE__NOT_FOUND,
+};
+
+#define DSO_BINARY_TYPE__SYMTAB_CNT sizeof(binary_type_symtab)
+
+static enum dso_binary_type binary_type_data[] = {
+       DSO_BINARY_TYPE__BUILD_ID_CACHE,
+       DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
+       DSO_BINARY_TYPE__NOT_FOUND,
+};
+
+#define DSO_BINARY_TYPE__DATA_CNT sizeof(binary_type_data)
+
 int dso__name_len(const struct dso *dso)
 {
        if (!dso)
@@ -318,7 +344,9 @@ struct dso *dso__new(const char *name)
                dso__set_short_name(dso, dso->name);
                for (i = 0; i < MAP__NR_TYPES; ++i)
                        dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
-               dso->symtab_type = SYMTAB__NOT_FOUND;
+               dso->cache = RB_ROOT;
+               dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
+               dso->data_type   = DSO_BINARY_TYPE__NOT_FOUND;
                dso->loaded = 0;
                dso->sorted_by_name = 0;
                dso->has_build_id = 0;
@@ -352,6 +380,7 @@ void dso__delete(struct dso *dso)
                free((char *)dso->short_name);
        if (dso->lname_alloc)
                free(dso->long_name);
+       dso_cache__free(&dso->cache);
        free(dso);
 }
 
@@ -806,9 +835,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
        symbols__fixup_end(&dso->symbols[map->type]);
 
        if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
-               dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
+               dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
        else
-               dso->symtab_type = SYMTAB__KALLSYMS;
+               dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
 
        return dso__split_kallsyms(dso, map, filter);
 }
@@ -1660,32 +1689,110 @@ out:
 char dso__symtab_origin(const struct dso *dso)
 {
        static const char origin[] = {
-               [SYMTAB__KALLSYMS]            = 'k',
-               [SYMTAB__JAVA_JIT]            = 'j',
-               [SYMTAB__DEBUGLINK]           = 'l',
-               [SYMTAB__BUILD_ID_CACHE]      = 'B',
-               [SYMTAB__FEDORA_DEBUGINFO]    = 'f',
-               [SYMTAB__UBUNTU_DEBUGINFO]    = 'u',
-               [SYMTAB__BUILDID_DEBUGINFO]   = 'b',
-               [SYMTAB__SYSTEM_PATH_DSO]     = 'd',
-               [SYMTAB__SYSTEM_PATH_KMODULE] = 'K',
-               [SYMTAB__GUEST_KALLSYMS]      =  'g',
-               [SYMTAB__GUEST_KMODULE]       =  'G',
+               [DSO_BINARY_TYPE__KALLSYMS]             = 'k',
+               [DSO_BINARY_TYPE__JAVA_JIT]             = 'j',
+               [DSO_BINARY_TYPE__DEBUGLINK]            = 'l',
+               [DSO_BINARY_TYPE__BUILD_ID_CACHE]       = 'B',
+               [DSO_BINARY_TYPE__FEDORA_DEBUGINFO]     = 'f',
+               [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO]     = 'u',
+               [DSO_BINARY_TYPE__BUILDID_DEBUGINFO]    = 'b',
+               [DSO_BINARY_TYPE__SYSTEM_PATH_DSO]      = 'd',
+               [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE]  = 'K',
+               [DSO_BINARY_TYPE__GUEST_KALLSYMS]       = 'g',
+               [DSO_BINARY_TYPE__GUEST_KMODULE]        = 'G',
        };
 
-       if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND)
+       if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
                return '!';
        return origin[dso->symtab_type];
 }
 
+int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
+                         char *root_dir, char *file, size_t size)
+{
+       char build_id_hex[BUILD_ID_SIZE * 2 + 1];
+       int ret = 0;
+
+       switch (type) {
+       case DSO_BINARY_TYPE__DEBUGLINK: {
+               char *debuglink;
+
+               strncpy(file, dso->long_name, size);
+               debuglink = file + dso->long_name_len;
+               while (debuglink != file && *debuglink != '/')
+                       debuglink--;
+               if (*debuglink == '/')
+                       debuglink++;
+               filename__read_debuglink(dso->long_name, debuglink,
+                                        size - (debuglink - file));
+               }
+               break;
+       case DSO_BINARY_TYPE__BUILD_ID_CACHE:
+               /* skip the locally configured cache if a symfs is given */
+               if (symbol_conf.symfs[0] ||
+                   (dso__build_id_filename(dso, file, size) == NULL))
+                       ret = -1;
+               break;
+
+       case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
+               snprintf(file, size, "%s/usr/lib/debug%s.debug",
+                        symbol_conf.symfs, dso->long_name);
+               break;
+
+       case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
+               snprintf(file, size, "%s/usr/lib/debug%s",
+                        symbol_conf.symfs, dso->long_name);
+               break;
+
+       case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
+               if (!dso->has_build_id) {
+                       ret = -1;
+                       break;
+               }
+
+               build_id__sprintf(dso->build_id,
+                                 sizeof(dso->build_id),
+                                 build_id_hex);
+               snprintf(file, size,
+                        "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
+                        symbol_conf.symfs, build_id_hex, build_id_hex + 2);
+               break;
+
+       case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
+               snprintf(file, size, "%s%s",
+                        symbol_conf.symfs, dso->long_name);
+               break;
+
+       case DSO_BINARY_TYPE__GUEST_KMODULE:
+               snprintf(file, size, "%s%s%s", symbol_conf.symfs,
+                        root_dir, dso->long_name);
+               break;
+
+       case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+               snprintf(file, size, "%s%s", symbol_conf.symfs,
+                        dso->long_name);
+               break;
+
+       default:
+       case DSO_BINARY_TYPE__KALLSYMS:
+       case DSO_BINARY_TYPE__GUEST_KALLSYMS:
+       case DSO_BINARY_TYPE__JAVA_JIT:
+       case DSO_BINARY_TYPE__NOT_FOUND:
+               ret = -1;
+               break;
+       }
+
+       return ret;
+}
+
 int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 {
-       int size = PATH_MAX;
        char *name;
        int ret = -1;
        int fd;
+       u_int i;
        struct machine *machine;
-       const char *root_dir;
+       char *root_dir = (char *) "";
        int want_symtab;
 
        dso__set_loaded(dso, map->type);
@@ -1700,7 +1807,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
        else
                machine = NULL;
 
-       name = malloc(size);
+       name = malloc(PATH_MAX);
        if (!name)
                return -1;
 
@@ -1719,81 +1826,27 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
                }
 
                ret = dso__load_perf_map(dso, map, filter);
-               dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
-                                             SYMTAB__NOT_FOUND;
+               dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
+                                            DSO_BINARY_TYPE__NOT_FOUND;
                return ret;
        }
 
+       if (machine)
+               root_dir = machine->root_dir;
+
        /* Iterate over candidate debug images.
         * On the first pass, only load images if they have a full symtab.
         * Failing that, do a second pass where we accept .dynsym also
         */
        want_symtab = 1;
 restart:
-       for (dso->symtab_type = SYMTAB__DEBUGLINK;
-            dso->symtab_type != SYMTAB__NOT_FOUND;
-            dso->symtab_type++) {
-               switch (dso->symtab_type) {
-               case SYMTAB__DEBUGLINK: {
-                       char *debuglink;
-                       strncpy(name, dso->long_name, size);
-                       debuglink = name + dso->long_name_len;
-                       while (debuglink != name && *debuglink != '/')
-                               debuglink--;
-                       if (*debuglink == '/')
-                               debuglink++;
-                       filename__read_debuglink(dso->long_name, debuglink,
-                                                size - (debuglink - name));
-                       }
-                       break;
-               case SYMTAB__BUILD_ID_CACHE:
-                       /* skip the locally configured cache if a symfs is given */
-                       if (symbol_conf.symfs[0] ||
-                           (dso__build_id_filename(dso, name, size) == NULL)) {
-                               continue;
-                       }
-                       break;
-               case SYMTAB__FEDORA_DEBUGINFO:
-                       snprintf(name, size, "%s/usr/lib/debug%s.debug",
-                                symbol_conf.symfs, dso->long_name);
-                       break;
-               case SYMTAB__UBUNTU_DEBUGINFO:
-                       snprintf(name, size, "%s/usr/lib/debug%s",
-                                symbol_conf.symfs, dso->long_name);
-                       break;
-               case SYMTAB__BUILDID_DEBUGINFO: {
-                       char build_id_hex[BUILD_ID_SIZE * 2 + 1];
+       for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
 
-                       if (!dso->has_build_id)
-                               continue;
+               dso->symtab_type = binary_type_symtab[i];
 
-                       build_id__sprintf(dso->build_id,
-                                         sizeof(dso->build_id),
-                                         build_id_hex);
-                       snprintf(name, size,
-                                "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
-                                symbol_conf.symfs, build_id_hex, build_id_hex + 2);
-                       }
-                       break;
-               case SYMTAB__SYSTEM_PATH_DSO:
-                       snprintf(name, size, "%s%s",
-                            symbol_conf.symfs, dso->long_name);
-                       break;
-               case SYMTAB__GUEST_KMODULE:
-                       if (map->groups && machine)
-                               root_dir = machine->root_dir;
-                       else
-                               root_dir = "";
-                       snprintf(name, size, "%s%s%s", symbol_conf.symfs,
-                                root_dir, dso->long_name);
-                       break;
-
-               case SYMTAB__SYSTEM_PATH_KMODULE:
-                       snprintf(name, size, "%s%s", symbol_conf.symfs,
-                                dso->long_name);
-                       break;
-               default:;
-               }
+               if (dso__binary_type_file(dso, dso->symtab_type,
+                                         root_dir, name, PATH_MAX))
+                       continue;
 
                /* Name is now the name of the next image to try */
                fd = open(name, O_RDONLY);
@@ -2010,9 +2063,9 @@ struct map *machine__new_module(struct machine *machine, u64 start,
                return NULL;
 
        if (machine__is_host(machine))
-               dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;
+               dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
        else
-               dso->symtab_type = SYMTAB__GUEST_KMODULE;
+               dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
        map_groups__insert(&machine->kmaps, map);
        return map;
 }
@@ -2564,8 +2617,15 @@ int machine__create_kernel_maps(struct machine *machine)
            __machine__create_kernel_maps(machine, kernel) < 0)
                return -1;
 
-       if (symbol_conf.use_modules && machine__create_modules(machine) < 0)
-               pr_debug("Problems creating module maps, continuing anyway...\n");
+       if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
+               if (machine__is_host(machine))
+                       pr_debug("Problems creating module maps, "
+                                "continuing anyway...\n");
+               else
+                       pr_debug("Problems creating module maps for guest %d, "
+                                "continuing anyway...\n", machine->pid);
+       }
+
        /*
         * Now that we have all the maps created, just set the ->end of them:
         */
@@ -2905,3 +2965,218 @@ struct map *dso__new_map(const char *name)
 
        return map;
 }
+
+static int open_dso(struct dso *dso, struct machine *machine)
+{
+       char *root_dir = (char *) "";
+       char *name;
+       int fd;
+
+       name = malloc(PATH_MAX);
+       if (!name)
+               return -ENOMEM;
+
+       if (machine)
+               root_dir = machine->root_dir;
+
+       if (dso__binary_type_file(dso, dso->data_type,
+                                 root_dir, name, PATH_MAX)) {
+               free(name);
+               return -EINVAL;
+       }
+
+       fd = open(name, O_RDONLY);
+       free(name);
+       return fd;
+}
+
+int dso__data_fd(struct dso *dso, struct machine *machine)
+{
+       int i = 0;
+
+       if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND)
+               return open_dso(dso, machine);
+
+       do {
+               int fd;
+
+               dso->data_type = binary_type_data[i++];
+
+               fd = open_dso(dso, machine);
+               if (fd >= 0)
+                       return fd;
+
+       } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND);
+
+       return -EINVAL;
+}
+
+static void
+dso_cache__free(struct rb_root *root)
+{
+       struct rb_node *next = rb_first(root);
+
+       while (next) {
+               struct dso_cache *cache;
+
+               cache = rb_entry(next, struct dso_cache, rb_node);
+               next = rb_next(&cache->rb_node);
+               rb_erase(&cache->rb_node, root);
+               free(cache);
+       }
+}
+
+static struct dso_cache*
+dso_cache__find(struct rb_root *root, u64 offset)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent = NULL;
+       struct dso_cache *cache;
+
+       while (*p != NULL) {
+               u64 end;
+
+               parent = *p;
+               cache = rb_entry(parent, struct dso_cache, rb_node);
+               end = cache->offset + DSO__DATA_CACHE_SIZE;
+
+               if (offset < cache->offset)
+                       p = &(*p)->rb_left;
+               else if (offset >= end)
+                       p = &(*p)->rb_right;
+               else
+                       return cache;
+       }
+       return NULL;
+}
+
+static void
+dso_cache__insert(struct rb_root *root, struct dso_cache *new)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent = NULL;
+       struct dso_cache *cache;
+       u64 offset = new->offset;
+
+       while (*p != NULL) {
+               u64 end;
+
+               parent = *p;
+               cache = rb_entry(parent, struct dso_cache, rb_node);
+               end = cache->offset + DSO__DATA_CACHE_SIZE;
+
+               if (offset < cache->offset)
+                       p = &(*p)->rb_left;
+               else if (offset >= end)
+                       p = &(*p)->rb_right;
+       }
+
+       rb_link_node(&new->rb_node, parent, p);
+       rb_insert_color(&new->rb_node, root);
+}
+
+static ssize_t
+dso_cache__memcpy(struct dso_cache *cache, u64 offset,
+                 u8 *data, u64 size)
+{
+       u64 cache_offset = offset - cache->offset;
+       u64 cache_size   = min(cache->size - cache_offset, size);
+
+       memcpy(data, cache->data + cache_offset, cache_size);
+       return cache_size;
+}
+
+static ssize_t
+dso_cache__read(struct dso *dso, struct machine *machine,
+                u64 offset, u8 *data, ssize_t size)
+{
+       struct dso_cache *cache;
+       ssize_t ret;
+       int fd;
+
+       fd = dso__data_fd(dso, machine);
+       if (fd < 0)
+               return -1;
+
+       do {
+               u64 cache_offset;
+
+               ret = -ENOMEM;
+
+               cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
+               if (!cache)
+                       break;
+
+               cache_offset = offset & DSO__DATA_CACHE_MASK;
+               ret = -EINVAL;
+
+               if (-1 == lseek(fd, cache_offset, SEEK_SET))
+                       break;
+
+               ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE);
+               if (ret <= 0)
+                       break;
+
+               cache->offset = cache_offset;
+               cache->size   = ret;
+               dso_cache__insert(&dso->cache, cache);
+
+               ret = dso_cache__memcpy(cache, offset, data, size);
+
+       } while (0);
+
+       if (ret <= 0)
+               free(cache);
+
+       close(fd);
+       return ret;
+}
+
+static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
+                             u64 offset, u8 *data, ssize_t size)
+{
+       struct dso_cache *cache;
+
+       cache = dso_cache__find(&dso->cache, offset);
+       if (cache)
+               return dso_cache__memcpy(cache, offset, data, size);
+       else
+               return dso_cache__read(dso, machine, offset, data, size);
+}
+
+ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
+                             u64 offset, u8 *data, ssize_t size)
+{
+       ssize_t r = 0;
+       u8 *p = data;
+
+       do {
+               ssize_t ret;
+
+               ret = dso_cache_read(dso, machine, offset, p, size);
+               if (ret < 0)
+                       return ret;
+
+               /* Reached EOF, return what we have. */
+               if (!ret)
+                       break;
+
+               BUG_ON(ret > size);
+
+               r      += ret;
+               p      += ret;
+               offset += ret;
+               size   -= ret;
+
+       } while (size);
+
+       return r;
+}
+
+ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
+                           struct machine *machine, u64 addr,
+                           u8 *data, ssize_t size)
+{
+       u64 offset = map->map_ip(map, addr);
+       return dso__data_read_offset(dso, machine, offset, data, size);
+}
index a884b99017f085c0dceb47e7b766dab8527dc7df..1fe733a1e21f2acb31282c9df562b34b0a03346f 100644 (file)
@@ -155,6 +155,21 @@ struct addr_location {
        s32           cpu;
 };
 
+enum dso_binary_type {
+       DSO_BINARY_TYPE__KALLSYMS = 0,
+       DSO_BINARY_TYPE__GUEST_KALLSYMS,
+       DSO_BINARY_TYPE__JAVA_JIT,
+       DSO_BINARY_TYPE__DEBUGLINK,
+       DSO_BINARY_TYPE__BUILD_ID_CACHE,
+       DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
+       DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
+       DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
+       DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
+       DSO_BINARY_TYPE__GUEST_KMODULE,
+       DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+       DSO_BINARY_TYPE__NOT_FOUND,
+};
+
 enum dso_kernel_type {
        DSO_TYPE_USER = 0,
        DSO_TYPE_KERNEL,
@@ -167,19 +182,31 @@ enum dso_swap_type {
        DSO_SWAP__YES,
 };
 
+#define DSO__DATA_CACHE_SIZE 4096
+#define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1)
+
+struct dso_cache {
+       struct rb_node  rb_node;
+       u64 offset;
+       u64 size;
+       char data[0];
+};
+
 struct dso {
        struct list_head node;
        struct rb_root   symbols[MAP__NR_TYPES];
        struct rb_root   symbol_names[MAP__NR_TYPES];
+       struct rb_root   cache;
        enum dso_kernel_type    kernel;
        enum dso_swap_type      needs_swap;
+       enum dso_binary_type    symtab_type;
+       enum dso_binary_type    data_type;
        u8               adjust_symbols:1;
        u8               has_build_id:1;
        u8               hit:1;
        u8               annotate_warned:1;
        u8               sname_alloc:1;
        u8               lname_alloc:1;
-       unsigned char    symtab_type;
        u8               sorted_by_name;
        u8               loaded;
        u8               build_id[BUILD_ID_SIZE];
@@ -253,21 +280,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso,
                                    enum map_type type, FILE *fp);
 size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
 
-enum symtab_type {
-       SYMTAB__KALLSYMS = 0,
-       SYMTAB__GUEST_KALLSYMS,
-       SYMTAB__JAVA_JIT,
-       SYMTAB__DEBUGLINK,
-       SYMTAB__BUILD_ID_CACHE,
-       SYMTAB__FEDORA_DEBUGINFO,
-       SYMTAB__UBUNTU_DEBUGINFO,
-       SYMTAB__BUILDID_DEBUGINFO,
-       SYMTAB__SYSTEM_PATH_DSO,
-       SYMTAB__GUEST_KMODULE,
-       SYMTAB__SYSTEM_PATH_KMODULE,
-       SYMTAB__NOT_FOUND,
-};
-
 char dso__symtab_origin(const struct dso *dso);
 void dso__set_long_name(struct dso *dso, char *name);
 void dso__set_build_id(struct dso *dso, void *build_id);
@@ -304,4 +316,14 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type);
 
 size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
 
+int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
+                         char *root_dir, char *file, size_t size);
+
+int dso__data_fd(struct dso *dso, struct machine *machine);
+ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
+                             u64 offset, u8 *data, ssize_t size);
+ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
+                           struct machine *machine, u64 addr,
+                           u8 *data, ssize_t size);
+int dso__test_data(void);
 #endif /* __PERF_SYMBOL */
index 1064d5b148ad9dce074bd828c6267c61de2cf376..3f59c496e64c9035311389fb73e9468fb47e7889 100644 (file)
@@ -110,8 +110,17 @@ int perf_target__strerror(struct perf_target *target, int errnum,
        int idx;
        const char *msg;
 
+       BUG_ON(buflen > 0);
+
        if (errnum >= 0) {
-               strerror_r(errnum, buf, buflen);
+               const char *err = strerror_r(errnum, buf, buflen);
+
+               if (err != buf) {
+                       size_t len = strlen(err);
+                       char *c = mempcpy(buf, err, min(buflen - 1, len));
+                       *c = '\0';
+               }
+
                return 0;
        }
 
diff --git a/tools/testing/fault-injection/failcmd.sh b/tools/testing/fault-injection/failcmd.sh
new file mode 100644 (file)
index 0000000..1776e92
--- /dev/null
@@ -0,0 +1,219 @@
+#!/bin/bash
+#
+# NAME
+#      failcmd.sh - run a command with injecting slab/page allocation failures
+#
+# SYNOPSIS
+#      failcmd.sh --help
+#      failcmd.sh [<options>] command [arguments]
+#
+# DESCRIPTION
+#      Run command with injecting slab/page allocation failures by fault
+#      injection.
+#
+#      NOTE: you need to run this script as root.
+#
+
+usage()
+{
+       cat >&2 <<EOF
+Usage: $0 [options] command [arguments]
+
+OPTIONS
+       -p percent
+       --probability=percent
+               likelihood of failure injection, in percent.
+               Default value is 1
+
+       -t value
+       --times=value
+               specifies how many times failures may happen at most.
+               Default value is 1
+
+       --oom-kill-allocating-task=value
+               set /proc/sys/vm/oom_kill_allocating_task to specified value
+               before running the command.
+               Default value is 1
+
+       -h, --help
+               Display a usage message and exit
+
+       --interval=value, --space=value, --verbose=value, --task-filter=value,
+       --stacktrace-depth=value, --require-start=value, --require-end=value,
+       --reject-start=value, --reject-end=value, --ignore-gfp-wait=value
+               See Documentation/fault-injection/fault-injection.txt for more
+               information
+
+       failslab options:
+       --cache-filter=value
+
+       fail_page_alloc options:
+       --ignore-gfp-highmem=value, --min-order=value
+
+ENVIRONMENT
+       FAILCMD_TYPE
+               The following values for FAILCMD_TYPE are recognized:
+
+               failslab
+                       inject slab allocation failures
+               fail_page_alloc
+                       inject page allocation failures
+
+               If FAILCMD_TYPE is not defined, then failslab is used.
+EOF
+}
+
+if [ $UID != 0 ]; then
+       echo must be run as root >&2
+       exit 1
+fi
+
+DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3}'`
+
+if [ ! -d "$DEBUGFS" ]; then
+       echo debugfs is not mounted >&2
+       exit 1
+fi
+
+FAILCMD_TYPE=${FAILCMD_TYPE:-failslab}
+FAULTATTR=$DEBUGFS/$FAILCMD_TYPE
+
+if [ ! -d $FAULTATTR ]; then
+       echo $FAILCMD_TYPE is not available >&2
+       exit 1
+fi
+
+LONGOPTS=probability:,interval:,times:,space:,verbose:,task-filter:
+LONGOPTS=$LONGOPTS,stacktrace-depth:,require-start:,require-end:
+LONGOPTS=$LONGOPTS,reject-start:,reject-end:,oom-kill-allocating-task:,help
+
+if [ $FAILCMD_TYPE = failslab ]; then
+       LONGOPTS=$LONGOPTS,ignore-gfp-wait:,cache-filter:
+elif [ $FAILCMD_TYPE = fail_page_alloc ]; then
+       LONGOPTS=$LONGOPTS,ignore-gfp-wait:,ignore-gfp-highmem:,min-order:
+fi
+
+TEMP=`getopt -o p:i:t:s:v:h --long $LONGOPTS -n 'failcmd.sh' -- "$@"`
+
+if [ $? != 0 ]; then
+       usage
+       exit 1
+fi
+
+eval set -- "$TEMP"
+
+fault_attr_default()
+{
+       echo N > $FAULTATTR/task-filter
+       echo 0 > $FAULTATTR/probability
+       echo 1 > $FAULTATTR/times
+}
+
+fault_attr_default
+
+oom_kill_allocating_task_saved=`cat /proc/sys/vm/oom_kill_allocating_task`
+
+restore_values()
+{
+       fault_attr_default
+       echo $oom_kill_allocating_task_saved \
+               > /proc/sys/vm/oom_kill_allocating_task
+}
+
+#
+# Default options
+#
+declare -i oom_kill_allocating_task=1
+declare task_filter=Y
+declare -i probability=1
+declare -i times=1
+
+while true; do
+       case "$1" in
+       -p|--probability)
+               probability=$2
+               shift 2
+               ;;
+       -i|--interval)
+               echo $2 > $FAULTATTR/interval
+               shift 2
+               ;;
+       -t|--times)
+               times=$2
+               shift 2
+               ;;
+       -s|--space)
+               echo $2 > $FAULTATTR/space
+               shift 2
+               ;;
+       -v|--verbose)
+               echo $2 > $FAULTATTR/verbose
+               shift 2
+               ;;
+       --task-filter)
+               task_filter=$2
+               shift 2
+               ;;
+       --stacktrace-depth)
+               echo $2 > $FAULTATTR/stacktrace-depth
+               shift 2
+               ;;
+       --require-start)
+               echo $2 > $FAULTATTR/require-start
+               shift 2
+               ;;
+       --require-end)
+               echo $2 > $FAULTATTR/require-end
+               shift 2
+               ;;
+       --reject-start)
+               echo $2 > $FAULTATTR/reject-start
+               shift 2
+               ;;
+       --reject-end)
+               echo $2 > $FAULTATTR/reject-end
+               shift 2
+               ;;
+       --oom-kill-allocating-task)
+               oom_kill_allocating_task=$2
+               shift 2
+               ;;
+       --ignore-gfp-wait)
+               echo $2 > $FAULTATTR/ignore-gfp-wait
+               shift 2
+               ;;
+       --cache-filter)
+               echo $2 > $FAULTATTR/cache_filter
+               shift 2
+               ;;
+       --ignore-gfp-highmem)
+               echo $2 > $FAULTATTR/ignore-gfp-highmem
+               shift 2
+               ;;
+       --min-order)
+               echo $2 > $FAULTATTR/min-order
+               shift 2
+               ;;
+       -h|--help)
+               usage
+               exit 0
+               shift
+               ;;
+       --)
+               shift
+               break
+               ;;
+       esac
+done
+
+[ -z "$@" ] && exit 0
+
+echo $oom_kill_allocating_task > /proc/sys/vm/oom_kill_allocating_task
+echo $task_filter > $FAULTATTR/task-filter
+echo $probability > $FAULTATTR/probability
+echo $times > $FAULTATTR/times
+
+trap "restore_values" SIGINT SIGTERM EXIT
+
+cmd="echo 1 > /proc/self/make-it-fail && exec $@"
+bash -c "$cmd"
index 292b13ad03f505f25790f6fb43a8b9c8b822c3c6..52b7959cd513dc358e57376528abcf41b36f4f6d 100755 (executable)
@@ -52,6 +52,7 @@ my %default = (
     "STOP_AFTER_SUCCESS"       => 10,
     "STOP_AFTER_FAILURE"       => 60,
     "STOP_TEST_AFTER"          => 600,
+    "MAX_MONITOR_WAIT"         => 1800,
 
 # required, and we will ask users if they don't have them but we keep the default
 # value something that is common.
@@ -77,6 +78,11 @@ my $output_config;
 my $test_type;
 my $build_type;
 my $build_options;
+my $final_post_ktest;
+my $pre_ktest;
+my $post_ktest;
+my $pre_test;
+my $post_test;
 my $pre_build;
 my $post_build;
 my $pre_build_die;
@@ -93,6 +99,7 @@ my $reboot_on_success;
 my $die_on_failure;
 my $powercycle_after_reboot;
 my $poweroff_after_halt;
+my $max_monitor_wait;
 my $ssh_exec;
 my $scp_to_target;
 my $scp_to_target_install;
@@ -101,6 +108,7 @@ my $grub_menu;
 my $grub_number;
 my $target;
 my $make;
+my $pre_install;
 my $post_install;
 my $no_install;
 my $noclean;
@@ -167,6 +175,7 @@ my $bisect_check;
 
 my $config_bisect;
 my $config_bisect_type;
+my $config_bisect_check;
 
 my $patchcheck_type;
 my $patchcheck_start;
@@ -182,6 +191,9 @@ my $newconfig = 0;
 my %entered_configs;
 my %config_help;
 my %variable;
+
+# force_config is the list of configs that we force enabled (or disabled)
+# in a .config file. The MIN_CONFIG and ADD_CONFIG configs.
 my %force_config;
 
 # do not force reboots on config problems
@@ -197,6 +209,10 @@ my %option_map = (
     "OUTPUT_DIR"               => \$outputdir,
     "BUILD_DIR"                        => \$builddir,
     "TEST_TYPE"                        => \$test_type,
+    "PRE_KTEST"                        => \$pre_ktest,
+    "POST_KTEST"               => \$post_ktest,
+    "PRE_TEST"                 => \$pre_test,
+    "POST_TEST"                        => \$post_test,
     "BUILD_TYPE"               => \$build_type,
     "BUILD_OPTIONS"            => \$build_options,
     "PRE_BUILD"                        => \$pre_build,
@@ -216,6 +232,7 @@ my %option_map = (
     "ADD_CONFIG"               => \$addconfig,
     "REBOOT_TYPE"              => \$reboot_type,
     "GRUB_MENU"                        => \$grub_menu,
+    "PRE_INSTALL"              => \$pre_install,
     "POST_INSTALL"             => \$post_install,
     "NO_INSTALL"               => \$no_install,
     "REBOOT_SCRIPT"            => \$reboot_script,
@@ -228,6 +245,7 @@ my %option_map = (
     "POWER_OFF"                        => \$power_off,
     "POWERCYCLE_AFTER_REBOOT"  => \$powercycle_after_reboot,
     "POWEROFF_AFTER_HALT"      => \$poweroff_after_halt,
+    "MAX_MONITOR_WAIT"         => \$max_monitor_wait,
     "SLEEP_TIME"               => \$sleep_time,
     "BISECT_SLEEP_TIME"                => \$bisect_sleep_time,
     "PATCHCHECK_SLEEP_TIME"    => \$patchcheck_sleep_time,
@@ -272,6 +290,7 @@ my %option_map = (
 
     "CONFIG_BISECT"            => \$config_bisect,
     "CONFIG_BISECT_TYPE"       => \$config_bisect_type,
+    "CONFIG_BISECT_CHECK"      => \$config_bisect_check,
 
     "PATCHCHECK_TYPE"          => \$patchcheck_type,
     "PATCHCHECK_START"         => \$patchcheck_start,
@@ -604,6 +623,10 @@ sub process_compare {
        return $lval eq $rval;
     } elsif ($cmp eq "!=") {
        return $lval ne $rval;
+    } elsif ($cmp eq "=~") {
+       return $lval =~ m/$rval/;
+    } elsif ($cmp eq "!~") {
+       return $lval !~ m/$rval/;
     }
 
     my $statement = "$lval $cmp $rval";
@@ -659,7 +682,7 @@ sub process_expression {
        }
     }
 
-    if ($val =~ /(.*)(==|\!=|>=|<=|>|<)(.*)/) {
+    if ($val =~ /(.*)(==|\!=|>=|<=|>|<|=~|\!~)(.*)/) {
        my $ret = process_compare($1, $2, $3);
        if ($ret < 0) {
            die "$name: $.: Unable to process comparison\n";
@@ -1117,7 +1140,11 @@ sub reboot {
     }
 
     if (defined($time)) {
-       wait_for_monitor($time, $reboot_success_line);
+       if (wait_for_monitor($time, $reboot_success_line)) {
+           # reboot got stuck?
+           doprint "Reboot did not finish. Forcing power cycle\n";
+           run_command "$power_cycle";
+       }
        end_monitor;
     }
 }
@@ -1212,6 +1239,11 @@ sub wait_for_monitor {
     my $full_line = "";
     my $line;
     my $booted = 0;
+    my $start_time = time;
+    my $skip_call_trace = 0;
+    my $bug = 0;
+    my $bug_ignored = 0;
+    my $now;
 
     doprint "** Wait for monitor to settle down **\n";
 
@@ -1227,11 +1259,39 @@ sub wait_for_monitor {
            $booted = 1;
        }
 
+       if ($full_line =~ /\[ backtrace testing \]/) {
+           $skip_call_trace = 1;
+       }
+
+       if ($full_line =~ /call trace:/i) {
+           if (!$bug && !$skip_call_trace) {
+               if ($ignore_errors) {
+                   $bug_ignored = 1;
+               } else {
+                   $bug = 1;
+               }
+           }
+       }
+
+       if ($full_line =~ /\[ end of backtrace testing \]/) {
+           $skip_call_trace = 0;
+       }
+
+       if ($full_line =~ /Kernel panic -/) {
+           $bug = 1;
+       }
+
        if ($line =~ /\n/) {
            $full_line = "";
        }
+       $now = time;
+       if ($now - $start_time >= $max_monitor_wait) {
+           doprint "Exiting monitor flush due to hitting MAX_MONITOR_WAIT\n";
+           return 1;
+       }
     }
     print "** Monitor flushed **\n";
+    return $bug;
 }
 
 sub save_logs {
@@ -1273,6 +1333,10 @@ sub save_logs {
 
 sub fail {
 
+       if (defined($post_test)) {
+               run_command $post_test;
+       }
+
        if ($die_on_failure) {
                dodie @_;
        }
@@ -1656,6 +1720,12 @@ sub install {
 
     return if ($no_install);
 
+    if (defined($pre_install)) {
+       my $cp_pre_install = eval_kernel_version $pre_install;
+       run_command "$cp_pre_install" or
+           dodie "Failed to run pre install";
+    }
+
     my $cp_target = eval_kernel_version $target_image;
 
     run_scp_install "$outputdir/$build_target", "$cp_target" or
@@ -1814,6 +1884,7 @@ sub make_oldconfig {
 sub load_force_config {
     my ($config) = @_;
 
+    doprint "Loading force configs from $config\n";
     open(IN, $config) or
        dodie "failed to read $config";
     while (<IN>) {
@@ -1937,6 +2008,10 @@ sub halt {
 sub success {
     my ($i) = @_;
 
+    if (defined($post_test)) {
+       run_command $post_test;
+    }
+
     $successes++;
 
     my $name = "";
@@ -2003,6 +2078,7 @@ sub do_run_test {
     my $line;
     my $full_line;
     my $bug = 0;
+    my $bug_ignored = 0;
 
     wait_for_monitor 1;
 
@@ -2027,7 +2103,11 @@ sub do_run_test {
            doprint $line;
 
            if ($full_line =~ /call trace:/i) {
-               $bug = 1;
+               if ($ignore_errors) {
+                   $bug_ignored = 1;
+               } else {
+                   $bug = 1;
+               }
            }
 
            if ($full_line =~ /Kernel panic -/) {
@@ -2040,6 +2120,10 @@ sub do_run_test {
        }
     } while (!$child_done && !$bug);
 
+    if (!$bug && $bug_ignored) {
+       doprint "WARNING: Call Trace detected but ignored due to IGNORE_ERRORS=1\n";
+    }
+
     if ($bug) {
        my $failure_start = time;
        my $now;
@@ -2362,9 +2446,24 @@ sub bisect {
     success $i;
 }
 
+# config_ignore holds the configs that were set (or unset) for
+# a good config and we will ignore these configs for the rest
+# of a config bisect. These configs stay as they were.
 my %config_ignore;
+
+# config_set holds what all configs were set as.
 my %config_set;
 
+# config_off holds the set of configs that the bad config had disabled.
+# We need to record them and set them in the .config when running
+# oldnoconfig, because oldnoconfig does not turn off new symbols, but
+# instead just keeps the defaults.
+my %config_off;
+
+# config_off_tmp holds a set of configs to turn off for now
+my @config_off_tmp;
+
+# config_list is the set of configs that are being tested
 my %config_list;
 my %null_config;
 
@@ -2443,12 +2542,21 @@ sub create_config {
        }
     }
 
+    # turn off configs to keep off
+    foreach my $config (keys %config_off) {
+       print OUT "# $config is not set\n";
+    }
+
+    # turn off configs that should be off for now
+    foreach my $config (@config_off_tmp) {
+       print OUT "# $config is not set\n";
+    }
+
     foreach my $config (keys %config_ignore) {
        print OUT "$config_ignore{$config}\n";
     }
     close(OUT);
 
-#    exit;
     make_oldconfig;
 }
 
@@ -2525,6 +2633,13 @@ sub run_config_bisect {
     do {
        my @tophalf = @start_list[0 .. $half];
 
+       # keep the bottom half off
+       if ($half < $#start_list) {
+           @config_off_tmp = @start_list[$half + 1 .. $#start_list];
+       } else {
+           @config_off_tmp = ();
+       }
+
        create_config @tophalf;
        read_current_config \%current_config;
 
@@ -2541,7 +2656,11 @@ sub run_config_bisect {
        if (!$found) {
            # try the other half
            doprint "Top half produced no set configs, trying bottom half\n";
+
+           # keep the top half off
+           @config_off_tmp = @tophalf;
            @tophalf = @start_list[$half + 1 .. $#start_list];
+
            create_config @tophalf;
            read_current_config \%current_config;
            foreach my $config (@tophalf) {
@@ -2679,6 +2798,10 @@ sub config_bisect {
                $added_configs{$2} = $1;
                $config_list{$2} = $1;
            }
+       } elsif (/^# ((CONFIG\S*).*)/) {
+           # Keep these configs disabled
+           $config_set{$2} = $1;
+           $config_off{$2} = $1;
        }
     }
     close(IN);
@@ -2701,6 +2824,8 @@ sub config_bisect {
     my %config_test;
     my $once = 0;
 
+    @config_off_tmp = ();
+
     # Sometimes kconfig does weird things. We must make sure
     # that the config we autocreate has everything we need
     # to test, otherwise we may miss testing configs, or
@@ -2719,6 +2844,18 @@ sub config_bisect {
        }
     }
     my $ret;
+
+    if (defined($config_bisect_check) && $config_bisect_check) {
+       doprint " Checking to make sure bad config with min config fails\n";
+       create_config keys %config_list;
+       $ret = run_config_bisect_test $config_bisect_type;
+       if ($ret) {
+           doprint " FAILED! Bad config with min config boots fine\n";
+           return -1;
+       }
+       doprint " Bad config with min config fails as expected\n";
+    }
+
     do {
        $ret = run_config_bisect;
     } while (!$ret);
@@ -3510,6 +3647,8 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
 
     $iteration = $i;
 
+    undef %force_config;
+
     my $makecmd = set_test_option("MAKE_CMD", $i);
 
     # Load all the options into their mapped variable names
@@ -3519,6 +3658,18 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
 
     $start_minconfig_defined = 1;
 
+    # The first test may override the PRE_KTEST option
+    if (defined($pre_ktest) && $i == 1) {
+       doprint "\n";
+       run_command $pre_ktest;
+    }
+
+    # Any test can override the POST_KTEST option
+    # The last test takes precedence.
+    if (defined($post_ktest)) {
+       $final_post_ktest = $post_ktest;
+    }
+
     if (!defined($start_minconfig)) {
        $start_minconfig_defined = 0;
        $start_minconfig = $minconfig;
@@ -3573,6 +3724,10 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
     doprint "\n\n";
     doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type$installme\n\n";
 
+    if (defined($pre_test)) {
+       run_command $pre_test;
+    }
+
     unlink $dmesg;
     unlink $buildlog;
     unlink $testlog;
@@ -3638,6 +3793,10 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
     success $i;
 }
 
+if (defined($final_post_ktest)) {
+    run_command $final_post_ktest;
+}
+
 if ($opt{"POWEROFF_ON_SUCCESS"}) {
     halt;
 } elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot && $reboot_success) {
index cf362b3d1ec959322af01e650b4eb0912084e5e9..de28a0a3b8fc90b6070ac557cf755fbaa366e32a 100644 (file)
 # DEFAULTS
 # DEFAULTS SKIP
 
+# If you want to execute some command before the first test runs
+# you can set this option. Note, it can be set as a default option
+# or an option in the first test case. All other test cases will
+# ignore it. If both the default and first test have this option
+# set, then the first test will take precedence.
+#
+# default (undefined)
+#PRE_KTEST = ${SSH} ~/set_up_test
+
+# If you want to execute some command after all the tests have
+# completed, you can set this option. Note, it can be set as a
+# default or any test case can override it. If multiple test cases
+# set this option, then the last test case that set it will take
+# precedence
+#
+# default (undefined)
+#POST_KTEST = ${SSH} ~/dismantle_test
+
 # The default test type (default test)
 # The test types may be:
 #   build   - only build the kernel, do nothing else
 # (default "")
 #BUILD_OPTIONS = -j20
 
+# If you need to do some special handling before installing
+# you can add a script with this option.
+# The environment variable KERNEL_VERSION will be set to the
+# kernel version that is used.
+#
+# default (undefined)
+#PRE_INSTALL = ssh user@target rm -rf '/lib/modules/*-test*'
+
 # If you need an initrd, you can add a script or code here to install
 # it. The environment variable KERNEL_VERSION will be set to the
 # kernel version that is used. Remember to add the initrd line
 # (default 0)
 #NO_INSTALL = 1
 
+# If there is a command that you want to run before the individual test
+# case executes, then you can set this option
+#
+# default (undefined)
+#PRE_TEST = ${SSH} reboot_to_special_kernel
+
+# If there is a command you want to run after the individual test case
+# completes, then you can set this option.
+#
+# default (undefined)
+#POST_TEST = cd ${BUILD_DIR}; git reset --hard
+
 # If there is a script that you require to run before the build is done
 # you can specify it with PRE_BUILD.
 #
 # (default 60)
 #BISECT_SLEEP_TIME = 60
 
+# The max wait time (in seconds) for waiting for the console to finish.
+# If for some reason, the console is outputting content without
+# ever finishing, this will cause ktest to get stuck. This
+# option is the max time ktest will wait for the monitor (console)
+# to settle down before continuing.
+# (default 1800)
+#MAX_MONITOR_WAIT
+
 # The time in between patch checks to sleep (in seconds)
 # (default 60)
 #PATCHCHECK_SLEEP_TIME = 60
 #  can specify it with CONFIG_BISECT_GOOD. Otherwise
 #  the MIN_CONFIG is the base.
 #
+# CONFIG_BISECT_CHECK (optional)
+#  Set this to 1 if you want to confirm that the config ktest
+#  generates (the bad config with the min config) is still bad.
+#  It may be that the min config fixes what broke the bad config
+#  and the test will not return a result.
+#
 # Example:
 #   TEST_START
 #   TEST_TYPE = config_bisect
index a4162e15c25f89f32862a1f4fb2630c32f8c1c60..85baf11e2acd7d11aa4990a0f7f53f8d28689a20 100644 (file)
@@ -1,4 +1,4 @@
-TARGETS = breakpoints kcmp mqueue vm
+TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug
 
 all:
        for TARGET in $(TARGETS); do \
diff --git a/tools/testing/selftests/cpu-hotplug/Makefile b/tools/testing/selftests/cpu-hotplug/Makefile
new file mode 100644 (file)
index 0000000..7c9c20f
--- /dev/null
@@ -0,0 +1,6 @@
+all:
+
+run_tests:
+       ./on-off-test.sh
+
+clean:
diff --git a/tools/testing/selftests/cpu-hotplug/on-off-test.sh b/tools/testing/selftests/cpu-hotplug/on-off-test.sh
new file mode 100644 (file)
index 0000000..bdde7cf
--- /dev/null
@@ -0,0 +1,221 @@
+#!/bin/bash
+
+SYSFS=
+
+prerequisite()
+{
+       msg="skip all tests:"
+
+       if [ $UID != 0 ]; then
+               echo $msg must be run as root >&2
+               exit 0
+       fi
+
+       SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
+
+       if [ ! -d "$SYSFS" ]; then
+               echo $msg sysfs is not mounted >&2
+               exit 0
+       fi
+
+       if ! ls $SYSFS/devices/system/cpu/cpu* > /dev/null 2>&1; then
+               echo $msg cpu hotplug is not supported >&2
+               exit 0
+       fi
+}
+
+#
+# list all hot-pluggable CPUs
+#
+hotpluggable_cpus()
+{
+       local state=${1:-.\*}
+
+       for cpu in $SYSFS/devices/system/cpu/cpu*; do
+               if [ -f $cpu/online ] && grep -q $state $cpu/online; then
+                       echo ${cpu##/*/cpu}
+               fi
+       done
+}
+
+hotplaggable_offline_cpus()
+{
+       hotpluggable_cpus 0
+}
+
+hotpluggable_online_cpus()
+{
+       hotpluggable_cpus 1
+}
+
+cpu_is_online()
+{
+       grep -q 1 $SYSFS/devices/system/cpu/cpu$1/online
+}
+
+cpu_is_offline()
+{
+       grep -q 0 $SYSFS/devices/system/cpu/cpu$1/online
+}
+
+online_cpu()
+{
+       echo 1 > $SYSFS/devices/system/cpu/cpu$1/online
+}
+
+offline_cpu()
+{
+       echo 0 > $SYSFS/devices/system/cpu/cpu$1/online
+}
+
+online_cpu_expect_success()
+{
+       local cpu=$1
+
+       if ! online_cpu $cpu; then
+               echo $FUNCNAME $cpu: unexpected fail >&2
+       elif ! cpu_is_online $cpu; then
+               echo $FUNCNAME $cpu: unexpected offline >&2
+       fi
+}
+
+online_cpu_expect_fail()
+{
+       local cpu=$1
+
+       if online_cpu $cpu 2> /dev/null; then
+               echo $FUNCNAME $cpu: unexpected success >&2
+       elif ! cpu_is_offline $cpu; then
+               echo $FUNCNAME $cpu: unexpected online >&2
+       fi
+}
+
+offline_cpu_expect_success()
+{
+       local cpu=$1
+
+       if ! offline_cpu $cpu; then
+               echo $FUNCNAME $cpu: unexpected fail >&2
+       elif ! cpu_is_offline $cpu; then
+               echo $FUNCNAME $cpu: unexpected offline >&2
+       fi
+}
+
+offline_cpu_expect_fail()
+{
+       local cpu=$1
+
+       if offline_cpu $cpu 2> /dev/null; then
+               echo $FUNCNAME $cpu: unexpected success >&2
+       elif ! cpu_is_online $cpu; then
+               echo $FUNCNAME $cpu: unexpected offline >&2
+       fi
+}
+
+error=-12
+priority=0
+
+while getopts e:hp: opt; do
+       case $opt in
+       e)
+               error=$OPTARG
+               ;;
+       h)
+               echo "Usage $0 [ -e errno ] [ -p notifier-priority ]"
+               exit
+               ;;
+       p)
+               priority=$OPTARG
+               ;;
+       esac
+done
+
+if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
+       echo "error code must be -4095 <= errno < 0" >&2
+       exit 1
+fi
+
+prerequisite
+
+#
+# Online all hot-pluggable CPUs
+#
+for cpu in `hotplaggable_offline_cpus`; do
+       online_cpu_expect_success $cpu
+done
+
+#
+# Offline all hot-pluggable CPUs
+#
+for cpu in `hotpluggable_online_cpus`; do
+       offline_cpu_expect_success $cpu
+done
+
+#
+# Online all hot-pluggable CPUs again
+#
+for cpu in `hotplaggable_offline_cpus`; do
+       online_cpu_expect_success $cpu
+done
+
+#
+# Test with cpu notifier error injection
+#
+
+DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
+NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/cpu
+
+prerequisite_extra()
+{
+       msg="skip extra tests:"
+
+       /sbin/modprobe -q -r cpu-notifier-error-inject
+       /sbin/modprobe -q cpu-notifier-error-inject priority=$priority
+
+       if [ ! -d "$DEBUGFS" ]; then
+               echo $msg debugfs is not mounted >&2
+               exit 0
+       fi
+
+       if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
+               echo $msg cpu-notifier-error-inject module is not available >&2
+               exit 0
+       fi
+}
+
+prerequisite_extra
+
+#
+# Offline all hot-pluggable CPUs
+#
+echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
+for cpu in `hotpluggable_online_cpus`; do
+       offline_cpu_expect_success $cpu
+done
+
+#
+# Test CPU hot-add error handling (offline => online)
+#
+echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_UP_PREPARE/error
+for cpu in `hotplaggable_offline_cpus`; do
+       online_cpu_expect_fail $cpu
+done
+
+#
+# Online all hot-pluggable CPUs
+#
+echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_UP_PREPARE/error
+for cpu in `hotplaggable_offline_cpus`; do
+       online_cpu_expect_success $cpu
+done
+
+#
+# Test CPU hot-remove error handling (online => offline)
+#
+echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
+for cpu in `hotpluggable_online_cpus`; do
+       offline_cpu_expect_fail $cpu
+done
+
+echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
+/sbin/modprobe -q -r cpu-notifier-error-inject
diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile
new file mode 100644 (file)
index 0000000..7c9c20f
--- /dev/null
@@ -0,0 +1,6 @@
+all:
+
+run_tests:
+       ./on-off-test.sh
+
+clean:
diff --git a/tools/testing/selftests/memory-hotplug/on-off-test.sh b/tools/testing/selftests/memory-hotplug/on-off-test.sh
new file mode 100644 (file)
index 0000000..a2816f6
--- /dev/null
@@ -0,0 +1,230 @@
+#!/bin/bash
+
+SYSFS=
+
+prerequisite()
+{
+       msg="skip all tests:"
+
+       if [ $UID != 0 ]; then
+               echo $msg must be run as root >&2
+               exit 0
+       fi
+
+       SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
+
+       if [ ! -d "$SYSFS" ]; then
+               echo $msg sysfs is not mounted >&2
+               exit 0
+       fi
+
+       if ! ls $SYSFS/devices/system/memory/memory* > /dev/null 2>&1; then
+               echo $msg memory hotplug is not supported >&2
+               exit 0
+       fi
+}
+
+#
+# list all hot-pluggable memory
+#
+hotpluggable_memory()
+{
+       local state=${1:-.\*}
+
+       for memory in $SYSFS/devices/system/memory/memory*; do
+               if grep -q 1 $memory/removable &&
+                  grep -q $state $memory/state; then
+                       echo ${memory##/*/memory}
+               fi
+       done
+}
+
+hotplaggable_offline_memory()
+{
+       hotpluggable_memory offline
+}
+
+hotpluggable_online_memory()
+{
+       hotpluggable_memory online
+}
+
+memory_is_online()
+{
+       grep -q online $SYSFS/devices/system/memory/memory$1/state
+}
+
+memory_is_offline()
+{
+       grep -q offline $SYSFS/devices/system/memory/memory$1/state
+}
+
+online_memory()
+{
+       echo online > $SYSFS/devices/system/memory/memory$1/state
+}
+
+offline_memory()
+{
+       echo offline > $SYSFS/devices/system/memory/memory$1/state
+}
+
+online_memory_expect_success()
+{
+       local memory=$1
+
+       if ! online_memory $memory; then
+               echo $FUNCNAME $memory: unexpected fail >&2
+       elif ! memory_is_online $memory; then
+               echo $FUNCNAME $memory: unexpected offline >&2
+       fi
+}
+
+online_memory_expect_fail()
+{
+       local memory=$1
+
+       if online_memory $memory 2> /dev/null; then
+               echo $FUNCNAME $memory: unexpected success >&2
+       elif ! memory_is_offline $memory; then
+               echo $FUNCNAME $memory: unexpected online >&2
+       fi
+}
+
+offline_memory_expect_success()
+{
+       local memory=$1
+
+       if ! offline_memory $memory; then
+               echo $FUNCNAME $memory: unexpected fail >&2
+       elif ! memory_is_offline $memory; then
+               echo $FUNCNAME $memory: unexpected offline >&2
+       fi
+}
+
+offline_memory_expect_fail()
+{
+       local memory=$1
+
+       if offline_memory $memory 2> /dev/null; then
+               echo $FUNCNAME $memory: unexpected success >&2
+       elif ! memory_is_online $memory; then
+               echo $FUNCNAME $memory: unexpected offline >&2
+       fi
+}
+
+error=-12
+priority=0
+ratio=10
+
+while getopts e:hp:r: opt; do
+       case $opt in
+       e)
+               error=$OPTARG
+               ;;
+       h)
+               echo "Usage $0 [ -e errno ] [ -p notifier-priority ] [ -r percent-of-memory-to-offline ]"
+               exit
+               ;;
+       p)
+               priority=$OPTARG
+               ;;
+       r)
+               ratio=$OPTARG
+               ;;
+       esac
+done
+
+if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
+       echo "error code must be -4095 <= errno < 0" >&2
+       exit 1
+fi
+
+prerequisite
+
+#
+# Online all hot-pluggable memory
+#
+for memory in `hotplaggable_offline_memory`; do
+       online_memory_expect_success $memory
+done
+
+#
+# Offline $ratio percent of hot-pluggable memory
+#
+for memory in `hotpluggable_online_memory`; do
+       if [ $((RANDOM % 100)) -lt $ratio ]; then
+               offline_memory_expect_success $memory
+       fi
+done
+
+#
+# Online all hot-pluggable memory again
+#
+for memory in `hotplaggable_offline_memory`; do
+       online_memory_expect_success $memory
+done
+
+#
+# Test with memory notifier error injection
+#
+
+DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
+NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/memory
+
+prerequisite_extra()
+{
+       msg="skip extra tests:"
+
+       /sbin/modprobe -q -r memory-notifier-error-inject
+       /sbin/modprobe -q memory-notifier-error-inject priority=$priority
+
+       if [ ! -d "$DEBUGFS" ]; then
+               echo $msg debugfs is not mounted >&2
+               exit 0
+       fi
+
+       if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
+               echo $msg memory-notifier-error-inject module is not available >&2
+               exit 0
+       fi
+}
+
+prerequisite_extra
+
+#
+# Offline $ratio percent of hot-pluggable memory
+#
+echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
+for memory in `hotpluggable_online_memory`; do
+       if [ $((RANDOM % 100)) -lt $ratio ]; then
+               offline_memory_expect_success $memory
+       fi
+done
+
+#
+# Test memory hot-add error handling (offline => online)
+#
+echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
+for memory in `hotplaggable_offline_memory`; do
+       online_memory_expect_fail $memory
+done
+
+#
+# Online all hot-pluggable memory
+#
+echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
+for memory in `hotplaggable_offline_memory`; do
+       online_memory_expect_success $memory
+done
+
+#
+# Test memory hot-remove error handling (online => offline)
+#
+echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
+for memory in `hotpluggable_online_memory`; do
+       offline_memory_expect_fail $memory
+done
+
+echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
+/sbin/modprobe -q -r memory-notifier-error-inject
index 164cbcf61106f5d65412961c46f548383e8263ab..808d5a9d5dcfb062a5dc9d9fc10246cb6e7e00d2 100644 (file)
@@ -437,34 +437,34 @@ static void slab_stats(struct slabinfo *s)
        printf("Fastpath             %8lu %8lu %3lu %3lu\n",
                s->alloc_fastpath, s->free_fastpath,
                s->alloc_fastpath * 100 / total_alloc,
-               s->free_fastpath * 100 / total_free);
+               total_free ? s->free_fastpath * 100 / total_free : 0);
        printf("Slowpath             %8lu %8lu %3lu %3lu\n",
                total_alloc - s->alloc_fastpath, s->free_slowpath,
                (total_alloc - s->alloc_fastpath) * 100 / total_alloc,
-               s->free_slowpath * 100 / total_free);
+               total_free ? s->free_slowpath * 100 / total_free : 0);
        printf("Page Alloc           %8lu %8lu %3lu %3lu\n",
                s->alloc_slab, s->free_slab,
                s->alloc_slab * 100 / total_alloc,
-               s->free_slab * 100 / total_free);
+               total_free ? s->free_slab * 100 / total_free : 0);
        printf("Add partial          %8lu %8lu %3lu %3lu\n",
                s->deactivate_to_head + s->deactivate_to_tail,
                s->free_add_partial,
                (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
-               s->free_add_partial * 100 / total_free);
+               total_free ? s->free_add_partial * 100 / total_free : 0);
        printf("Remove partial       %8lu %8lu %3lu %3lu\n",
                s->alloc_from_partial, s->free_remove_partial,
                s->alloc_from_partial * 100 / total_alloc,
-               s->free_remove_partial * 100 / total_free);
+               total_free ? s->free_remove_partial * 100 / total_free : 0);
 
        printf("Cpu partial list     %8lu %8lu %3lu %3lu\n",
                s->cpu_partial_alloc, s->cpu_partial_free,
                s->cpu_partial_alloc * 100 / total_alloc,
-               s->cpu_partial_free * 100 / total_free);
+               total_free ? s->cpu_partial_free * 100 / total_free : 0);
 
        printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
                s->deactivate_remote_frees, s->free_frozen,
                s->deactivate_remote_frees * 100 / total_alloc,
-               s->free_frozen * 100 / total_free);
+               total_free ? s->free_frozen * 100 / total_free : 0);
 
        printf("Total                %8lu %8lu\n\n", total_alloc, total_free);